diff --git a/connect_ext_ppr/db.py b/connect_ext_ppr/db.py index 292a5bd..47ffab9 100644 --- a/connect_ext_ppr/db.py +++ b/connect_ext_ppr/db.py @@ -114,6 +114,33 @@ def set_next_verbose(self, instance, related_id_field): instance.id = '{0}-{1}'.format(_instance_id, '{0:03d}'.format(new_suffix)) return self.add(instance) + def set_all_next_verbose(self, instances, related_id_field): + first_item = instances[0] + instance_class = first_item.__class__ + new_suffix = 0 + related_id_value = getattr(first_item, related_id_field) + + if ( + self.query(self.query(instance_class).filter( + instance_class.__dict__[related_id_field] == related_id_value).exists(), + ).scalar() + ): + + last_obj = self.query(instance_class).order_by( + instance_class.id.desc(), + ).first() + _instance_id, suffix = last_obj.id.rsplit('-', 1) + new_suffix = int(suffix) + 1 + else: + id_body = related_id_value.split('-', 1)[-1] + _instance_id = f"{instance_class.PREFIX}-{id_body}" + + for instance in instances: + instance.id = '{0}-{1}'.format(_instance_id, '{0:03d}'.format(new_suffix)) + new_suffix += 1 + + return self.add_all(instances) + SessionLocal = sessionmaker(autocommit=False, autoflush=False, class_=VerboseBaseSession) Model = declarative_base() diff --git a/connect_ext_ppr/errors.py b/connect_ext_ppr/errors.py index 38b3e2b..31f1a3c 100644 --- a/connect_ext_ppr/errors.py +++ b/connect_ext_ppr/errors.py @@ -91,6 +91,7 @@ class ExtensionHttpError(ExtensionErrorBase): " for first row in Batch {batch_id}.", 15: 'No Marketplace is linked with Deployment Hub {hub_id}', 16: "Pricing Batch '{batch_id}' does not have any file.", + 17: "Cannot create a new request, an open one already exists.", } @@ -98,4 +99,8 @@ class ExtensionValidationError(ExtensionErrorBase): PREFIX = 'VAL' ERRORS = { 0: "{validation_error}", # PPR Schema validation + 1: "{field}: {id} not found.", + 2: "{field}: This values {values} are invalid.", + 3: "At least one choice needs to be specified.", + 4: "Cannot applied PPR to {entity} {values}.", } diff --git a/connect_ext_ppr/models/deployment.py b/connect_ext_ppr/models/deployment.py index 5991ffc..f494e59 100644 --- a/connect_ext_ppr/models/deployment.py +++ b/connect_ext_ppr/models/deployment.py @@ -36,6 +36,7 @@ class Deployment(Model): updated_at = db.Column(db.DateTime(), onupdate=datetime.utcnow, default=datetime.utcnow) product = relationship("Product", back_populates="deployment") + marketplaces = relationship('MarketplaceConfiguration', backref='deployment', lazy=True) class DeploymentRequest(Model): @@ -63,7 +64,11 @@ class DeploymentRequest(Model): aborted_by = db.Column(db.String(20), nullable=True) ppr = relationship('PPRVersion', foreign_keys="DeploymentRequest.ppr_id") - deployment = relationship('Deployment', foreign_keys="DeploymentRequest.deployment_id") + deployment = relationship( + 'Deployment', + foreign_keys="DeploymentRequest.deployment_id", + innerjoin=True, + ) class MarketplaceConfiguration(Model): @@ -71,7 +76,7 @@ class MarketplaceConfiguration(Model): id = db.Column(db.Integer(), primary_key=True, autoincrement=True) marketplace = db.Column(db.String(16)) - deployment = db.Column(db.ForeignKey(Deployment.id), nullable=True) + deployment_id = db.Column(db.ForeignKey(Deployment.id), nullable=True) deployment_request = db.Column(db.ForeignKey(DeploymentRequest.id), nullable=True) ppr_id = db.Column(db.String, db.ForeignKey(PPRVersion.id)) diff --git a/connect_ext_ppr/models/task.py b/connect_ext_ppr/models/task.py index 9b6454c..a6d473d 100644 --- a/connect_ext_ppr/models/task.py +++ b/connect_ext_ppr/models/task.py @@ -13,6 +13,7 @@ class Task(Model): PREFIX = 'TSK' STATUSES = TasksStatusChoices + TYPES = TaskTypesChoices id = db.Column(db.String(30), primary_key=True) status = db.Column( diff --git a/connect_ext_ppr/schemas.py b/connect_ext_ppr/schemas.py index f8045b4..43aeaa1 100644 --- a/connect_ext_ppr/schemas.py +++ b/connect_ext_ppr/schemas.py @@ -4,10 +4,13 @@ # All rights reserved. # from datetime import datetime -from typing import Dict, Optional, Union from pydantic import BaseModel, Field, root_validator +from fastapi import status +from typing import Dict, List, Optional, Union + +from connect_ext_ppr.errors import ExtensionValidationError from connect_ext_ppr.models.enums import ( ConfigurationStateChoices, DeploymentRequestStatusChoices, @@ -56,6 +59,21 @@ def validate_events(cls, values): return values +class PrimaryKeyReference(BaseModel): + id: str + + +class ChoicesSchema(BaseModel): + choices: Optional[List[PrimaryKeyReference]] + all: bool + + @root_validator + def check_choices_exists_if_all_is_false(cls, values): + if not values.get('all') and not values.get('choices'): + raise ExtensionValidationError.VAL_003(status_code=status.HTTP_400_BAD_REQUEST) + return values + + class VendorSchema(NonNullSchema): id: str name: str @@ -187,3 +205,11 @@ class TaskSchema(NonNullSchema): events: Events status: TasksStatusChoices error_message: Optional[str] + + +class DeploymentRequestCreateSchema(NonNullSchema): + deployment: PrimaryKeyReference + ppr: PrimaryKeyReference + manually: bool + delegate_l2: Optional[bool] + marketplaces: ChoicesSchema diff --git a/connect_ext_ppr/service.py b/connect_ext_ppr/service.py index 2cb37e7..4ac773b 100644 --- a/connect_ext_ppr/service.py +++ b/connect_ext_ppr/service.py @@ -10,10 +10,15 @@ from connect_ext_ppr.db import get_db_ctx_manager from connect_ext_ppr.errors import ExtensionHttpError from connect_ext_ppr.models.configuration import Configuration -from connect_ext_ppr.models.deployment import Deployment, MarketplaceConfiguration +from connect_ext_ppr.models.deployment import ( + Deployment, + DeploymentRequest, + MarketplaceConfiguration, +) from connect_ext_ppr.models.file import File from connect_ext_ppr.models.ppr import PPRVersion from connect_ext_ppr.models.replicas import Product +from connect_ext_ppr.models.task import Task from connect_ext_ppr.schemas import clean_empties_from_dict, FileSchema, PPRVersionCreateSchema from connect_ext_ppr.utils import ( build_summary, @@ -55,11 +60,12 @@ def add_marketplaces_to_deployment(db, deployment, marketplaces): configs = [] for marketplace in marketplaces: mc = MarketplaceConfiguration( - deployment=deployment.id, + deployment_id=deployment.id, marketplace=marketplace, ) configs.append(mc) db.add_all(configs) + db.commit() def add_deployments(installation, listings, config, logger): @@ -98,6 +104,7 @@ def add_deployments(installation, listings, config, logger): ) deployments.append(dep) seen.add(comb) + key = f"{product_id}#{hub_id}" deployments_marketplaces.setdefault( key, @@ -291,3 +298,57 @@ def create_ppr(ppr, user_id, deployment, db, client, logger): def validate_configuration(client, deployment, file_data): data = get_configuration_from_media(client, deployment.account_id, deployment.id, file_data.id) return validate_configuration_schema(data, deployment.product_id) + + +def add_new_deployment_request(db, dr_data, deployment, account_id, logger): + try: + deployment_request = DeploymentRequest( + deployment_id=dr_data.deployment.id, + ppr_id=dr_data.ppr.id, + manually=dr_data.manually, + delegate_l2=dr_data.delegate_l2, + created_by=account_id, + ) + db.set_next_verbose(deployment_request, 'deployment_id') + db.commit() + db.refresh(deployment_request) + + marketplaces = [m.id for m in dr_data.marketplaces.choices] + if dr_data.marketplaces.all: + marketplaces = [m.id for m in deployment.marketplaces] + + for m_id in marketplaces: + mc = MarketplaceConfiguration( + deployment_request=deployment_request.id, + marketplace=m_id, + ) + db.add(mc) + + tasks = [] + tasks.append(Task( + deployment_request=deployment_request.id, + title='PPR Validation', + type=Task.TYPES.ppr_validation, + created_by=account_id, + )) + tasks.append(Task( + deployment_request=deployment_request.id, + title='Apply PP and delegate to marketplaces', + type=Task.TYPES.apply_and_delegate, + created_by=account_id, + )) + if deployment_request.delegate_l2: + tasks.append(Task( + deployment_request=deployment_request.id, + title='Delegate to L2', + type=Task.TYPES.delegate_to_l2, + created_by=account_id, + )) + + db.set_all_next_verbose(tasks, 'deployment_request') + db.commit() + return deployment_request + except DBAPIError as ex: + logger.error(ex) + db.rollback() + raise ExtensionHttpError.EXT_003() diff --git a/connect_ext_ppr/static/images/mkp.svg b/connect_ext_ppr/static/images/mkp.svg deleted file mode 100644 index 38a59f2..0000000 --- a/connect_ext_ppr/static/images/mkp.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/connect_ext_ppr/static/index.5c5477c3e81eb95e1456.css b/connect_ext_ppr/static/index.5c5477c3e81eb95e1456.css deleted file mode 100644 index 5d771e7..0000000 --- a/connect_ext_ppr/static/index.5c5477c3e81eb95e1456.css +++ /dev/null @@ -1,3476 +0,0 @@ -/*!**************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ - !*** css ./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js!./node_modules/stylus-loader/dist/cjs.js!./node_modules/vue-loader/lib/index.js??vue-loader-options!./ui/src/components/cIcon.vue?vue&type=style&index=0&id=094f790b&lang=stylus& ***! - \**************************************************************************************************************************************************************************************************************************************************************************************************************************************/ -.c-icon { - color: #757575; - caret-color: currentColor; - vertical-align: text-bottom; - fill: currentColor; - height: 24px; - width: 24px; -} -.c-icon_disabled { - pointer-events: none; - color: #c5c5c5 !important; -} -.c-icon_link { - cursor: pointer; - outline: none; -} -button .c-icon { - color: inherit; -} - -/*!************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ - !*** css ./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js!./node_modules/stylus-loader/dist/cjs.js!./node_modules/vue-loader/lib/index.js??vue-loader-options!./ui/src/components/Pic.vue?vue&type=style&index=0&id=7ef515b9&lang=stylus&scoped=true& ***! - \************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ -.image[data-v-7ef515b9] { - overflow: hidden; - box-sizing: content-box; - position: relative; -} -.image__itself[data-v-7ef515b9] { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-repeat: no-repeat; - background-position: center; -} -.image__placeholder[data-v-7ef515b9] { - display: flex; - justify-content: center; - align-items: center; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; -} -.loader[data-v-7ef515b9] { - display: flex; - justify-content: center; - align-items: center; - height: 100%; -} - -/*!**************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ - !*** css ./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js!./node_modules/stylus-loader/dist/cjs.js!./node_modules/vue-loader/lib/index.js??vue-loader-options!./ui/src/components/cTabs.vue?vue&type=style&index=0&id=00476590&lang=stylus& ***! - \**************************************************************************************************************************************************************************************************************************************************************************************************************************************/ -.c-tabs__controls { - display: flex; - border-bottom: 1px solid #e0e0e0; -} -.c-tabs__controls_border_none { - border-bottom: none; -} -.c-tabs__content { - margin-top: 32px; -} -.c-tabs__control-tooltip { - position: relative; - display: flex; - align-items: center; - margin-left: 24px; - line-height: 48px; - white-space: nowrap; - cursor: pointer; - color: #212121; -} -.c-tabs__control-tooltip:first-child { - margin-left: 0; -} -a.c-tabs__control-tooltip { - text-decoration: none; -} -a.c-tabs__control-tooltip:hover { - color: var(--theme_accent); -} -.c-tabs__control-item { - font-weight: 500; - text-decoration: none; - text-transform: uppercase; - letter-spacing: 0.5px; - display: flex; - align-items: center; -} -.c-tabs__control-item:after { - content: ''; - height: 3px; - position: absolute; - right: 0; - bottom: -1px; - left: 0; - transform-origin: bottom; - transform: scaleY(0); - transition: transform 385ms cubic-bezier(0.4, 0, 0.2, 1); - background-color: var(--theme_accent); -} -.c-tabs__control-item_active { - color: var(--theme_accent); -} -.c-tabs__control-item_active:after { - transform: scaleX(1); -} -.c-tabs__control-item_disabled { - color: #bdbdbd !important; - cursor: default !important; -} -.c-tabs__control-item_height_full { - height: 100%; -} -.c-tabs__control-item .pic { - border-radius: 2px; -} - -/*!****************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ - !*** css ./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js!./node_modules/stylus-loader/dist/cjs.js!./node_modules/vue-loader/lib/index.js??vue-loader-options!./ui/src/components/cNavBar.vue?vue&type=style&index=0&id=b2fed2fc&lang=stylus& ***! - \****************************************************************************************************************************************************************************************************************************************************************************************************************************************/ -.navigation-bar { - box-sizing: content-box; - display: flex; - align-items: center; - flex: 0 0 auto; - height: 64px; - padding-left: 24px; - padding-right: 24px; - border-bottom: 1px solid #e0e0e0; - background: #f5f5f5; -} -.navigation-bar__page-title { - font-weight: 500; - font-size: 20px; - line-height: 24px; - margin-top: 0; - margin-bottom: 0; -} -.navigation-bar__page-assistive-title { - color: #707070; -} -.navigation-bar__back-button + .navigation-bar__page-title-holder, -.navigation-bar__back-button + .navigation-bar__page-title { - margin-left: 32px; -} -.navigation-bar__back-button { - margin: 0 -6px; - color: #666; - padding: 4px; -} -.navigation-bar__back-button:hover { - background: #e0e0e0; -} -.navigation-bar__tabs, -.navigation-bar__content, -.navigation-bar__actions { - padding-left: 48px; -} -.navigation-bar__tabs, -.navigation-bar__content { - display: flex; - align-self: stretch; -} -.navigation-bar__tabs { - flex: 0 0 auto; -} -.navigation-bar__content { - flex: 1 1 auto; -} -.navigation-bar__actions { - margin-left: auto; - display: flex; - align-items: center; - flex: 0 0 auto; -} -.page-title { - display: flex; - align-items: center; -} -.page-title__link { - display: flex; - align-items: center; - text-decoration: none; - color: #000; - cursor: pointer; -} -.actions-holder .actions-slot { - display: flex; - align-items: center; -} -.actions-holder .actions-slot > div { - padding-left: 16px; -} -.actions-holder__button { - margin: 0; - min-width: 0; -} -.actions-menu__divider { - margin-top: 7px; - margin-bottom: 8px; -} -._mb_2 { - margin-bottom: 2px; -} - -/*!**************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ - !*** css ./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js!./node_modules/stylus-loader/dist/cjs.js!./node_modules/vue-loader/lib/index.js??vue-loader-options!./ui/src/components/cView.vue?vue&type=style&index=0&id=7c928137&lang=stylus& ***! - \**************************************************************************************************************************************************************************************************************************************************************************************************************************************/ -.c-view { - position: relative; - flex: 1 1 100%; - display: grid; - grid-template-rows: auto auto; - grid-template-columns: 1fr; - grid-template-areas: "n" "c"; - overflow: auto; -} -.c-view__progress-wrapper { - position: absolute; - left: 0; - right: 0; - top: 0; - bottom: 0; - display: flex; -} -.c-view__navigation { - grid-area: n; -} -.c-view__content-holder { - position: relative; - grid-area: c; -} -.c-view__content { - position: relative; - min-height: 100%; - box-sizing: border-box; - padding-bottom: 64px; -} -.c-view__content_padded { - padding: 24px 24px 40px; -} -.c-view__content:empty, -.c-view__navigation:empty { - display: none; -} - -/*!**************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ - !*** css ./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js!./node_modules/stylus-loader/dist/cjs.js!./node_modules/vue-loader/lib/index.js??vue-loader-options!./ui/src/components/cMenu.vue?vue&type=style&index=0&id=114e6ef1&lang=stylus& ***! - \**************************************************************************************************************************************************************************************************************************************************************************************************************************************/ -.c-menu { - --c-menu-trigger-color: transparent; - --c-menu-offsetX: -80px; - --c-menu-offsetY: 0; - --c-menu-left: 0; - --c-menu-top: 0; - position: static; - display: inline-block; - vertical-align: middle; -} -.c-menu__trigger { - position: relative; - cursor: pointer; -} -.c-menu__container { - position: absolute; - top: var(--c-menu-top); - left: var(--c-menu-left); - transform-origin: left top; - display: inline-block; - overflow-y: auto; - overflow-x: hidden; - contain: content; - will-change: transform; - white-space: nowrap; - border-radius: 4px; - background: #fff; - box-shadow: 0 4px 10px 0 rgba(0,0,0,0.25); -} -.v-dialog .c-menu__container { - z-index: 201 !important; -} -.c-menu_position-center .c-menu__container { - transform: translateX(-50%) translateY(0); - top: revert; - left: revert; -} -.c-menu_position-left .c-menu__container { - top: revert; - left: revert; -} -.c-menu_position-right .c-menu__container { - transform: translateX(var(--c-menu-offsetX)) translateY(var(--c-menu-offsetY)); - top: revert; - left: revert; -} -.c-menu_at-top .c-menu__container { - top: auto; - bottom: 100%; -} -.c-menu_active .c-menu__trigger .c-button { - background: var(--c-menu-trigger-color); -} -.c-menu_disabled { - cursor: default; -} -.c-menu_full-width { - width: 100%; -} -.c-menu_attached.c-menu_at-top { - position: relative; -} - -/*!****************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ - !*** css ./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js!./node_modules/stylus-loader/dist/cjs.js!./node_modules/vue-loader/lib/index.js??vue-loader-options!./ui/src/components/cTable/cTableHeader.vue?vue&type=style&index=0&id=6bcab16a&lang=stylus&scoped=true& ***! - \****************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ -.c-table-header[data-v-6bcab16a] { - min-height: 32px; - font-size: 12px; - line-height: 20px; - letter-spacing: 0.5px; - color: #707070; - text-transform: uppercase; - font-weight: bold; - padding-right: 12px; - padding-left: 12px; -} -.c-table-header[data-v-6bcab16a]:first-child { - border-left: none; - padding-left: 8px; -} -.c-table-header[data-v-6bcab16a]:last-child { - border-right: none; - padding-right: 8px; -} -.c-table-header_disabled-resize[data-v-6bcab16a] { - pointer-events: none; -} -.c-table-header__content[data-v-6bcab16a] { - display: flex; - align-items: center; - min-width: 0; -} -.c-table-header__content-icon[data-v-6bcab16a] { - margin-right: 4px; - border-radius: 2px; -} -.c-table-header__text[data-v-6bcab16a] { - line-height: 32px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} -.c-table-header__icon[data-v-6bcab16a] { - margin-left: 2px; - transition: none; - flex-shrink: 0; -} -.c-table-header__icon_active[data-v-6bcab16a] { - color: var(--theme_accent); -} -.c-table-header__button[data-v-6bcab16a] { - width: auto; - height: 32px; - overflow: hidden; - align-items: center; - line-height: 32px; - padding-right: 8px; - padding-left: 8px; - margin-left: -8px; - cursor: pointer; - transition: background-color 0.2s; - text-transform: uppercase; -} -.c-table-header__button_active[data-v-6bcab16a] { - background-color: rgba(33,33,33,0.05); -} -.c-table-header__button[disabled][data-v-6bcab16a] { - cursor: default; -} -.c-table-header__button[disabled][data-v-6bcab16a]:hover { - background-color: transparent; -} -.c-table-header__wrapper[data-v-6bcab16a] { - width: 100%; - display: flex; - align-items: center; -} -.v-menu--inline[data-v-6bcab16a] { - display: block; -} -.header-menu[data-v-6bcab16a] { - padding: 8px 0; -} -.header-menu__title[data-v-6bcab16a] { - padding: 4px 16px 4px 24px; - font-size: 14px; - font-weight: 500; - color: #666; -} -.header-menu__item[data-v-6bcab16a] { - min-height: 48px; - display: flex; - align-items: center; - font-size: 14px; - line-height: 24px; - padding: 12px 16px 12px 24px; - cursor: pointer; -} -.header-menu__item[data-v-6bcab16a]:hover { - background-color: rgba(33,33,33,0.05); -} -.header-menu__item_active[data-v-6bcab16a] { - background-color: rgba(var(--theme_accent_rgb),0.15) !important; - color: var(--theme_accent); -} -.header-menu__item_active .header-menu__icon[data-v-6bcab16a] { - color: var(--theme_accent); -} -.header-menu__icon[data-v-6bcab16a] { - margin-right: 24px; - font-size: 24px; -} -.header-menu__label[data-v-6bcab16a] { - color: inherit; -} -.v-menu__content[data-v-6bcab16a] { - overflow: hidden; - background: #fff; -} -.th-menu[data-v-6bcab16a] { - width: auto; - min-width: 0; -} -.th-menu .c-menu__trigger[data-v-6bcab16a] { - margin-left: -8px; -} -i[data-v-6bcab16a] { - font-size: 18px; -} -i.active[data-v-6bcab16a] { - color: var(--theme_accent); -} -i.nosort[data-v-6bcab16a] { - color: rgba(0,0,0,0.26); -} -.scrollable[data-v-6bcab16a] { - overflow-y: auto; -} - -/*!****************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ - !*** css ./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js!./node_modules/stylus-loader/dist/cjs.js!./node_modules/vue-loader/lib/index.js??vue-loader-options!./ui/src/components/cButton.vue?vue&type=style&index=0&id=6548a8c4&lang=stylus& ***! - \****************************************************************************************************************************************************************************************************************************************************************************************************************************************/ -.c-button { - --button-color: 33, 33, 33; - --button-computed-color: var(--button-custom-color, var(--button-color)); - --button-border-color: #e0e0e0; - --button-padding: 8px; - --button-height: 36px; - --button-min-width: 80px; - --button-label-size: 14px; - --button-label-margin: 8px; - --button-label-letter-spacing: 0.6px; - --button-icon-margin: 4px; - border: none; - font-family: Roboto, "Helvetica Neue", sans-serif; - display: inline-flex; - align-items: center; - justify-content: center; - height: var(--button-height); - min-width: var(--button-min-width); - overflow: hidden; - padding-left: var(--button-padding); - padding-right: var(--button-padding); - color: rgb(var(--button-computed-color)); - background-color: transparent; - border-radius: 2px; - cursor: pointer; - vertical-align: bottom; - box-sizing: border-box; - position: relative; -} -.c-button_fluid { - display: flex; - width: 100%; -} -.c-button__link { - position: absolute; - cursor: pointer; - top: 0; - right: 0; - bottom: 0; - left: 0; -} -.c-button:hover, -.c-button_active { - background-color: rgba(var(--button-computed-color),0.1); -} -.c-button_solid { - background-color: rgb(var(--button-computed-color)); /* given color */ - color: rgb(var(--solid-content-color)); /* calculated */ -} -.c-button_solid:hover, -.c-button_solid.c-button_active { - background-image: linear-gradient(rgba(255,255,255,0.4), rgba(255,255,255,0.4)), linear-gradient(rgb(var(--button-computed-color)), rgb(var(--button-computed-color))); -} -.c-button_outlined { - --button-padding: 7px; - border: 1px solid var(--button-border-color); - background-color: #fff; -} -.c-button__label { - margin-left: var(--button-label-margin); - margin-right: var(--button-label-margin); - font-size: var(--button-label-size); - line-height: 20px; - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; - flex-shrink: 1; - flex-grow: 0; -} -.c-button__label_uppercase { - text-transform: uppercase; - letter-spacing: var(--button-label-letter-spacing); -} -.c-button__icon-left, -.c-button__icon-right { - display: flex; - flex: 0 0 auto; -} -.c-button__icon-left .c-icon, -.c-button__icon-right .c-icon { - color: inherit; -} -.c-button__icon-left { - margin-left: var(--button-icon-margin); -} -.c-button__icon-right { - margin-right: var(--button-icon-margin); -} -.c-button_small { - --button-height: 28px; - --button-min-width: 64px; - --button-padding: 6px; - --button-label-size: 12px; - --button-label-margin: 4px; - --button-label-letter-spacing: 0.5px; - --button-icon-margin: 2px; -} -.c-button_icon-only { - --button-padding: 0; - --button-icon-margin: 0; - --button-min-width: var(--button-height); - width: var(--button-height); -} -.c-button_txt-only .c-icon { - position: absolute; -} -.c-button_rounded { - border-radius: 50%; -} -.c-button_disabled { - color: #bdbdbd; - cursor: default; - pointer-events: none; -} -.c-button_disabled.c-button_solid { - background: #f2f2f2; -} -.c-button_fluid { - display: flex; -} -.c-button__label_loading { - visibility: hidden; -} -.c-button__label a { - text-decoration: none; - color: inherit; -} - -/*!*****************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ - !*** css ./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js!./node_modules/stylus-loader/dist/cjs.js!./node_modules/vue-loader/lib/index.js??vue-loader-options!./ui/src/components/cTooltip.vue?vue&type=style&index=0&id=3d7ddf3e&scoped=true&lang=stylus& ***! - \*****************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ -.c-tooltip[data-v-3d7ddf3e] { - display: inline-block; -} -.c-tooltip__content[data-v-3d7ddf3e] { - z-index: 301 !important; - background: #616161; - border-radius: 2px; - color: #fff; - font-size: 12px; - padding: 5px 8px; - position: absolute; - text-transform: initial; - display: inline-block; - width: auto; - 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); -} - -/*!*********************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ - !*** css ./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js!./node_modules/stylus-loader/dist/cjs.js!./node_modules/vue-loader/lib/index.js??vue-loader-options!./ui/src/components/cTable/cTableControlMenu.vue?vue&type=style&index=0&id=5856740e&lang=stylus& ***! - \*********************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ -.c-table-control-menu { - background: #fff; - max-height: 600px; - padding: 8px 16px; -} -.c-table-control-menu__buttons { - display: flex; - height: 56px; - align-items: center; -} -.c-table-control-menu__buttons .c-button { - margin: 0; -} -.c-table-control-menu__buttons .c-button:last-child { - margin-left: auto; -} - -/*!*************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ - !*** css ./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js!./node_modules/stylus-loader/dist/cjs.js!./node_modules/vue-loader/lib/index.js??vue-loader-options!./ui/src/components/cTable/cTableHeadersSelector.vue?vue&type=style&index=0&id=706183b7&lang=stylus&scoped=true& ***! - \*************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ -.headers-selector[data-v-706183b7] { - padding: 8px 0px; -} -.headers-selector[data-v-706183b7] .c-tooltip:first-child .v-input--selection-controls { - margin-top: 0px; -} -.selector-option[data-v-706183b7] { - display: block; -} - -/*!*******************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ - !*** css ./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js!./node_modules/stylus-loader/dist/cjs.js!./node_modules/vue-loader/lib/index.js??vue-loader-options!./ui/src/components/cTextField.vue?vue&type=style&index=0&id=b5bb9caa&lang=stylus&scoped=true& ***! - \*******************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ -.c-text-field[data-v-b5bb9caa] { - --ctf-color-default-text: 33, 33, 33; - --ctf-color-border: #d8d8d8; - --ctf-color-accent: var(--theme_accent); - --ctf-color-warning: #f2994a; - --ctf-color-error: #ff6a6a; - --ctf-color-background: #fbfbfb; - --ctf-color-disabled: 189, 189, 189; - --ctf-color-icon: 102, 102, 102; - --ctf-color-assistive-text: #707070; - --ctf-color-current: var(--ctf-color-default-text); - --ctf-unit: 4; - --ctf-unit-x2: calc(var(--ctf-unit) * 2); - --ctf-unit-x3: calc(var(--ctf-unit) * 3); - --ctf-unit-x4: calc(var(--ctf-unit) * 4); - --ctf-unit-x5: calc(var(--ctf-unit) * 5); - --ctf-unit-x6: calc(var(--ctf-unit) * 6); - --ctf-unit-px: calc(var(--ctf-unit) * 1px); - --ctf-unit-px2: calc(var(--ctf-unit-x2) * 1px); - --ctf-unit-px3: calc(var(--ctf-unit-x3) * 1px); - --ctf-unit-px4: calc(var(--ctf-unit-x4) * 1px); - --ctf-unit-px5: calc(var(--ctf-unit-x5) * 1px); - --ctf-unit-px6: calc(var(--ctf-unit-x6) * 1px); - --ctf-label-offset: var(--ctf-unit-px2); - --ctf-buttons-offset: var(--ctf-unit-px2); - --ctf-wrapper-offset: var(--ctf-unit-px); - --ctf-wrapper-parts-offset: var(--ctf-unit-px3); - --ctf-body-parts-offset: var(--ctf-unit-px3); - --ctf-border-width: 1px; - --ctf-input-padding: var(--ctf-unit-px3); - --ctf-input-padding-fixed: calc(var(--ctf-input-padding) - var(--ctf-border-width)); - --ctf-input-padding-sm: calc(var(--ctf-unit-px3) / 2); - --ctf-input-padding-fixed-sm: calc(var(--ctf-input-padding-sm) - var(--ctf-border-width)); - --ctf-input-padding-x-sm: var(--ctf-unit-px2); - --ctf-input-padding-x-fixed-sm: calc(var(--ctf-input-padding-x-sm) - var(--ctf-border-width)); - --ctf-font-family: Roboto, "Helvetica Neue", sans-serif; - --ctf-font-size: 14px; - --ctf-line-height: 20px; - --ctf-font-size-sm: 12px; - --ctf-line-height-sm: 16px; - --crf-font-weight-main: 400; - --ctf-font-weight-label: 500; - --ctf-body-max-height: calc(var(--ctf-input-padding) * 2 + var(--ctf-line-height)); - --ctf-body-max-height-sm: calc(var(--ctf-input-padding-sm) * 2 + var(--ctf-line-height)); - --cb-width: 36px; - --ci-width: 24px; - --cb-width-sm: 28px; - --ci-width-sm: 18px; - --cb-offset: calc((var(--cb-width) - var(--ci-width)) / 2); - --cb-offset-sm: calc((var(--cb-width-sm) - var(--ci-width-sm)) / 2); - font-family: var(--ctf-font-family, 'Roboto'); - font-size: var(--ctf-font-size, 14px); - line-height: var(--ctf-line-height, 20px); - font-weight: var(--ctf-font-weight-main, 400); - display: flex; - flex-flow: column nowrap; - color: rgb(var(--ctf-color-default-text)); -} -.c-text-field.c-text-field_focused[data-v-b5bb9caa], -.c-text-field.c-text-field_warning[data-v-b5bb9caa], -.c-text-field.c-text-field_error[data-v-b5bb9caa] { - --ctf-border-width: 2px; - --ctf-input-padding-fixed: calc(var(--ctf-input-padding) - var(--ctf-border-width)); -} -.c-text-field.c-text-field_small[data-v-b5bb9caa] { - --ctf-wrapper-parts-offset: var(--ctf-unit-px2); - --ctf-body-parts-offset: var(--ctf-unit-px2); -} -.c-text-field.c-text-field_small.c-text-field_focused[data-v-b5bb9caa], -.c-text-field.c-text-field_small.c-text-field_warning[data-v-b5bb9caa], -.c-text-field.c-text-field_small.c-text-field_error[data-v-b5bb9caa] { - --ctf-input-padding-fixed-sm: calc(var(--ctf-input-padding-sm) - var(--ctf-border-width)); - --ctf-input-padding-x-fixed-sm: calc(var(--ctf-input-padding-x-sm) - var(--ctf-border-width)); -} -.c-text-field__label[data-v-b5bb9caa] { - font-size: var(--ctf-font-size); - line-height: var(--ctf-line-height); - font-weight: var(--ctf-font-weight-label); - flex-grow: 1; - position: relative; - max-height: 20px; - display: flex; - flex-flow: row nowrap; - align-items: center; - margin-bottom: var(--ctf-label-offset); -} -.c-text-field_disabled .c-text-field__label[data-v-b5bb9caa] { - color: rgb(var(--ctf-color-disabled)); -} -.c-text-field__label span[data-v-b5bb9caa] { - flex-grow: 1; - margin-right: var(--ctf-unit-px2); -} -.c-text-field_label-left-icon .c-text-field__label span[data-v-b5bb9caa] { - flex-grow: 0; -} -.c-text-field_required .c-text-field__label span[data-v-b5bb9caa]::after { - content: '(required)'; - display: inline-block; - margin-left: 3px; - text-decoration: none; -} -.c-text-field_disabled.c-text-field_required .c-text-field__label span[data-v-b5bb9caa]::after { - color: rgb(var(--ctf-color-disabled)); -} -.c-text-field_optional .c-text-field__label span[data-v-b5bb9caa]::after { - content: '(optional)'; - display: inline-block; - margin-left: 3px; - color: rgb(var(--ctf-color-default-text)); - text-decoration: none; -} -.c-text-field_disabled.c-text-field_optional .c-text-field__label span[data-v-b5bb9caa]::after { - color: rgb(var(--ctf-color-disabled)); -} -.c-text-field__label-icon[data-v-b5bb9caa] { - --ctf-color-current: var(--ctf-color-icon); - position: absolute; - right: 0; - top: 0; - color: rgb(var(--ctf-color-current)); -} -.c-text-field_disabled .c-text-field__label-icon[data-v-b5bb9caa] { - --ctf-color-current: var(--ctf-color-disabled); -} -.c-text-field_label-left-icon .c-text-field__label-icon[data-v-b5bb9caa] { - position: static; -} -.c-text-field__wrapper[data-v-b5bb9caa] { - display: flex; - flex-flow: row nowrap; - align-items: center; -} -.c-text-field__prepend[data-v-b5bb9caa] { - --ctf-color-current: var(--ctf-color-icon); - margin-right: var(--ctf-wrapper-parts-offset); - color: rgb(var(--ctf-color-current)); -} -.c-text-field_disabled .c-text-field__prepend[data-v-b5bb9caa] { - --ctf-color-current: var(--ctf-color-disabled); -} -.c-text-field__body[data-v-b5bb9caa] { - flex-grow: 1; - display: flex; - flex-flow: row nowrap; - align-items: center; - max-height: var(--ctf-body-max-height); - padding: var(--ctf-input-padding-fixed); - border: var(--ctf-border-width) solid var(--ctf-color-border); - border-radius: 2px; - background-color: var(--ctf-color-background); - cursor: pointer; -} -.c-text-field_disabled .c-text-field__body[data-v-b5bb9caa], -[disabled] .c-text-field__body[data-v-b5bb9caa], -:disabled .c-text-field__body[data-v-b5bb9caa] { - border-style: dashed; - cursor: default; -} -.c-text-field_focused .c-text-field__body[data-v-b5bb9caa] { - border-color: rgb(var(--ctf-color-accent)); -} -.c-text-field_warning .c-text-field__body[data-v-b5bb9caa] { - border-color: var(--ctf-color-warning); -} -.c-text-field_error .c-text-field__body[data-v-b5bb9caa] { - border-color: var(--ctf-color-error); -} -.c-text-field__body input + svg[data-v-b5bb9caa], -.c-text-field__body button + svg[data-v-b5bb9caa] { - margin-left: var(--cb-offset); -} -.c-text-field_small .c-text-field__body input + svg[data-v-b5bb9caa], -.c-text-field_small .c-text-field__body button + svg[data-v-b5bb9caa] { - margin-left: var(--cb-offset-sm); -} -.c-text-field__body svg + svg[data-v-b5bb9caa] { - margin-left: calc(2 * var(--cb-offset)); -} -.c-text-field_small .c-text-field__body svg + svg[data-v-b5bb9caa] { - margin-left: calc(2 * var(--cb-offset-sm)); -} -.c-text-field__body button[data-v-b5bb9caa]:last-child { - margin-right: calc(-1 * var(--cb-offset)); -} -.c-text-field_small .c-text-field__body button[data-v-b5bb9caa]:last-child { - margin-right: calc(-1 * var(--cb-offset-sm)); -} -.c-text-field__body svg[data-v-b5bb9caa]:last-child { - margin-right: 0; -} -.c-text-field_small .c-text-field__body[data-v-b5bb9caa] { - max-height: var(--ctf-body-max-height-sm); - padding-top: var(--ctf-input-padding-fixed-sm); - padding-bottom: var(--ctf-input-padding-fixed-sm); - padding-left: var(--ctf-input-padding-x-fixed-sm); - padding-right: var(--ctf-input-padding-x-fixed-sm); -} -.c-text-field__prepend-inner[data-v-b5bb9caa] { - --ctf-color-current: var(--ctf-color-icon); - display: flex; - flex-flow: row nowrap; - align-items: center; - max-height: var(--ctf-line-height); - color: rgb(var(--ctf-color-current)); -} -.c-text-field_disabled .c-text-field__prepend-inner[data-v-b5bb9caa] { - --ctf-color-current: var(--ctf-color-disabled); -} -.c-text-field__prepend-inner svg[data-v-b5bb9caa]:last-child { - margin-right: var(--ctf-body-parts-offset); -} -.c-text-field__prepend-inner button[data-v-b5bb9caa]:last-child { - margin-right: var(--ctf-buttons-offset); -} -.c-text-field__prefix[data-v-b5bb9caa] { - margin-right: var(--ctf-body-parts-offset); - color: var(--ctf-color-assistive-text); -} -.c-text-field_disabled .c-text-field__prefix[data-v-b5bb9caa] { - color: rgb(var(--ctf-color-disabled)); -} -.c-text-field__input[data-v-b5bb9caa] { - flex-grow: 1; - outline: none; -} -.c-text-field__input[data-v-b5bb9caa]:hover, -.c-text-field__input[data-v-b5bb9caa]:focus { - outline: none; -} -.c-text-field__input[data-v-b5bb9caa]:-webkit-autofill, -.c-text-field__input[data-v-b5bb9caa]:-webkit-autofill:hover, -.c-text-field__input[data-v-b5bb9caa]:-webkit-autofill:focus, -.c-text-field__input[data-v-b5bb9caa]:-webkit-autofill:active { - -webkit-box-shadow: 0 0 0 30px var(--ctf-color-background) inset !important; -} -.c-text-field__input[data-v-b5bb9caa]::placeholder { - color: var(--ctf-color-assistive-text); -} -.c-text-field_disabled .c-text-field__input[data-v-b5bb9caa] { - color: rgb(var(--ctf-color-disabled)); -} -.c-text-field__suffix[data-v-b5bb9caa] { - margin-left: var(--ctf-body-parts-offset); - color: var(--ctf-color-assistive-text); -} -.c-text-field_disabled .c-text-field__suffix[data-v-b5bb9caa] { - color: rgb(var(--ctf-color-disabled)); -} -.c-text-field__suffix + button[data-v-b5bb9caa] { - margin-left: var(--ctf-body-parts-offset); -} -.c-text-field__toggle-visibility[data-v-b5bb9caa] { - color: rgb(var(--ctf-color-icon)); -} -.c-text-field_disabled .c-text-field__toggle-visibility[data-v-b5bb9caa] { - color: rgb(var(--ctf-color-disabled)); -} -.c-text-field__input + .c-text-field__toggle-visibility[data-v-b5bb9caa] { - margin-left: var(--ctf-buttons-offset); -} -.c-text-field__clearable[data-v-b5bb9caa] { - color: rgb(var(--ctf-color-icon)); -} -.c-text-field_disabled .c-text-field__clearable[data-v-b5bb9caa] { - color: rgb(var(--ctf-color-disabled)); -} -.c-text-field__input + .c-text-field__clearable[data-v-b5bb9caa] { - margin-left: var(--ctf-buttons-offset); -} -.c-text-field__append-inner[data-v-b5bb9caa] { - --ctf-color-current: var(--ctf-color-icon); - display: flex; - flex-flow: row nowrap; - align-items: center; - max-height: var(--ctf-line-height); - color: rgb(var(--ctf-color-current)); -} -.c-text-field_disabled .c-text-field__append-inner[data-v-b5bb9caa] { - --ctf-color-current: var(--ctf-color-disabled); -} -.c-text-field__append-inner .c-button[data-v-b5bb9caa] { - overflow: visible; -} -.c-text-field__input + .c-text-field__append-inner button[data-v-b5bb9caa]:first-child { - margin-left: var(--ctf-buttons-offset); -} -.c-text-field__input + .c-text-field__append-inner svg[data-v-b5bb9caa]:first-child { - margin-left: var(--ctf-body-parts-offset); -} -button + .c-text-field__append-inner > svg[data-v-b5bb9caa]:first-child { - margin-left: var(--cb-offset); -} -.c-text-field_small button + .c-text-field__append-inner > svg[data-v-b5bb9caa]:first-child { - margin-left: var(--cb-offset-sm); -} -.c-text-field__append-inner svg + button[data-v-b5bb9caa] { - margin-left: var(--cb-offset); -} -.c-text-field_small .c-text-field__append-inner svg + button[data-v-b5bb9caa] { - margin-left: var(--cb-offset-sm); -} -.c-text-field__append[data-v-b5bb9caa] { - --ctf-color-current: var(--ctf-color-icon); - margin-left: var(--ctf-wrapper-parts-offset); - color: rgb(var(--ctf-color-current)); -} -.c-text-field_disabled .c-text-field__append[data-v-b5bb9caa] { - --ctf-color-current: var(--ctf-color-disabled); -} -.c-text-field__underline[data-v-b5bb9caa] { - font-size: var(--ctf-font-size-sm); - line-height: var(--ctf-line-height-sm); - position: relative; - display: flex; - flex-flow: row nowrap; - justify-content: flex-start; - margin-top: var(--ctf-wrapper-offset); - color: var(--ctf-color-assistive-text); -} -.c-text-field_disabled .c-text-field__underline[data-v-b5bb9caa] { - color: rgb(var(--ctf-color-disabled)); -} -.c-text-field__underline-icon[data-v-b5bb9caa] { - --ctf-color-current: var(--ctf-color-icon); - position: absolute; - left: 0; - top: 0; - max-height: var(--ctf-line-height-sm); - margin-right: var(--ctf-unit-px); - color: rgb(var(--ctf-color-current)); -} -.c-text-field_warning .c-text-field__underline-icon[data-v-b5bb9caa] { - --ctf-color-current: var(--ctf-color-warning); -} -.c-text-field_error .c-text-field__underline-icon[data-v-b5bb9caa] { - --ctf-color-current: var(--ctf-color-error); -} -.c-text-field_disabled .c-text-field__underline-icon[data-v-b5bb9caa] { - --ctf-color-current: var(--ctf-color-disabled); -} -.c-text-field__errors[data-v-b5bb9caa], -.c-text-field__warnings[data-v-b5bb9caa] { - flex-grow: 1; - display: flex; - flex-flow: column nowrap; - padding: 0; -} -.c-text-field__underline-icon + .c-text-field__errors[data-v-b5bb9caa], -.c-text-field__underline-icon + .c-text-field__warnings[data-v-b5bb9caa] { - padding-left: 16px; -} -.c-text-field__errors[data-v-b5bb9caa] { - color: var(--ctf-color-error); -} -.c-text-field__warnings[data-v-b5bb9caa] { - color: var(--ctf-color-warning); -} -.c-text-field__error[data-v-b5bb9caa], -.c-text-field__warning[data-v-b5bb9caa] { - list-style-type: none; -} -.c-text-field__helper[data-v-b5bb9caa] { - flex-grow: 1; -} -.c-text-field_warning .c-text-field__helper[data-v-b5bb9caa] { - color: var(--ctf-color-warning); -} -.c-text-field_error .c-text-field__helper[data-v-b5bb9caa] { - color: var(--ctf-color-error); -} -.c-text-field__underline-icon + .c-text-field__helper[data-v-b5bb9caa] { - padding-left: 16px; -} - -/*!*******************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ - !*** css ./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js!./node_modules/stylus-loader/dist/cjs.js!./node_modules/vue-loader/lib/index.js??vue-loader-options!./ui/src/components/NumberItem.vue?vue&type=style&index=0&id=e7d6f7c6&lang=stylus&scoped=true& ***! - \*******************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ -.number__item + .number__item[data-v-e7d6f7c6] { - margin-left: 0.25em; -} - -/*!********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ - !*** css ./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js!./node_modules/stylus-loader/dist/cjs.js!./node_modules/vue-loader/lib/index.js??vue-loader-options!./ui/src/components/cTable/cTablePagination.vue?vue&type=style&index=0&id=3a56ead8&lang=stylus&scoped=true& ***! - \********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ -.pagination[data-v-3a56ead8] { - --pagination-text-color: #707070; - --pagination-text-color-current: #2c98f0; - display: inline-flex; - flex-flow: row nowrap; - align-items: center; - width: 100%; -} -.pagination_hidden[data-v-3a56ead8] { - justify-content: flex-end; -} -.pagination_p24[data-v-3a56ead8] { - padding-left: 24px; - padding-right: 24px; -} -.pagination__navigation[data-v-3a56ead8] { - display: flex; -} -.pagination__part[data-v-3a56ead8] { - display: inline-flex; - flex-flow: row wrap; - align-items: center; -} -.pagination__part_left[data-v-3a56ead8] { - justify-content: flex-start; - flex-grow: 1; -} -.pagination__part_right[data-v-3a56ead8] { - justify-content: flex-end; -} -.pagination__button[data-v-3a56ead8] { - min-width: 28px; - margin-right: 4px; - transition: background-color 0.15s ease-in; -} -.pagination__button[data-v-3a56ead8]:first-child { - margin-right: 16px; -} -.pagination__button[data-v-3a56ead8]:last-of-type { - margin-left: 16px; - margin-right: 16px; -} -.pagination__button-current[data-v-3a56ead8] { - font-family: 'Roboto'; - font-style: normal; - font-weight: 400; - font-size: 12px; - line-height: 20px; - font-weight: 500; - padding: 4px 8px; - min-width: 28px; - margin-right: 4px; - border-width: 0; - color: var(--pagination-text-color-current); - background-color: rgba(44,152,240,0.2); - border-radius: 2px; - text-align: center; -} -.pagination__more[data-v-3a56ead8] { - font-family: 'Roboto'; - font-style: normal; - font-weight: 400; - font-size: 12px; - line-height: 20px; - width: 12px; - margin-right: 4px; - color: var(--pagination-text-color); -} -.pagination__goto-page[data-v-3a56ead8] { - --ctf-input-padding-fixed-sm: 3px; -} -[data-v-3a56ead8] .pagination__goto-page.pagination__goto-page.c-text-field_focused { - --ctf-input-padding-fixed-sm: 2px; -} -.pagination__text[data-v-3a56ead8] { - font-family: 'Roboto'; - font-style: normal; - font-weight: 400; - font-size: 12px; - line-height: 20px; - display: inline-flex; - align-items: center; - margin-right: 8px; - color: var(--pagination-text-color); -} -.pagination__rows-selection[data-v-3a56ead8] { - margin-right: 16px; -} -.pagination__rows-selection-btn[data-v-3a56ead8] { - justify-content: flex-start; - padding-left: 18px; -} -.pagination__dot[data-v-3a56ead8] { - font-family: 'Roboto'; - font-style: normal; - font-weight: 400; - font-size: 12px; - line-height: 20px; - color: var(--pagination-text-color); -} -.pagination__info[data-v-3a56ead8] { - font-family: 'Roboto'; - font-style: normal; - font-weight: 400; - font-size: 12px; - line-height: 20px; - display: inline-flex; - align-items: center; - color: var(--pagination-text-color); -} -.pagination__go-to-page[data-v-3a56ead8] { - display: flex; -} -.c-menu-list[data-v-3a56ead8] { - position: relative; -} -.c-menu-list_at-top[data-v-3a56ead8] { - --c-menu-offsetY: -2px; -} -.c-menu-list_at-bottom[data-v-3a56ead8] { - --c-menu-offsetY: 2px; -} -.c-menu-list__open[data-v-3a56ead8] { - font-weight: 500; - letter-spacing: var(--button-label-letter-spacing); - min-width: 51px; - margin-right: 0; - transition: background-color 0.15s ease-in; -} -.c-menu-list__list[data-v-3a56ead8] { - margin: 0; - padding: 0; - list-style: none; -} -.c-menu-list__item[data-v-3a56ead8] { - padding: 0; - text-align: left; -} -.c-menu-list__item[data-v-3a56ead8] > *:hover, -.c-menu-list__item[data-v-3a56ead8] > *:focus { - color: var(--theme_accent); - background-color: rgba(var(--theme_accent_rgb),0.1); -} - -/*!***************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ - !*** css ./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js!./node_modules/stylus-loader/dist/cjs.js!./node_modules/vue-loader/lib/index.js??vue-loader-options!./ui/src/components/cTable.vue?vue&type=style&index=0&id=00cc8fa8&lang=stylus& ***! - \***************************************************************************************************************************************************************************************************************************************************************************************************************************************/ -.fade-enter-active { - transition: opacity 0.4s ease-out; -} -.fade-leave-active { - transition: opacity 0.4s ease-in; -} -.fade-enter, -.fade-leave-to { - opacity: 0; -} -.c-table { - position: relative; -} -.c-table_layout_fixed { - table-layout: fixed; -} -.c-table_loading tr:hover { - background: none !important; -} -.c-table_dense tbody tr td { - height: 32px; -} -.c-table__overflow { - width: 100%; - overflow-x: auto; - overflow-y: hidden; -} -.c-table table { - border-collapse: collapse; - border-spacing: 0; - width: 100%; - max-width: 100%; -} -.c-table__loader { - animation: aniVertical 3s ease; - animation-iteration-count: infinite; - animation-fill-mode: forwards; - opacity: 1; -} -.c-table__loader_skeleton { - border-radius: 8px; - background: #d9d9d9; - height: 12px; - max-width: 100%; -} -.c-table__loader:nth-child(2) { - animation-delay: 0.5s; -} -.c-table__loader:nth-child(3) { - animation-delay: 1s; -} -.c-table__loader:nth-child(4) { - animation-delay: 1.5s; -} -.c-table__loader:nth-child(5) { - animation-delay: 2s; -} -.c-table__loader:nth-child(6) { - animation-delay: 2.5s; -} -.c-table__loader:nth-child(7) { - animation-delay: 3s; -} -.c-table__loader:nth-child(8) { - animation-delay: 3.5s; -} -.c-table__loader:nth-child(9) { - animation-delay: 4s; -} -.c-table__loader:nth-child(10) { - animation-delay: 4.5s; -} -.c-table__pagination.disabled { - pointer-events: none; - opacity: 0.3; - filter: grayscale(100%); -} -.c-table th, -.c-table td { - box-sizing: content-box; -} -.c-table td { - height: 48px; - font-size: 14px; - padding-right: 12px; - padding-left: 12px; -} -.c-table td .date-item { - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} -.c-table td .detail-item__assistive-text, -.c-table td .detail-item__text { - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} -.c-table td a, -.c-table td .status-mark { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} -.c-table td .assistive-text { - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} -.c-table th:first-child { - border-left: none; - padding-left: var(--padding); -} -.c-table th:last-child { - border-right: none; - padding-right: var(--padding); -} -.c-table thead { - border-top: 1px solid #e0e0e0; - border-bottom: 1px solid #e0e0e0; - background-color: #f5f5f5; -} -.c-table thead th { - overflow: hidden; - height: 32px; - min-height: 32px; - padding-right: 12px; - padding-left: 12px; - font-size: 12px; - line-height: 20px; - letter-spacing: 0.5px; - color: #707070; - text-transform: uppercase; -} -.c-table thead tr th:first-child, -.c-table tbody tr td:first-child { - padding-left: var(--padding) !important; -} -.c-table thead tr th:last-child, -.c-table tbody tr td:last-child { - padding-right: var(--padding) !important; -} -.c-table tbody > tr:not(:last-child) { - border-bottom: 1px solid #e0e0e0; -} -.c-table tbody > tr:last-child td { - border-bottom: none; -} -.c-table__panel { - display: flex; - align-items: center; - justify-content: space-between; - height: 48px; - padding-left: var(--padding); - padding-right: var(--padding); -} -.c-table__panel.disabled { - pointer-events: none; - opacity: 0.3; - filter: grayscale(100%); -} -.c-table__panel_bottom { - display: flex; - align-items: center; - justify-content: flex-end; - height: 48px; - padding-left: var(--padding); - padding-right: var(--padding); - border-top: 1px solid #e0e0e0; -} -.c-table__panel-actions { - margin-left: -8px; - display: flex; - align-items: center; -} -.c-table__panel-button { - margin: 0 12px 0 0; -} -.c-table_buttons .c-table__panel-button:last-child { - margin: 0; -} -.c-table__panel-button_active.c-button { - color: var(--theme_accent); - caret-color: var(--theme_accent); -} -.c-table__panel-button_active.c-button:before { - background-color: currentColor; -} -.c-table_dragging { - user-select: none; -} -.table-relative { - position: relative; -} -.semi-transparent-overlay tbody { - opacity: 0.5; - pointer-events: none; -} -.progress-spinner { - position: absolute; - left: 0; - right: 0; - bottom: 0; - top: 0; - z-index: 2; - margin: auto; - width: 32px !important; - height: 32px; - padding: 6px; - background-color: #fff; - border-radius: 50%; - box-shadow: 0 0 15px 1px #888; -} -.splitpane { - position: absolute; - top: 0; - right: 0; - bottom: 0; - width: 8px !important; - padding-top: 4px; - padding-bottom: 4px; - cursor: col-resize; -} -.splitpane:after { - content: ""; - display: block; - width: 1px; - height: 100%; - margin-left: auto; - margin-right: auto; - border-radius: 2px; - background-color: #e0e0e0; -} -.splitpane_hovered:after, -.splitpane:hover:after { - width: 4px; - background-color: var(--theme_accent); -} -@-moz-keyframes aniVertical { -0% { - opacity: 1; -} -50% { - opacity: 0.6; -} -100% { - opacity: 1; -} -} -@-webkit-keyframes aniVertical { -0% { - opacity: 1; -} -50% { - opacity: 0.6; -} -100% { - opacity: 1; -} -} -@-o-keyframes aniVertical { -0% { - opacity: 1; -} -50% { - opacity: 0.6; -} -100% { - opacity: 1; -} -} -@keyframes aniVertical { -0% { - opacity: 1; -} -50% { - opacity: 0.6; -} -100% { - opacity: 1; -} -} - -/*!*******************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ - !*** css ./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js!./node_modules/stylus-loader/dist/cjs.js!./node_modules/vue-loader/lib/index.js??vue-loader-options!./ui/src/components/cDataTable.vue?vue&type=style&index=0&id=673514a2&lang=stylus&scoped=true& ***! - \*******************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ -.c-data-table .progress-spinner[data-v-673514a2] { - position: absolute; - left: 0; - right: 0; - bottom: 0; - top: 0; - z-index: 2; - margin: auto; - width: 32px !important; - height: 32px; - padding: 6px; - background-color: #fff; - border-radius: 50%; - box-shadow: 0 0 15px 1px #888; -} -.c-data-table[data-v-673514a2] .v-snack__content { - padding: 16px; -} -.c-data-table[data-v-673514a2] .v-snack__content button { - margin-left: 12px; -} - -/*!****************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ - !*** css ./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js!./node_modules/stylus-loader/dist/cjs.js!./node_modules/vue-loader/lib/index.js??vue-loader-options!./ui/src/components/cStatus.vue?vue&type=style&index=0&id=5eb1f184&lang=stylus& ***! - \****************************************************************************************************************************************************************************************************************************************************************************************************************************************/ -.status-mark { - display: inline-flex; - align-items: center; - vertical-align: middle; -} -.status-mark__icon { - margin-right: 4px; - flex: 0 0 auto; -} -.status-mark__text { - color: #212121; - font-size: 14px; - line-height: 20px; - white-space: nowrap; -} - -/*!*************************************************************************************************************************************************************!*\ - !*** css ./node_modules/css-loader/dist/cjs.js!./node_modules/postcss-loader/dist/cjs.js!./node_modules/stylus-loader/dist/cjs.js!./ui/src/styles/app.styl ***! - \*************************************************************************************************************************************************************/ -html, -body { - font: 14px/1.2 Roboto, "Helvetica Neue", sans-serif; - color: #212121; -} -*[tabindex]:focus, -button:focus { - outline: none; -} -.v-text-field input, -.v-text-field__suffix, -.v-text-field__prefix, -.v-textarea textarea, -.v-input label, -.v-select .v-select__selection--comma, -.v-list__tile { - font-size: 14px; -} -.v-text-field .v-label--active, -.input-group--text-field:not(.input-group--single-line).input-group--placeholder:not(.input-group--textarea) label, -.input-group--text-field.input-group--dirty.input-group--select label, -.v-input.input-group--dirty:not(.input-group--textarea) label { - transform: translate(0, -22px) scale(0.92); -} -h1, -h2, -h3, -h4, -h5, -h6 { - margin: 0.625rem 0; - font-weight: 400; -} -h1, -.h1 { - font-size: 32px; -} -h2, -.h2 { - font-size: 24px; - margin: 0 0 1.5625rem; -} -h3, -.h3 { - font-size: 20px; - margin: 0 0 0.9375rem; -} -p { - margin: 0 0 1.25rem; -} -b, -strong { - font-weight: 500; -} -ol { - padding: 10px 20px; -} -.monospace { - font-family: 'Roboto Mono', monospace; -} -font::first-letter { - text-transform: capitalize; -} -i font::first-letter { - text-transform: none; -} -.disabled-dotted-border, -.v-input--is-readonly .v-input__control .v-input__slot:before, -.md-output_readonly:after { - background-color: transparent !important; - background-image: linear-gradient(to right, rgba(0,0,0,0.37) 0, rgba(0,0,0,0.37) 33%, transparent 0); - background-position: bottom; - background-size: 3px 1px; - background-repeat: repeat-x; -} -.v-list__tile__action .v-input--selection-controls .v-input__slot { - margin: 0; -} -.container { - padding: 16px; -} -.v-select__selections { - font-size: 14px; - overflow: hidden; -} -.v-select__selections .selection { - flex: 1 1 100%; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} -.v-text-field__details { - min-height: 22px; -} -.v-select > .v-input__control > .v-input__slot { - cursor: pointer; -} -.v-input--is-readonly label { - transform: translate(0, -22px) scale(0.92); -} -.v-input--is-readonly.v-input--is-focused label { - color: rgba(0,0,0,0.57) !important; -} -.v-input--is-readonly input:focus { - caret-color: transparent !important; -} -.v-input--is-readonly .v-input__control .v-input__slot:after { - content: none; -} -.v-input--is-readonly .v-input__control .v-input__slot:before { - border-color: transparent !important; -} -.v-input--checkbox label, -.v-radio label { - color: #212121 !important; - user-select: auto !important; -} -.v-input--is-disabled.v-input--checkbox label, -.v-input--is-disabled .v-radio label, -.v-radio--is-disabled.v-radio label { - color: #bdbdbd !important; - user-select: auto !important; -} -.theme--light.v-input--selection-controls.v-input--is-disabled.v-input--is-label-active.v-input--checkbox .v-icon, -.v-radio.v-radio--is-disabled.theme--light.accent--text .v-icon { - color: rgba(var(--theme_accent_rgb),0.26) !important; -} -.v-tabs__item--active { - color: var(--theme_accent); -} -.v-btn--small { - min-width: auto; -} -.theme--light.v-list .v-list__tile__mask { - color: var(--theme_accent); - background: rgba(var(--theme_accent_rgb),0.1); -} -.v-dialog__content { - min-width: 1200px; -} -.v-list--disabled, -.v-list__tile--disabled { - pointer-events: none !important; -} -.theme--light .v-text-field__prefix { - color: rgba(0,0,0,0.87); -} -.v-input.primary--text, -.v-input .v-label.primary--text, -.v-input .v-input__icon .primary--text { - color: var(--theme_accent) !important; - caret-color: currentColor !important; -} -.hint { - font-size: 12px; - color: rgba(0,0,0,0.57); - padding: 5px 0; - float: left; - max-width: 99%; -} -.hint_error { - color: #d21a44; -} -.hint_right { - float: right; - color: #2196f3; - cursor: pointer; -} -.dialog-form { - width: 100%; -} -.layout-flex { - display: flex; - flex-direction: column; - flex: 1; - min-height: 0; -} -html, -body { - overflow-y: auto; - overflow-x: auto; - margin: 0; -} -body { - min-width: 1200px; - display: flex; - flex-direction: column; -} -.theme--light.application { - background-color: #fff; -} -.application, -.application--wrap, -.base-layout, -.proxy-layout { - height: 100vh; -} -.application { - min-width: 1280px; -} -.base-layout, -.proxy-layout { - display: flex; - flex-direction: column; -} -.base-layout, -.application, -.proxy-layout { - flex: 1 1 100%; -} -.card { - background-color: #fff; - border-color: #fff; - color: rgba(0,0,0,0.87); - display: block; - border-radius: 2px; - position: relative; - transition: 0.3s cubic-bezier(0.25, 0.8, 0.5, 1); - text-decoration: none; - 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); -} -.card_hoverable:hover { - cursor: pointer; - box-shadow: 0px 5px 5px -3px rgba(0,0,0,0.2), 0px 8px 10px 1px rgba(0,0,0,0.14), 0px 3px 14px 2px rgba(0,0,0,0.12); -} -.base-layout-width { - min-width: 1200px; - max-width: 1200px; -} -.form-control { - margin: 18px 0; -} -.assistive-text, -.detail-item__subhead, -.detail-item__assistive-text { - line-height: 16px; - color: #707070; - font-size: 12px; -} -.detail-item { - min-width: 0; - margin-top: 24px; -} -.detail-item:first-child { - margin-top: 0; -} -.detail-item__head { - display: flex; - align-items: center; - margin-bottom: 8px; - line-height: 16px; - font-weight: 500; - font-size: 14px; -} -.detail-item__subhead { - font-weight: normal; - margin-left: 16px; -} -.detail-item__content-holder { - display: flex; - align-items: center; -} -.detail-item__image { - flex: 0 0 auto; - margin-right: 8px; -} -.detail-item__image_right { - order: 2; - margin-left: 8px; - margin-right: 0; -} -.detail-item__content { - flex-grow: 1; - flex-shrink: 1; - min-width: 0; -} -.detail-item__text { - line-height: 20px; - font-size: 14px; - word-wrap: break-word; - word-break: break-word; -} -.detail-item__text .v-btn--icon.v-btn--small { - margin-top: -4px; - margin-bottom: -4px; - vertical-align: bottom; -} -.detail-group { - margin-top: 24px; -} -.detail-group:first-child { - margin-top: 0; -} -.detail-group__content { - display: inline-flex; - align-items: flex-start; - vertical-align: top; -} -.detail-group_separated { - margin-top: 32px; -} -.detail-group_separated .detail-group__content { - border-top: 1px solid rgba(0,0,0,0.12); - padding-top: 24px; -} -.detail-group .detail-item { - margin-right: 32px; - margin-top: 0; -} -.link-with-icon { - display: inline-flex; - align-items: center; - text-decoration: none; -} -.link-with-icon span { - text-decoration: underline; -} -.link-with-icon .icon { - text-decoration: none; -} -.link-with-icon:hover span { - text-decoration: none; -} -.documents-list__item + .documents-list__item { - margin-top: 48px; - padding-top: 24px; - border-top: 1px dashed rgba(0,0,0,0.12); -} -.document-info__caption { - margin-bottom: 8px; - line-height: 1; - letter-spacing: 0.25px; - font-size: 12px; - font-weight: 500; -} -.document-info__title { - display: inline; - margin-bottom: 0; - margin-top: 0; - margin-right: 8px; - font-size: 18px; - line-height: 24px; - color: #212121; - font-weight: 500; - vertical-align: middle; -} -.document-info__title a { - color: var(--theme_accent); - transition: color 0.3s cubic-bezier(0.25, 0.8, 0.5, 1); -} -.document-info__title a:hover { - text-decoration: none; -} -.document-info__subtitle { - color: #707070; -} -.document-info__title-holder .inline-mark { - vertical-align: middle; -} -.document-info__toolbar { - display: flex; - align-items: center; - height: 36px; - margin-top: 2px; -} -.document-info__description { - margin-top: 24px; - max-width: 800px; -} -.document-info__description_wide { - max-width: 1000px; -} -.document-info__actions-holder { - margin-top: 24px; -} -.details-view__section + .details-view__section { - margin-top: 48px; -} -.details-view__section-head { - display: flex; - align-items: flex-start; -} -.details-view__section-head button { - height: 24px; -} -.details-view__section-title { - line-height: 24px; - font-size: 18px; - font-weight: 500; - margin-top: 0; - margin-bottom: 24px; -} -.details-view__section-subtitle { - margin-top: 4px; - margin-bottom: 24px; - line-height: 20px; - font-size: 14px; - color: #707070; -} -.content-columns-holder { - display: flex; - flex: 1; - min-height: 0; -} -.page-navigation { - display: flex; - align-items: center; - margin-right: 48px; -} -.page-navigation__back-button.v-btn--icon { - margin: 0 26px 0 -6px; - flex: 0 0 auto; -} -.page-navigation__title { - flex: 0 1 auto; - font-size: 20px; - font-weight: 500; - line-height: 1; - margin-top: 0; - margin-bottom: 0; - letter-spacing: 0; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} -.search { - width: 400px; - margin-left: auto; - margin-right: auto; -} -.search_fluid { - width: auto; -} -.markdown-document { - background-color: rgba(33,33,33,0.04); - padding: 32px 24px; - width: 640px; - overflow: hidden; - border-radius: 8px; -} -.object-image { - border-radius: 6.25%; -} -.list { - padding: 8px 0 8px; - display: flex; - flex-direction: column; -} -.list .list-item { - justify-content: left; - align-items: center; - display: flex; - font-size: 16px; - font-weight: 400; - height: 48px; - margin: 0; - padding: 0 16px; - width: 100%; - position: relative; - text-decoration: none; - transition: background 0.3s cubic-bezier(0.25, 0.8, 0.5, 1); -} -.section-headline { - margin: 0 0 1.5625rem; -} -.section-headline__title { - margin: 0 0 5px; -} -.section-headline__hint { - color: rgba(0,0,0,0.57); -} -.empty-data { - text-align: center; - margin: 40px 0; -} -.empty-data__media.icon { - color: rgba(0,0,0,0.37); -} -.empty-data__text { - text-transform: uppercase; - font-weight: 500; - color: rgba(0,0,0,0.57); -} -.empty-state { - padding: 16px; - margin: auto; - text-align: center; - color: rgba(0,0,0,0.57); -} -.empty-state__title { - margin-bottom: 30px; -} -.empty-state__text { - line-height: 1.388; - font-size: 18px; -} -.empty-state__icon { - margin: 0 0 30px; - font-size: 96px; - width: 96px; - height: 96px; - min-width: 96px; - min-height: 96px; -} -.v-text-field .v-input__append-inner { - margin-top: 9px; -} -._required::after, -._field_required label::after { - content: '*'; - margin-left: 3px; - color: #f00; - text-decoration: none; - display: inline-block; -} -.info-mode label { - color: rgba(0,0,0,0.57) !important; -} -.info-mode input { - color: rgba(0,0,0,0.87) !important; -} -.info-mode .input-group__details { - opacity: 0 !important; -} -.info-mode .v-input__slot:before { - display: none; -} -.md-output_readonly { - position: relative; - padding-bottom: 31px; - padding-top: 5px; - line-height: 20px; - min-height: 56px; -} -.md-output_readonly:after { - content: ''; - position: absolute; - bottom: 25px; - left: 0; - right: 0; - height: 1px; -} -.md-output_readonly p:last-child, -.md-output_readonly ol:last-child, -.md-output_readonly ul:last-child, -.md-output_readonly blockquote:last-child { - margin-bottom: 0; -} -.collapse_details .input-group__details { - display: none; -} -.button_ignore-left-frame { - margin-left: -16px; -} -.button_ignore-right-frame { - margin-right: -16px; -} -.button_margin_none { - margin: 0px; -} -.v-select_single-line .v-select__selections { - color: #000 !important; - font-size: 14px; -} -.v-input__box .v-input__slot { - background: #f5f5f5; - height: 44px; - padding: 12px; - border-radius: 6px; -} -.v-input__box .v-input__append-inner { - margin-top: 4px; -} -.font-size_h1 { - font-size: 24px; -} -.font-size_h2 { - font-size: 20px; -} -.font-size_normal { - font-size: 16px; -} -.font-size_smaller { - font-size: 14px; -} -.font-size_small { - font-size: 12px; -} -.font-weight_medium { - font-weight: 500; -} -._ma_0 { - margin: 0px; -} -._mt_0 { - margin-top: 0px; -} -._mr_0 { - margin-right: 0px; -} -._mb_0 { - margin-bottom: 0px; -} -._ml_0 { - margin-left: 0px; -} -._mx_0 { - margin-right: 0px; - margin-left: 0px; -} -._my_0 { - margin-top: 0px; - margin-bottom: 0px; -} -._pa_0 { - padding: 0px; -} -._pt_0 { - padding-top: 0px; -} -._pr_0 { - padding-right: 0px; -} -._pb_0 { - padding-bottom: 0px; -} -._pl_0 { - padding-left: 0px; -} -._px_0 { - padding-right: 0px; - padding-left: 0px; -} -._py_0 { - padding-top: 0px; - padding-bottom: 0px; -} -._ma_4 { - margin: 4px; -} -._mt_4 { - margin-top: 4px; -} -._mr_4 { - margin-right: 4px; -} -._mb_4 { - margin-bottom: 4px; -} -._ml_4 { - margin-left: 4px; -} -._mx_4 { - margin-right: 4px; - margin-left: 4px; -} -._my_4 { - margin-top: 4px; - margin-bottom: 4px; -} -._pa_4 { - padding: 4px; -} -._pt_4 { - padding-top: 4px; -} -._pr_4 { - padding-right: 4px; -} -._pb_4 { - padding-bottom: 4px; -} -._pl_4 { - padding-left: 4px; -} -._px_4 { - padding-right: 4px; - padding-left: 4px; -} -._py_4 { - padding-top: 4px; - padding-bottom: 4px; -} -._ma_8 { - margin: 8px; -} -._mt_8 { - margin-top: 8px; -} -._mr_8 { - margin-right: 8px; -} -._mb_8 { - margin-bottom: 8px; -} -._ml_8 { - margin-left: 8px; -} -._mx_8 { - margin-right: 8px; - margin-left: 8px; -} -._my_8 { - margin-top: 8px; - margin-bottom: 8px; -} -._pa_8 { - padding: 8px; -} -._pt_8 { - padding-top: 8px; -} -._pr_8 { - padding-right: 8px; -} -._pb_8 { - padding-bottom: 8px; -} -._pl_8 { - padding-left: 8px; -} -._px_8 { - padding-right: 8px; - padding-left: 8px; -} -._py_8 { - padding-top: 8px; - padding-bottom: 8px; -} -._ma_12 { - margin: 12px; -} -._mt_12 { - margin-top: 12px; -} -._mr_12 { - margin-right: 12px; -} -._mb_12 { - margin-bottom: 12px; -} -._ml_12 { - margin-left: 12px; -} -._mx_12 { - margin-right: 12px; - margin-left: 12px; -} -._my_12 { - margin-top: 12px; - margin-bottom: 12px; -} -._pa_12 { - padding: 12px; -} -._pt_12 { - padding-top: 12px; -} -._pr_12 { - padding-right: 12px; -} -._pb_12 { - padding-bottom: 12px; -} -._pl_12 { - padding-left: 12px; -} -._px_12 { - padding-right: 12px; - padding-left: 12px; -} -._py_12 { - padding-top: 12px; - padding-bottom: 12px; -} -._ma_16 { - margin: 16px; -} -._mt_16 { - margin-top: 16px; -} -._mr_16 { - margin-right: 16px; -} -._mb_16 { - margin-bottom: 16px; -} -._ml_16 { - margin-left: 16px; -} -._mx_16 { - margin-right: 16px; - margin-left: 16px; -} -._my_16 { - margin-top: 16px; - margin-bottom: 16px; -} -._pa_16 { - padding: 16px; -} -._pt_16 { - padding-top: 16px; -} -._pr_16 { - padding-right: 16px; -} -._pb_16 { - padding-bottom: 16px; -} -._pl_16 { - padding-left: 16px; -} -._px_16 { - padding-right: 16px; - padding-left: 16px; -} -._py_16 { - padding-top: 16px; - padding-bottom: 16px; -} -._ma_20 { - margin: 20px; -} -._mt_20 { - margin-top: 20px; -} -._mr_20 { - margin-right: 20px; -} -._mb_20 { - margin-bottom: 20px; -} -._ml_20 { - margin-left: 20px; -} -._mx_20 { - margin-right: 20px; - margin-left: 20px; -} -._my_20 { - margin-top: 20px; - margin-bottom: 20px; -} -._pa_20 { - padding: 20px; -} -._pt_20 { - padding-top: 20px; -} -._pr_20 { - padding-right: 20px; -} -._pb_20 { - padding-bottom: 20px; -} -._pl_20 { - padding-left: 20px; -} -._px_20 { - padding-right: 20px; - padding-left: 20px; -} -._py_20 { - padding-top: 20px; - padding-bottom: 20px; -} -._ma_24 { - margin: 24px; -} -._mt_24 { - margin-top: 24px; -} -._mr_24 { - margin-right: 24px; -} -._mb_24 { - margin-bottom: 24px; -} -._ml_24 { - margin-left: 24px; -} -._mx_24 { - margin-right: 24px; - margin-left: 24px; -} -._my_24 { - margin-top: 24px; - margin-bottom: 24px; -} -._pa_24 { - padding: 24px; -} -._pt_24 { - padding-top: 24px; -} -._pr_24 { - padding-right: 24px; -} -._pb_24 { - padding-bottom: 24px; -} -._pl_24 { - padding-left: 24px; -} -._px_24 { - padding-right: 24px; - padding-left: 24px; -} -._py_24 { - padding-top: 24px; - padding-bottom: 24px; -} -._ma_28 { - margin: 28px; -} -._mt_28 { - margin-top: 28px; -} -._mr_28 { - margin-right: 28px; -} -._mb_28 { - margin-bottom: 28px; -} -._ml_28 { - margin-left: 28px; -} -._mx_28 { - margin-right: 28px; - margin-left: 28px; -} -._my_28 { - margin-top: 28px; - margin-bottom: 28px; -} -._pa_28 { - padding: 28px; -} -._pt_28 { - padding-top: 28px; -} -._pr_28 { - padding-right: 28px; -} -._pb_28 { - padding-bottom: 28px; -} -._pl_28 { - padding-left: 28px; -} -._px_28 { - padding-right: 28px; - padding-left: 28px; -} -._py_28 { - padding-top: 28px; - padding-bottom: 28px; -} -._ma_32 { - margin: 32px; -} -._mt_32 { - margin-top: 32px; -} -._mr_32 { - margin-right: 32px; -} -._mb_32 { - margin-bottom: 32px; -} -._ml_32 { - margin-left: 32px; -} -._mx_32 { - margin-right: 32px; - margin-left: 32px; -} -._my_32 { - margin-top: 32px; - margin-bottom: 32px; -} -._pa_32 { - padding: 32px; -} -._pt_32 { - padding-top: 32px; -} -._pr_32 { - padding-right: 32px; -} -._pb_32 { - padding-bottom: 32px; -} -._pl_32 { - padding-left: 32px; -} -._px_32 { - padding-right: 32px; - padding-left: 32px; -} -._py_32 { - padding-top: 32px; - padding-bottom: 32px; -} -._ma_36 { - margin: 36px; -} -._mt_36 { - margin-top: 36px; -} -._mr_36 { - margin-right: 36px; -} -._mb_36 { - margin-bottom: 36px; -} -._ml_36 { - margin-left: 36px; -} -._mx_36 { - margin-right: 36px; - margin-left: 36px; -} -._my_36 { - margin-top: 36px; - margin-bottom: 36px; -} -._pa_36 { - padding: 36px; -} -._pt_36 { - padding-top: 36px; -} -._pr_36 { - padding-right: 36px; -} -._pb_36 { - padding-bottom: 36px; -} -._pl_36 { - padding-left: 36px; -} -._px_36 { - padding-right: 36px; - padding-left: 36px; -} -._py_36 { - padding-top: 36px; - padding-bottom: 36px; -} -._ma_40 { - margin: 40px; -} -._mt_40 { - margin-top: 40px; -} -._mr_40 { - margin-right: 40px; -} -._mb_40 { - margin-bottom: 40px; -} -._ml_40 { - margin-left: 40px; -} -._mx_40 { - margin-right: 40px; - margin-left: 40px; -} -._my_40 { - margin-top: 40px; - margin-bottom: 40px; -} -._pa_40 { - padding: 40px; -} -._pt_40 { - padding-top: 40px; -} -._pr_40 { - padding-right: 40px; -} -._pb_40 { - padding-bottom: 40px; -} -._pl_40 { - padding-left: 40px; -} -._px_40 { - padding-right: 40px; - padding-left: 40px; -} -._py_40 { - padding-top: 40px; - padding-bottom: 40px; -} -._ma_44 { - margin: 44px; -} -._mt_44 { - margin-top: 44px; -} -._mr_44 { - margin-right: 44px; -} -._mb_44 { - margin-bottom: 44px; -} -._ml_44 { - margin-left: 44px; -} -._mx_44 { - margin-right: 44px; - margin-left: 44px; -} -._my_44 { - margin-top: 44px; - margin-bottom: 44px; -} -._pa_44 { - padding: 44px; -} -._pt_44 { - padding-top: 44px; -} -._pr_44 { - padding-right: 44px; -} -._pb_44 { - padding-bottom: 44px; -} -._pl_44 { - padding-left: 44px; -} -._px_44 { - padding-right: 44px; - padding-left: 44px; -} -._py_44 { - padding-top: 44px; - padding-bottom: 44px; -} -._ma_48 { - margin: 48px; -} -._mt_48 { - margin-top: 48px; -} -._mr_48 { - margin-right: 48px; -} -._mb_48 { - margin-bottom: 48px; -} -._ml_48 { - margin-left: 48px; -} -._mx_48 { - margin-right: 48px; - margin-left: 48px; -} -._my_48 { - margin-top: 48px; - margin-bottom: 48px; -} -._pa_48 { - padding: 48px; -} -._pt_48 { - padding-top: 48px; -} -._pr_48 { - padding-right: 48px; -} -._pb_48 { - padding-bottom: 48px; -} -._pl_48 { - padding-left: 48px; -} -._px_48 { - padding-right: 48px; - padding-left: 48px; -} -._py_48 { - padding-top: 48px; - padding-bottom: 48px; -} -._ma_52 { - margin: 52px; -} -._mt_52 { - margin-top: 52px; -} -._mr_52 { - margin-right: 52px; -} -._mb_52 { - margin-bottom: 52px; -} -._ml_52 { - margin-left: 52px; -} -._mx_52 { - margin-right: 52px; - margin-left: 52px; -} -._my_52 { - margin-top: 52px; - margin-bottom: 52px; -} -._pa_52 { - padding: 52px; -} -._pt_52 { - padding-top: 52px; -} -._pr_52 { - padding-right: 52px; -} -._pb_52 { - padding-bottom: 52px; -} -._pl_52 { - padding-left: 52px; -} -._px_52 { - padding-right: 52px; - padding-left: 52px; -} -._py_52 { - padding-top: 52px; - padding-bottom: 52px; -} -._ma_56 { - margin: 56px; -} -._mt_56 { - margin-top: 56px; -} -._mr_56 { - margin-right: 56px; -} -._mb_56 { - margin-bottom: 56px; -} -._ml_56 { - margin-left: 56px; -} -._mx_56 { - margin-right: 56px; - margin-left: 56px; -} -._my_56 { - margin-top: 56px; - margin-bottom: 56px; -} -._pa_56 { - padding: 56px; -} -._pt_56 { - padding-top: 56px; -} -._pr_56 { - padding-right: 56px; -} -._pb_56 { - padding-bottom: 56px; -} -._pl_56 { - padding-left: 56px; -} -._px_56 { - padding-right: 56px; - padding-left: 56px; -} -._py_56 { - padding-top: 56px; - padding-bottom: 56px; -} -._ma_60 { - margin: 60px; -} -._mt_60 { - margin-top: 60px; -} -._mr_60 { - margin-right: 60px; -} -._mb_60 { - margin-bottom: 60px; -} -._ml_60 { - margin-left: 60px; -} -._mx_60 { - margin-right: 60px; - margin-left: 60px; -} -._my_60 { - margin-top: 60px; - margin-bottom: 60px; -} -._pa_60 { - padding: 60px; -} -._pt_60 { - padding-top: 60px; -} -._pr_60 { - padding-right: 60px; -} -._pb_60 { - padding-bottom: 60px; -} -._pl_60 { - padding-left: 60px; -} -._px_60 { - padding-right: 60px; - padding-left: 60px; -} -._py_60 { - padding-top: 60px; - padding-bottom: 60px; -} -._ma_64 { - margin: 64px; -} -._mt_64 { - margin-top: 64px; -} -._mr_64 { - margin-right: 64px; -} -._mb_64 { - margin-bottom: 64px; -} -._ml_64 { - margin-left: 64px; -} -._mx_64 { - margin-right: 64px; - margin-left: 64px; -} -._my_64 { - margin-top: 64px; - margin-bottom: 64px; -} -._pa_64 { - padding: 64px; -} -._pt_64 { - padding-top: 64px; -} -._pr_64 { - padding-right: 64px; -} -._pb_64 { - padding-bottom: 64px; -} -._pl_64 { - padding-left: 64px; -} -._px_64 { - padding-right: 64px; - padding-left: 64px; -} -._py_64 { - padding-top: 64px; - padding-bottom: 64px; -} -._ma_auto { - margin: auto; -} -._mt_auto { - margin-top: auto; -} -._mr_auto { - margin-right: auto; -} -._mb_auto { - margin-bottom: auto; -} -._ml_auto { - margin-left: auto; -} -._mx_auto { - margin-right: auto; - margin-left: auto; -} -._my_auto { - margin-top: auto; - margin-bottom: auto; -} -.horizontal-spacer { - flex-grow: 1; -} -.mgt_1 { - margin-top: 64px; -} -.mgt_2 { - margin-top: 24px; -} -.mgt_3 { - margin-top: 16px; -} -.mgb_1 { - margin-bottom: 64px; -} -.mgb_2 { - margin-bottom: 24px; -} -.mgb_3 { - margin-bottom: 16px; -} -.mgr_1 { - margin-right: 64px; -} -.mgr_2 { - margin-right: 24px; -} -.mgr_3 { - margin-right: 16px; -} -.mgl_1 { - margin-left: 64px; -} -.mgl_2 { - margin-left: 24px; -} -.mgl_3 { - margin-left: 16px; -} -.is-disabled { - opacity: 0.5; - pointer-events: none; -} -.is-failed { - color: #d21a44; -} -.is-successfully { - color: #00c853; -} -.is-transparent { - opacity: 0; -} -.is-hidden { - display: none; -} -.is-inactive { - color: #d21a44; -} -.is-active { - color: #00c853; -} -.is-empty { - color: rgba(0,0,0,0.57); -} -.color_light { - color: #424242; -} -.is-invisible { - visibility: hidden; - overflow: hidden; - opacity: 0; - transition: all 0.2s ease-out; -} -.is-visible { - visibility: visible; - overflow: visible; - opacity: 1; -} -.line-height_compact { - line-height: 1; -} -.line-height_small { - line-height: 1.1; -} -.img { - max-width: 100%; - display: block; - height: auto; -} -.drag-handle { - cursor: grab; -} -.pointer { - cursor: pointer; -} -.padding { - padding: 16px; -} -.text-left { - text-align: left; -} -.text-right { - text-align: right; -} -.text-center { - text-align: center; -} -.capitalize { - text-transform: capitalize; -} -.lowercase { - text-transform: lowercase; -} -.uppercase { - text-transform: uppercase; -} -.capitalize-first-letter::first-letter { - text-transform: capitalize; -} -.text-decoration-none { - text-decoration: none; -} -.text-decoration-underline { - text-decoration: underline; -} -.text_nowrap { - white-space: nowrap; -} -.col-centered { - float: none; - display: block; - margin-right: auto; - margin-left: auto; -} -.scroll { - overflow-y: auto; -} -.full-width { - width: 100%; -} -.full-height { - line-height: 100%; - min-height: 100%; - height: 100%; -} -.global-indent { - margin-bottom: 60px; -} -.browser-warning-text { - margin-bottom: 0; -} -.overflow-auto { - overflow: auto; -} -.font-size-normal { - font-size: 1em !important; -} -.container_compact, -.container_compact.fluid { - max-width: 1440px; -} -.min-width_none { - min-width: 0; -} -.inherit-width { - max-width: 100%; -} -.flex-0-0 { - flex: 0 0 auto; -} -.border { - border: 1px solid rgba(0,0,0,0.12); -} -.border-dashed { - border-bottom: 1px dashed rgba(0,0,0,0.12); -} -.border-bottom-0 { - border-bottom-width: 0; -} -.border-bottom-1 { - border-bottom: 1px solid rgba(0,0,0,0.12); -} -.border-top-0 { - border-top-width: 0; -} -.border-top-1 { - border-top: 1px solid rgba(0,0,0,0.12); -} -.assistive-color { - color: #707070; -} -.outlined-picture { - background-color: #f8f8f8; - border: 1px solid #000; -} -.outlined-picture_gray { - border-color: #e5e5e5; -} -.outlined-picture .c-icon, -.picture-placeholder .c-icon { - color: #dedede; -} -.multiline-code { - white-space: pre-wrap; - font-family: 'Roboto Mono', monospace; - font-size: 13px; -} -.truncate-text, -.truncator__truncate { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} -.truncator { - display: flex; - min-width: 0; - align-items: center; -} -.truncator__keep { - flex: 0 0 auto; -} -._clamp-lines, -.clamp-lines-2, -.clamp-lines-3, -.clamp-lines-4 { - display: -webkit-box; - overflow: hidden; - -webkit-box-orient: vertical; -} -.clamp-lines-2 { - -webkit-line-clamp: 2; -} -.clamp-lines-3 { - -webkit-line-clamp: 3; -} -.clamp-lines-4 { - -webkit-line-clamp: 4; -} -._display_inline-block { - display: inline-block; -} -._display_flex { - display: flex; -} -._display_flex-wrap { - display: flex; - flex-wrap: wrap; -} -._display_flex-center { - display: flex; - align-items: center; -} -.placeholder-image { - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZAAAADhCAMAAADRaBMuAAAARVBMVEUAAADh4eHh4eHg4ODf39/f39/g4ODh4eHf39/f39/g4ODf39/g4ODf39/f39/f39/g4ODg4ODh4eHf39/f39/m5ubf39+Jo7sIAAAAF3RSTlMAj3//QCC/n3Aw7xDfgGBQr89fkKAfsCGTTG8AAAQ/SURBVHgB7dvpmqs6DoVhpYQZbOFAJ933f6d9Rs5cJI4ooufU9/7fE9r2WjaU4E0AAAAAAAAAAAAAAAAAAAAAXHgEoXxox0MIJKn2PIVABlUdeQxhTPqjXHgQUZj+ZOZBBFH1F4lHEUIy/UUvMVB5N50gROXdmMRA5d2Mgne76obqG6jybi4SA5V3MwlCVF6l+oZLdKpvqMq7sSJ4m0X/bhYESHSqb7zKuxnkrbjECpfrVN6g1ZfKu6kSApWXXH+nVTdhqy+Vd5OTBEDlDZDrVN5I1ZdEj79EqLybUXCeSTfRqi+JTvUNoOozkpyKSyxyPYqLbqi+ESR9kgleV9LU1Z903VQclZdcdyvdOKxZ/2Rd5uvUmuj+6otyvZh+Ji81tVdePmR8WRn7rA+sl6lhgZDrDl2f9SlrTW2Vl+rbrnyYNhhSa6JvrvIMxpG10ZAaKi8fMrbZxvHCSBZtNcs+dKYv+pCqzXKSHUiLvs5mbTcIPvefrA6zjFk3/uqLMqiHla32HlJ9kUxdqvxk1lZV0LJdtV7ejrrxXGnhQ52S/Goyqm+AeQyykWTe6otBnXJypFEvaJlH+7aTzFN9cVEv8zW2VdCUH+3VNWVtMQra59EUAtOL1Red+iX5u1FbXARtu337BeHtlZnC1M2S/KOV6nt8gHgSOeV3VF8CxOQzY+tvA1O/Kp/qz7/SYsMa5HMpU31bJD1Akh0z1bfFoH432VPs5Fwn0ZPsqmGqL4nemOt8yFjVz45bhnzI2Ktfd/A6nEkQl0EeG897m0vFSvJYydpg4QziMMszbnpO9SXSrRy3N1J9V3Wrx7UH3uamgyuv8/6EK61R3dKBw6f69uo1HHglQPUteuCniv6eRa5f1Ws+8k+j+t7Uyb5yPRoR0qweeq9M9c3qs0iTu+6i+k7qlL64ZF/I9CbDl/95k3wrs7pY+vJ7gZ6S1aCecOzpKFlPszNKhBUG4lggvt7LlZapw3D4/wCqb/ZV3naLY/DfwaGXWP6TIbmuDsN8lisD+TJVwEAYCB/tvqX2ks8MhJP60f4re3DXk8ku3PRcWXZh1HP1sgudnut/sgtFzzXKPlis1otFT1UkElJ9lVBI9UEeQY51tYh7rAhBjXUsRMm8nfq2F75JHkMXrGMhxzqmY9ZzmDQg1uNEOm6xFgiSnmEWRDqtW5IGpEioBMEcK0FQLNYCQRfskI4lVqKjWKwNCx0b1rc5r1uRQHgxkpNEQoxc5TVIOdYdFqYcax6oerS7wKMGmwdq1gPdBF6TxcoPJIv10zlIvR4hdxII76vWJDjM1WLFOdJdPawTHKyao10ViYMk6ZMgzr7VdxIEI2EcJ0ij6bPywjjOcL3rM/qxCM5R6j0/mkYSnKobF9N/kvvbtcg7oHTjbenN9CfZ1mUYr6yMfy0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAfAFTgo7mGhZ5cAAAAAElFTkSuQmCC); -} -.horizontal-list > :not(:last-child)::after { - content: '\2022'; - margin: 0 7px; - display: inline-block; - color: #707070; -} -.divider { - display: block; - flex: 1 1 0px; - max-width: 100%; - height: 0px; - max-height: 0px; - border: solid; - border-width: thin 0 0 0; - border-color: #e0e0e0; - transition: inherit; -} -.divider_vertical { - align-self: stretch; - border: solid; - border-width: 0 thin 0 0; - border-color: #e0e0e0; - display: inline-flex; - height: inherit; - min-height: 100%; - max-height: 100%; - max-width: 0px; - width: 0px; - vertical-align: text-bottom; -} -.nowrap-cell { - white-space: nowrap; -} -#updateBrowserWarning { - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - z-index: 3; - display: none; - vertical-align: middle; - text-align: center; - white-space: nowrap; - background-color: #fff; -} -#updateBrowserWarning:after { - content: ""; - display: inline-block; - height: 100%; - vertical-align: middle; -} -#updateBrowserWarning .message { - display: inline-block; - vertical-align: middle; - color: #212121; -} -#updateBrowserWarning .message .message__title { - margin-bottom: 24px; - font-size: 24px; - font-weight: 500; - line-height: 1; -} -#updateBrowserWarning .message p { - line-height: 20px; - margin: 0; -} -#updateBrowserWarning .message .message__icon { - display: inline-block; - width: 56px; - height: 56px; - margin-bottom: 48px; - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADgAAAA4CAMAAACfWMssAAAApVBMVEUAAADvx0zyyUzyykzyyEz0ylXvx1Dvx0jxyUvvz0Dvz1Dvx0ryyU3xx0zyykzyyU3yyUz0yUvvykrxyEvyx0ryyEzzykzvxUrxyUvxzE7vx0zvyUnxyUzyyUzvyUzwyEvyyEzxyUvzyEzvylDzyUzyyUv1yErxxkvyykvyyUzyyUzzy0zxyUvyyk3yyEzyyUzxx0vyyE3xyEzxyEvyyE3xyEzyyUwjqgGbAAAANnRSTlMAQP6/vwEgIN4QEGDfgL7er18wcGC+bzDfX0FQz+9Qr+5fbzDP309wn7+uf8+e7+6gru7fr29GUEDAAAABL0lEQVR4XuXU13LCMBCF4SOZSK4YSAiEFlJ7L/v+jxYuktmMbK+1lxm++3+OPJaNfZY7szPJddH5aE4/ytHYIY5JKJCMY7KSWtTXkOUJdbh1ujlWC+UxSbZLdHggmT2R9vSloX4vEzS4kiLUGUKvFOUegSMKrYwxi0sKWBOEJYUGAA4SCg3lQQ57JhMhlCYdxYc2AzvShIdgI0VIp2DPmrDmLichlB7yQhc6/DK60PzH0FOLdbKzbgsnwutg8p27IoVUuHKiU7AbRWfPwLzm6/BguIsPp/iriAr5pGweG6ZAz+SjMWax6hpkQ4ryhJDfUoTUo2FD/ewMLSoS8Q9OX1boUFndHtuk1Ck1EPhh1+jUQ1akVjnH6dQG7WCJOL54e/+NPz6/HDSymdlxGfbYN5W5RuTbEk06AAAAAElFTkSuQmCC); -} -#updateBrowserWarning .message .message__suggested-browsers { - margin-top: 40px; - color: #707070; -} -.recaptcha-position { - left: calc(100vw / 4 * 3 - 200px) !important; - top: -80px !important; - margin: auto 0 !important; -} -.recaptcha-position-parent { - left: 0 !important; -} -.grecaptcha-badge { - box-shadow: none !important; - border-radius: none !important; -} -.detail-item a { - text-decoration: none; -} -.detail-item a:hover { - text-decoration: underline; -} -a { - color: var(--theme_accent); - cursor: pointer; -} -.overflow-container { - position: absolute; - top: 0; - right: 0; - left: 0; - bottom: 0; - pointer-events: none; -} -.overflowing .overflow-container:before, -.overflowing .overflow-container:after { - content: ""; - position: absolute; - top: 0; - width: 96px; - height: 100%; - opacity: 0; - transition: opacity 0.2s ease; - z-index: 1; - pointer-events: none; -} -.overflowing .overflow-container:after { - right: 0; - background: linear-gradient(90deg, transparent, rgba(255,255,255,0.66) 50%, #fff 90%, #fff); -} -.overflowing .overflow-container:before { - left: 0; - background: linear-gradient(270deg, transparent, rgba(255,255,255,0.66) 50%, #fff 90%, #fff); -} -.overflowing_right .overflow-container:after, -.overflowing_both .overflow-container:after { - opacity: 1; -} -.overflowing_left .overflow-container:before, -.overflowing_both .overflow-container:before { - opacity: 1; -} -.highlighted { - background: #f2c94c; -} -input[type=text][materialize] { - appearance: none; - -webkit-appearance: none; - -moz-appearance: none; - width: 100%; - padding: 12px; - background: rgba(0,0,0,0.01); - border: 1px solid rgba(0,0,0,0.12); - border-radius: 2px; - color: #212121; - font-family: Roboto, "Helvetica Neue", sans-serif; - font-size: 14; - font-style: normal; - font-weight: 400; - line-height: 1.2em; -} -input[type=text][materialize]:focus-visible { - outline-width: 0; - border-color: var(--theme_accent); -} -input[type=text][materialize]:disabled { - border-style: dashed; -} -input[type=password][materialize] { - appearance: none; - -webkit-appearance: none; - -moz-appearance: none; - width: 100%; - padding: 12px; - background: rgba(0,0,0,0.01); - border: 1px solid rgba(0,0,0,0.12); - border-radius: 2px; - color: #212121; - font-family: Roboto, "Helvetica Neue", sans-serif; - font-size: 14; - font-style: normal; - font-weight: 400; - line-height: 1.2em; -} -input[type=password][materialize]:focus-visible { - outline-width: 0; - border-color: var(--theme_accent); -} -input[type=password][materialize]:disabled { - border-style: dashed; -} -textarea[materialize] { - appearance: none; - -webkit-appearance: none; - -moz-appearance: none; - width: 100%; - padding: 12px; - background: rgba(0,0,0,0.01); - border: 1px solid rgba(0,0,0,0.12); - border-radius: 2px; - color: #212121; - font-family: Roboto, "Helvetica Neue", sans-serif; - font-size: 14; - font-style: normal; - font-weight: 400; - line-height: 1.2em; -} -textarea[materialize]:focus-visible { - outline-width: 0; - border-color: var(--theme_accent); -} -textarea[materialize]:disabled { - border-style: dashed; -} -input[type=radio][materialize] { - appearance: none; - -webkit-appearance: none; - -moz-appearance: none; - margin: 0; - background: rgba(0,0,0,0.01); - width: 24px; - height: 24px; - border: 3px solid #666; - border-radius: 50%; - cursor: pointer; -} -input[type=radio][materialize]:checked { - background: radial-gradient(circle, var(--theme_accent) 45%, rgba(255,255,255,0) 45%); - border-color: var(--theme_accent); -} -input[type=radio][materialize]:focus-visible { - outline-width: 0; - border-color: var(--theme_accent); -} -input[type=checkbox][materialize] { - appearance: none; - -webkit-appearance: none; - -moz-appearance: none; - margin: 3px; - background: rgba(0,0,0,0.01); - width: 18px; - height: 18px; - border: 3px solid #666; - border-radius: 2px; - cursor: pointer; -} -input[type=checkbox][materialize]:checked { - border-color: var(--theme_accent); - background-color: var(--theme_accent); - position: relative; -} -input[type=checkbox][materialize]:checked:after { - content: url("data:image/svg+xml;utf8,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20width=%2212%22%20height=%2212%22%20viewBox=%220%200%2024%2024%22%3E%3Cpath%20d=%22M0%200h24v24H0z%22%20fill=%22none%22/%3E%3Cpath%20fill=%22white%22%20d=%22M9%2022l-10-10.598%202.798-2.859%207.149%207.473%2013.144-14.016%202.909%202.806z%22/%3E%3C/svg%3E"); - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; -} -input[type=checkbox][materialize]:focus-visible { - outline-width: 0; - border-color: var(--theme_accent); -} -label[materialize] { - color: #212121; - font-family: Roboto, "Helvetica Neue", sans-serif; - font-size: 14; - font-style: normal; - font-weight: 400; - line-height: 1.2em; -} -label[materialize][for] { - cursor: pointer; -} -select[materialize] { - appearance: none; - -webkit-appearance: none; - -moz-appearance: none; - width: 100%; - padding: 12px; - background: rgba(0,0,0,0.01); - border: 1px solid rgba(0,0,0,0.12); - border-radius: 2px; - background-image: url("data:image/svg+xml;utf8,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20width=%2224%22%20height=%2224%22%20viewBox=%220%200%2024%2024%22%3E%3Cpath%20d=%22M0%200h24v24H0z%22%20fill=%22none%22/%3E%3Cpath%20fill=%22rgba%280,0,0,0.57%29%22%20d=%22M7%2010l5%205%205-5z,%20M9%2022l-10-10.598%202.798-2.859%207.149%207.473%2013.144-14.016%202.909%202.806z%22/%3E%3C/svg%3E"); - background-repeat: no-repeat; - background-position: 100% center; - color: #212121; - font-family: Roboto, "Helvetica Neue", sans-serif; - font-size: 14; - font-style: normal; - font-weight: 400; - line-height: 1.2em; -} -select[materialize]::-ms-expand { - display: none; -} -select[materialize]:focus-visible { - outline-width: 0; - border-color: var(--theme_accent); -} -select[materialize]:disabled { - border-style: dashed; -} - -/*!***********************************************************************!*\ - !*** css ./node_modules/css-loader/dist/cjs.js!./ui/styles/index.css ***! - \***********************************************************************/ -/* -Copyright (c) 2023, Ingram Micro -All rights reserved. -*/ -:root { - --theme_primary: #1565c0; - --theme_primary_rgb: 21,101,192; - --theme_accent: #4797f2; - --theme_accent_rgb: 71,151,242; - --theme_contrast: #ffffff; - --theme_contrast_rgb: 255,255,255; -} - -body { - font-family: "Roboto", sans-serif; -} - diff --git a/connect_ext_ppr/static/settings.228c534170f31239141d.css b/connect_ext_ppr/static/settings.228c534170f31239141d.css deleted file mode 100644 index 50b16fe..0000000 --- a/connect_ext_ppr/static/settings.228c534170f31239141d.css +++ /dev/null @@ -1,1972 +0,0 @@ -/*!*************************************************************************************************************************************************************!*\ - !*** css ./node_modules/css-loader/dist/cjs.js!./node_modules/postcss-loader/dist/cjs.js!./node_modules/stylus-loader/dist/cjs.js!./ui/src/styles/app.styl ***! - \*************************************************************************************************************************************************************/ -html, -body { - font: 14px/1.2 Roboto, "Helvetica Neue", sans-serif; - color: #212121; -} -*[tabindex]:focus, -button:focus { - outline: none; -} -.v-text-field input, -.v-text-field__suffix, -.v-text-field__prefix, -.v-textarea textarea, -.v-input label, -.v-select .v-select__selection--comma, -.v-list__tile { - font-size: 14px; -} -.v-text-field .v-label--active, -.input-group--text-field:not(.input-group--single-line).input-group--placeholder:not(.input-group--textarea) label, -.input-group--text-field.input-group--dirty.input-group--select label, -.v-input.input-group--dirty:not(.input-group--textarea) label { - transform: translate(0, -22px) scale(0.92); -} -h1, -h2, -h3, -h4, -h5, -h6 { - margin: 0.625rem 0; - font-weight: 400; -} -h1, -.h1 { - font-size: 32px; -} -h2, -.h2 { - font-size: 24px; - margin: 0 0 1.5625rem; -} -h3, -.h3 { - font-size: 20px; - margin: 0 0 0.9375rem; -} -p { - margin: 0 0 1.25rem; -} -b, -strong { - font-weight: 500; -} -ol { - padding: 10px 20px; -} -.monospace { - font-family: 'Roboto Mono', monospace; -} -font::first-letter { - text-transform: capitalize; -} -i font::first-letter { - text-transform: none; -} -.disabled-dotted-border, -.v-input--is-readonly .v-input__control .v-input__slot:before, -.md-output_readonly:after { - background-color: transparent !important; - background-image: linear-gradient(to right, rgba(0,0,0,0.37) 0, rgba(0,0,0,0.37) 33%, transparent 0); - background-position: bottom; - background-size: 3px 1px; - background-repeat: repeat-x; -} -.v-list__tile__action .v-input--selection-controls .v-input__slot { - margin: 0; -} -.container { - padding: 16px; -} -.v-select__selections { - font-size: 14px; - overflow: hidden; -} -.v-select__selections .selection { - flex: 1 1 100%; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} -.v-text-field__details { - min-height: 22px; -} -.v-select > .v-input__control > .v-input__slot { - cursor: pointer; -} -.v-input--is-readonly label { - transform: translate(0, -22px) scale(0.92); -} -.v-input--is-readonly.v-input--is-focused label { - color: rgba(0,0,0,0.57) !important; -} -.v-input--is-readonly input:focus { - caret-color: transparent !important; -} -.v-input--is-readonly .v-input__control .v-input__slot:after { - content: none; -} -.v-input--is-readonly .v-input__control .v-input__slot:before { - border-color: transparent !important; -} -.v-input--checkbox label, -.v-radio label { - color: #212121 !important; - user-select: auto !important; -} -.v-input--is-disabled.v-input--checkbox label, -.v-input--is-disabled .v-radio label, -.v-radio--is-disabled.v-radio label { - color: #bdbdbd !important; - user-select: auto !important; -} -.theme--light.v-input--selection-controls.v-input--is-disabled.v-input--is-label-active.v-input--checkbox .v-icon, -.v-radio.v-radio--is-disabled.theme--light.accent--text .v-icon { - color: rgba(var(--theme_accent_rgb),0.26) !important; -} -.v-tabs__item--active { - color: var(--theme_accent); -} -.v-btn--small { - min-width: auto; -} -.theme--light.v-list .v-list__tile__mask { - color: var(--theme_accent); - background: rgba(var(--theme_accent_rgb),0.1); -} -.v-dialog__content { - min-width: 1200px; -} -.v-list--disabled, -.v-list__tile--disabled { - pointer-events: none !important; -} -.theme--light .v-text-field__prefix { - color: rgba(0,0,0,0.87); -} -.v-input.primary--text, -.v-input .v-label.primary--text, -.v-input .v-input__icon .primary--text { - color: var(--theme_accent) !important; - caret-color: currentColor !important; -} -.hint { - font-size: 12px; - color: rgba(0,0,0,0.57); - padding: 5px 0; - float: left; - max-width: 99%; -} -.hint_error { - color: #d21a44; -} -.hint_right { - float: right; - color: #2196f3; - cursor: pointer; -} -.dialog-form { - width: 100%; -} -.layout-flex { - display: flex; - flex-direction: column; - flex: 1; - min-height: 0; -} -html, -body { - overflow-y: auto; - overflow-x: auto; - margin: 0; -} -body { - min-width: 1200px; - display: flex; - flex-direction: column; -} -.theme--light.application { - background-color: #fff; -} -.application, -.application--wrap, -.base-layout, -.proxy-layout { - height: 100vh; -} -.application { - min-width: 1280px; -} -.base-layout, -.proxy-layout { - display: flex; - flex-direction: column; -} -.base-layout, -.application, -.proxy-layout { - flex: 1 1 100%; -} -.card { - background-color: #fff; - border-color: #fff; - color: rgba(0,0,0,0.87); - display: block; - border-radius: 2px; - position: relative; - transition: 0.3s cubic-bezier(0.25, 0.8, 0.5, 1); - text-decoration: none; - 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); -} -.card_hoverable:hover { - cursor: pointer; - box-shadow: 0px 5px 5px -3px rgba(0,0,0,0.2), 0px 8px 10px 1px rgba(0,0,0,0.14), 0px 3px 14px 2px rgba(0,0,0,0.12); -} -.base-layout-width { - min-width: 1200px; - max-width: 1200px; -} -.form-control { - margin: 18px 0; -} -.assistive-text, -.detail-item__subhead, -.detail-item__assistive-text { - line-height: 16px; - color: #707070; - font-size: 12px; -} -.detail-item { - min-width: 0; - margin-top: 24px; -} -.detail-item:first-child { - margin-top: 0; -} -.detail-item__head { - display: flex; - align-items: center; - margin-bottom: 8px; - line-height: 16px; - font-weight: 500; - font-size: 14px; -} -.detail-item__subhead { - font-weight: normal; - margin-left: 16px; -} -.detail-item__content-holder { - display: flex; - align-items: center; -} -.detail-item__image { - flex: 0 0 auto; - margin-right: 8px; -} -.detail-item__image_right { - order: 2; - margin-left: 8px; - margin-right: 0; -} -.detail-item__content { - flex-grow: 1; - flex-shrink: 1; - min-width: 0; -} -.detail-item__text { - line-height: 20px; - font-size: 14px; - word-wrap: break-word; - word-break: break-word; -} -.detail-item__text .v-btn--icon.v-btn--small { - margin-top: -4px; - margin-bottom: -4px; - vertical-align: bottom; -} -.detail-group { - margin-top: 24px; -} -.detail-group:first-child { - margin-top: 0; -} -.detail-group__content { - display: inline-flex; - align-items: flex-start; - vertical-align: top; -} -.detail-group_separated { - margin-top: 32px; -} -.detail-group_separated .detail-group__content { - border-top: 1px solid rgba(0,0,0,0.12); - padding-top: 24px; -} -.detail-group .detail-item { - margin-right: 32px; - margin-top: 0; -} -.link-with-icon { - display: inline-flex; - align-items: center; - text-decoration: none; -} -.link-with-icon span { - text-decoration: underline; -} -.link-with-icon .icon { - text-decoration: none; -} -.link-with-icon:hover span { - text-decoration: none; -} -.documents-list__item + .documents-list__item { - margin-top: 48px; - padding-top: 24px; - border-top: 1px dashed rgba(0,0,0,0.12); -} -.document-info__caption { - margin-bottom: 8px; - line-height: 1; - letter-spacing: 0.25px; - font-size: 12px; - font-weight: 500; -} -.document-info__title { - display: inline; - margin-bottom: 0; - margin-top: 0; - margin-right: 8px; - font-size: 18px; - line-height: 24px; - color: #212121; - font-weight: 500; - vertical-align: middle; -} -.document-info__title a { - color: var(--theme_accent); - transition: color 0.3s cubic-bezier(0.25, 0.8, 0.5, 1); -} -.document-info__title a:hover { - text-decoration: none; -} -.document-info__subtitle { - color: #707070; -} -.document-info__title-holder .inline-mark { - vertical-align: middle; -} -.document-info__toolbar { - display: flex; - align-items: center; - height: 36px; - margin-top: 2px; -} -.document-info__description { - margin-top: 24px; - max-width: 800px; -} -.document-info__description_wide { - max-width: 1000px; -} -.document-info__actions-holder { - margin-top: 24px; -} -.details-view__section + .details-view__section { - margin-top: 48px; -} -.details-view__section-head { - display: flex; - align-items: flex-start; -} -.details-view__section-head button { - height: 24px; -} -.details-view__section-title { - line-height: 24px; - font-size: 18px; - font-weight: 500; - margin-top: 0; - margin-bottom: 24px; -} -.details-view__section-subtitle { - margin-top: 4px; - margin-bottom: 24px; - line-height: 20px; - font-size: 14px; - color: #707070; -} -.content-columns-holder { - display: flex; - flex: 1; - min-height: 0; -} -.page-navigation { - display: flex; - align-items: center; - margin-right: 48px; -} -.page-navigation__back-button.v-btn--icon { - margin: 0 26px 0 -6px; - flex: 0 0 auto; -} -.page-navigation__title { - flex: 0 1 auto; - font-size: 20px; - font-weight: 500; - line-height: 1; - margin-top: 0; - margin-bottom: 0; - letter-spacing: 0; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} -.search { - width: 400px; - margin-left: auto; - margin-right: auto; -} -.search_fluid { - width: auto; -} -.markdown-document { - background-color: rgba(33,33,33,0.04); - padding: 32px 24px; - width: 640px; - overflow: hidden; - border-radius: 8px; -} -.object-image { - border-radius: 6.25%; -} -.list { - padding: 8px 0 8px; - display: flex; - flex-direction: column; -} -.list .list-item { - justify-content: left; - align-items: center; - display: flex; - font-size: 16px; - font-weight: 400; - height: 48px; - margin: 0; - padding: 0 16px; - width: 100%; - position: relative; - text-decoration: none; - transition: background 0.3s cubic-bezier(0.25, 0.8, 0.5, 1); -} -.section-headline { - margin: 0 0 1.5625rem; -} -.section-headline__title { - margin: 0 0 5px; -} -.section-headline__hint { - color: rgba(0,0,0,0.57); -} -.empty-data { - text-align: center; - margin: 40px 0; -} -.empty-data__media.icon { - color: rgba(0,0,0,0.37); -} -.empty-data__text { - text-transform: uppercase; - font-weight: 500; - color: rgba(0,0,0,0.57); -} -.empty-state { - padding: 16px; - margin: auto; - text-align: center; - color: rgba(0,0,0,0.57); -} -.empty-state__title { - margin-bottom: 30px; -} -.empty-state__text { - line-height: 1.388; - font-size: 18px; -} -.empty-state__icon { - margin: 0 0 30px; - font-size: 96px; - width: 96px; - height: 96px; - min-width: 96px; - min-height: 96px; -} -.v-text-field .v-input__append-inner { - margin-top: 9px; -} -._required::after, -._field_required label::after { - content: '*'; - margin-left: 3px; - color: #f00; - text-decoration: none; - display: inline-block; -} -.info-mode label { - color: rgba(0,0,0,0.57) !important; -} -.info-mode input { - color: rgba(0,0,0,0.87) !important; -} -.info-mode .input-group__details { - opacity: 0 !important; -} -.info-mode .v-input__slot:before { - display: none; -} -.md-output_readonly { - position: relative; - padding-bottom: 31px; - padding-top: 5px; - line-height: 20px; - min-height: 56px; -} -.md-output_readonly:after { - content: ''; - position: absolute; - bottom: 25px; - left: 0; - right: 0; - height: 1px; -} -.md-output_readonly p:last-child, -.md-output_readonly ol:last-child, -.md-output_readonly ul:last-child, -.md-output_readonly blockquote:last-child { - margin-bottom: 0; -} -.collapse_details .input-group__details { - display: none; -} -.button_ignore-left-frame { - margin-left: -16px; -} -.button_ignore-right-frame { - margin-right: -16px; -} -.button_margin_none { - margin: 0px; -} -.v-select_single-line .v-select__selections { - color: #000 !important; - font-size: 14px; -} -.v-input__box .v-input__slot { - background: #f5f5f5; - height: 44px; - padding: 12px; - border-radius: 6px; -} -.v-input__box .v-input__append-inner { - margin-top: 4px; -} -.font-size_h1 { - font-size: 24px; -} -.font-size_h2 { - font-size: 20px; -} -.font-size_normal { - font-size: 16px; -} -.font-size_smaller { - font-size: 14px; -} -.font-size_small { - font-size: 12px; -} -.font-weight_medium { - font-weight: 500; -} -._ma_0 { - margin: 0px; -} -._mt_0 { - margin-top: 0px; -} -._mr_0 { - margin-right: 0px; -} -._mb_0 { - margin-bottom: 0px; -} -._ml_0 { - margin-left: 0px; -} -._mx_0 { - margin-right: 0px; - margin-left: 0px; -} -._my_0 { - margin-top: 0px; - margin-bottom: 0px; -} -._pa_0 { - padding: 0px; -} -._pt_0 { - padding-top: 0px; -} -._pr_0 { - padding-right: 0px; -} -._pb_0 { - padding-bottom: 0px; -} -._pl_0 { - padding-left: 0px; -} -._px_0 { - padding-right: 0px; - padding-left: 0px; -} -._py_0 { - padding-top: 0px; - padding-bottom: 0px; -} -._ma_4 { - margin: 4px; -} -._mt_4 { - margin-top: 4px; -} -._mr_4 { - margin-right: 4px; -} -._mb_4 { - margin-bottom: 4px; -} -._ml_4 { - margin-left: 4px; -} -._mx_4 { - margin-right: 4px; - margin-left: 4px; -} -._my_4 { - margin-top: 4px; - margin-bottom: 4px; -} -._pa_4 { - padding: 4px; -} -._pt_4 { - padding-top: 4px; -} -._pr_4 { - padding-right: 4px; -} -._pb_4 { - padding-bottom: 4px; -} -._pl_4 { - padding-left: 4px; -} -._px_4 { - padding-right: 4px; - padding-left: 4px; -} -._py_4 { - padding-top: 4px; - padding-bottom: 4px; -} -._ma_8 { - margin: 8px; -} -._mt_8 { - margin-top: 8px; -} -._mr_8 { - margin-right: 8px; -} -._mb_8 { - margin-bottom: 8px; -} -._ml_8 { - margin-left: 8px; -} -._mx_8 { - margin-right: 8px; - margin-left: 8px; -} -._my_8 { - margin-top: 8px; - margin-bottom: 8px; -} -._pa_8 { - padding: 8px; -} -._pt_8 { - padding-top: 8px; -} -._pr_8 { - padding-right: 8px; -} -._pb_8 { - padding-bottom: 8px; -} -._pl_8 { - padding-left: 8px; -} -._px_8 { - padding-right: 8px; - padding-left: 8px; -} -._py_8 { - padding-top: 8px; - padding-bottom: 8px; -} -._ma_12 { - margin: 12px; -} -._mt_12 { - margin-top: 12px; -} -._mr_12 { - margin-right: 12px; -} -._mb_12 { - margin-bottom: 12px; -} -._ml_12 { - margin-left: 12px; -} -._mx_12 { - margin-right: 12px; - margin-left: 12px; -} -._my_12 { - margin-top: 12px; - margin-bottom: 12px; -} -._pa_12 { - padding: 12px; -} -._pt_12 { - padding-top: 12px; -} -._pr_12 { - padding-right: 12px; -} -._pb_12 { - padding-bottom: 12px; -} -._pl_12 { - padding-left: 12px; -} -._px_12 { - padding-right: 12px; - padding-left: 12px; -} -._py_12 { - padding-top: 12px; - padding-bottom: 12px; -} -._ma_16 { - margin: 16px; -} -._mt_16 { - margin-top: 16px; -} -._mr_16 { - margin-right: 16px; -} -._mb_16 { - margin-bottom: 16px; -} -._ml_16 { - margin-left: 16px; -} -._mx_16 { - margin-right: 16px; - margin-left: 16px; -} -._my_16 { - margin-top: 16px; - margin-bottom: 16px; -} -._pa_16 { - padding: 16px; -} -._pt_16 { - padding-top: 16px; -} -._pr_16 { - padding-right: 16px; -} -._pb_16 { - padding-bottom: 16px; -} -._pl_16 { - padding-left: 16px; -} -._px_16 { - padding-right: 16px; - padding-left: 16px; -} -._py_16 { - padding-top: 16px; - padding-bottom: 16px; -} -._ma_20 { - margin: 20px; -} -._mt_20 { - margin-top: 20px; -} -._mr_20 { - margin-right: 20px; -} -._mb_20 { - margin-bottom: 20px; -} -._ml_20 { - margin-left: 20px; -} -._mx_20 { - margin-right: 20px; - margin-left: 20px; -} -._my_20 { - margin-top: 20px; - margin-bottom: 20px; -} -._pa_20 { - padding: 20px; -} -._pt_20 { - padding-top: 20px; -} -._pr_20 { - padding-right: 20px; -} -._pb_20 { - padding-bottom: 20px; -} -._pl_20 { - padding-left: 20px; -} -._px_20 { - padding-right: 20px; - padding-left: 20px; -} -._py_20 { - padding-top: 20px; - padding-bottom: 20px; -} -._ma_24 { - margin: 24px; -} -._mt_24 { - margin-top: 24px; -} -._mr_24 { - margin-right: 24px; -} -._mb_24 { - margin-bottom: 24px; -} -._ml_24 { - margin-left: 24px; -} -._mx_24 { - margin-right: 24px; - margin-left: 24px; -} -._my_24 { - margin-top: 24px; - margin-bottom: 24px; -} -._pa_24 { - padding: 24px; -} -._pt_24 { - padding-top: 24px; -} -._pr_24 { - padding-right: 24px; -} -._pb_24 { - padding-bottom: 24px; -} -._pl_24 { - padding-left: 24px; -} -._px_24 { - padding-right: 24px; - padding-left: 24px; -} -._py_24 { - padding-top: 24px; - padding-bottom: 24px; -} -._ma_28 { - margin: 28px; -} -._mt_28 { - margin-top: 28px; -} -._mr_28 { - margin-right: 28px; -} -._mb_28 { - margin-bottom: 28px; -} -._ml_28 { - margin-left: 28px; -} -._mx_28 { - margin-right: 28px; - margin-left: 28px; -} -._my_28 { - margin-top: 28px; - margin-bottom: 28px; -} -._pa_28 { - padding: 28px; -} -._pt_28 { - padding-top: 28px; -} -._pr_28 { - padding-right: 28px; -} -._pb_28 { - padding-bottom: 28px; -} -._pl_28 { - padding-left: 28px; -} -._px_28 { - padding-right: 28px; - padding-left: 28px; -} -._py_28 { - padding-top: 28px; - padding-bottom: 28px; -} -._ma_32 { - margin: 32px; -} -._mt_32 { - margin-top: 32px; -} -._mr_32 { - margin-right: 32px; -} -._mb_32 { - margin-bottom: 32px; -} -._ml_32 { - margin-left: 32px; -} -._mx_32 { - margin-right: 32px; - margin-left: 32px; -} -._my_32 { - margin-top: 32px; - margin-bottom: 32px; -} -._pa_32 { - padding: 32px; -} -._pt_32 { - padding-top: 32px; -} -._pr_32 { - padding-right: 32px; -} -._pb_32 { - padding-bottom: 32px; -} -._pl_32 { - padding-left: 32px; -} -._px_32 { - padding-right: 32px; - padding-left: 32px; -} -._py_32 { - padding-top: 32px; - padding-bottom: 32px; -} -._ma_36 { - margin: 36px; -} -._mt_36 { - margin-top: 36px; -} -._mr_36 { - margin-right: 36px; -} -._mb_36 { - margin-bottom: 36px; -} -._ml_36 { - margin-left: 36px; -} -._mx_36 { - margin-right: 36px; - margin-left: 36px; -} -._my_36 { - margin-top: 36px; - margin-bottom: 36px; -} -._pa_36 { - padding: 36px; -} -._pt_36 { - padding-top: 36px; -} -._pr_36 { - padding-right: 36px; -} -._pb_36 { - padding-bottom: 36px; -} -._pl_36 { - padding-left: 36px; -} -._px_36 { - padding-right: 36px; - padding-left: 36px; -} -._py_36 { - padding-top: 36px; - padding-bottom: 36px; -} -._ma_40 { - margin: 40px; -} -._mt_40 { - margin-top: 40px; -} -._mr_40 { - margin-right: 40px; -} -._mb_40 { - margin-bottom: 40px; -} -._ml_40 { - margin-left: 40px; -} -._mx_40 { - margin-right: 40px; - margin-left: 40px; -} -._my_40 { - margin-top: 40px; - margin-bottom: 40px; -} -._pa_40 { - padding: 40px; -} -._pt_40 { - padding-top: 40px; -} -._pr_40 { - padding-right: 40px; -} -._pb_40 { - padding-bottom: 40px; -} -._pl_40 { - padding-left: 40px; -} -._px_40 { - padding-right: 40px; - padding-left: 40px; -} -._py_40 { - padding-top: 40px; - padding-bottom: 40px; -} -._ma_44 { - margin: 44px; -} -._mt_44 { - margin-top: 44px; -} -._mr_44 { - margin-right: 44px; -} -._mb_44 { - margin-bottom: 44px; -} -._ml_44 { - margin-left: 44px; -} -._mx_44 { - margin-right: 44px; - margin-left: 44px; -} -._my_44 { - margin-top: 44px; - margin-bottom: 44px; -} -._pa_44 { - padding: 44px; -} -._pt_44 { - padding-top: 44px; -} -._pr_44 { - padding-right: 44px; -} -._pb_44 { - padding-bottom: 44px; -} -._pl_44 { - padding-left: 44px; -} -._px_44 { - padding-right: 44px; - padding-left: 44px; -} -._py_44 { - padding-top: 44px; - padding-bottom: 44px; -} -._ma_48 { - margin: 48px; -} -._mt_48 { - margin-top: 48px; -} -._mr_48 { - margin-right: 48px; -} -._mb_48 { - margin-bottom: 48px; -} -._ml_48 { - margin-left: 48px; -} -._mx_48 { - margin-right: 48px; - margin-left: 48px; -} -._my_48 { - margin-top: 48px; - margin-bottom: 48px; -} -._pa_48 { - padding: 48px; -} -._pt_48 { - padding-top: 48px; -} -._pr_48 { - padding-right: 48px; -} -._pb_48 { - padding-bottom: 48px; -} -._pl_48 { - padding-left: 48px; -} -._px_48 { - padding-right: 48px; - padding-left: 48px; -} -._py_48 { - padding-top: 48px; - padding-bottom: 48px; -} -._ma_52 { - margin: 52px; -} -._mt_52 { - margin-top: 52px; -} -._mr_52 { - margin-right: 52px; -} -._mb_52 { - margin-bottom: 52px; -} -._ml_52 { - margin-left: 52px; -} -._mx_52 { - margin-right: 52px; - margin-left: 52px; -} -._my_52 { - margin-top: 52px; - margin-bottom: 52px; -} -._pa_52 { - padding: 52px; -} -._pt_52 { - padding-top: 52px; -} -._pr_52 { - padding-right: 52px; -} -._pb_52 { - padding-bottom: 52px; -} -._pl_52 { - padding-left: 52px; -} -._px_52 { - padding-right: 52px; - padding-left: 52px; -} -._py_52 { - padding-top: 52px; - padding-bottom: 52px; -} -._ma_56 { - margin: 56px; -} -._mt_56 { - margin-top: 56px; -} -._mr_56 { - margin-right: 56px; -} -._mb_56 { - margin-bottom: 56px; -} -._ml_56 { - margin-left: 56px; -} -._mx_56 { - margin-right: 56px; - margin-left: 56px; -} -._my_56 { - margin-top: 56px; - margin-bottom: 56px; -} -._pa_56 { - padding: 56px; -} -._pt_56 { - padding-top: 56px; -} -._pr_56 { - padding-right: 56px; -} -._pb_56 { - padding-bottom: 56px; -} -._pl_56 { - padding-left: 56px; -} -._px_56 { - padding-right: 56px; - padding-left: 56px; -} -._py_56 { - padding-top: 56px; - padding-bottom: 56px; -} -._ma_60 { - margin: 60px; -} -._mt_60 { - margin-top: 60px; -} -._mr_60 { - margin-right: 60px; -} -._mb_60 { - margin-bottom: 60px; -} -._ml_60 { - margin-left: 60px; -} -._mx_60 { - margin-right: 60px; - margin-left: 60px; -} -._my_60 { - margin-top: 60px; - margin-bottom: 60px; -} -._pa_60 { - padding: 60px; -} -._pt_60 { - padding-top: 60px; -} -._pr_60 { - padding-right: 60px; -} -._pb_60 { - padding-bottom: 60px; -} -._pl_60 { - padding-left: 60px; -} -._px_60 { - padding-right: 60px; - padding-left: 60px; -} -._py_60 { - padding-top: 60px; - padding-bottom: 60px; -} -._ma_64 { - margin: 64px; -} -._mt_64 { - margin-top: 64px; -} -._mr_64 { - margin-right: 64px; -} -._mb_64 { - margin-bottom: 64px; -} -._ml_64 { - margin-left: 64px; -} -._mx_64 { - margin-right: 64px; - margin-left: 64px; -} -._my_64 { - margin-top: 64px; - margin-bottom: 64px; -} -._pa_64 { - padding: 64px; -} -._pt_64 { - padding-top: 64px; -} -._pr_64 { - padding-right: 64px; -} -._pb_64 { - padding-bottom: 64px; -} -._pl_64 { - padding-left: 64px; -} -._px_64 { - padding-right: 64px; - padding-left: 64px; -} -._py_64 { - padding-top: 64px; - padding-bottom: 64px; -} -._ma_auto { - margin: auto; -} -._mt_auto { - margin-top: auto; -} -._mr_auto { - margin-right: auto; -} -._mb_auto { - margin-bottom: auto; -} -._ml_auto { - margin-left: auto; -} -._mx_auto { - margin-right: auto; - margin-left: auto; -} -._my_auto { - margin-top: auto; - margin-bottom: auto; -} -.horizontal-spacer { - flex-grow: 1; -} -.mgt_1 { - margin-top: 64px; -} -.mgt_2 { - margin-top: 24px; -} -.mgt_3 { - margin-top: 16px; -} -.mgb_1 { - margin-bottom: 64px; -} -.mgb_2 { - margin-bottom: 24px; -} -.mgb_3 { - margin-bottom: 16px; -} -.mgr_1 { - margin-right: 64px; -} -.mgr_2 { - margin-right: 24px; -} -.mgr_3 { - margin-right: 16px; -} -.mgl_1 { - margin-left: 64px; -} -.mgl_2 { - margin-left: 24px; -} -.mgl_3 { - margin-left: 16px; -} -.is-disabled { - opacity: 0.5; - pointer-events: none; -} -.is-failed { - color: #d21a44; -} -.is-successfully { - color: #00c853; -} -.is-transparent { - opacity: 0; -} -.is-hidden { - display: none; -} -.is-inactive { - color: #d21a44; -} -.is-active { - color: #00c853; -} -.is-empty { - color: rgba(0,0,0,0.57); -} -.color_light { - color: #424242; -} -.is-invisible { - visibility: hidden; - overflow: hidden; - opacity: 0; - transition: all 0.2s ease-out; -} -.is-visible { - visibility: visible; - overflow: visible; - opacity: 1; -} -.line-height_compact { - line-height: 1; -} -.line-height_small { - line-height: 1.1; -} -.img { - max-width: 100%; - display: block; - height: auto; -} -.drag-handle { - cursor: grab; -} -.pointer { - cursor: pointer; -} -.padding { - padding: 16px; -} -.text-left { - text-align: left; -} -.text-right { - text-align: right; -} -.text-center { - text-align: center; -} -.capitalize { - text-transform: capitalize; -} -.lowercase { - text-transform: lowercase; -} -.uppercase { - text-transform: uppercase; -} -.capitalize-first-letter::first-letter { - text-transform: capitalize; -} -.text-decoration-none { - text-decoration: none; -} -.text-decoration-underline { - text-decoration: underline; -} -.text_nowrap { - white-space: nowrap; -} -.col-centered { - float: none; - display: block; - margin-right: auto; - margin-left: auto; -} -.scroll { - overflow-y: auto; -} -.full-width { - width: 100%; -} -.full-height { - line-height: 100%; - min-height: 100%; - height: 100%; -} -.global-indent { - margin-bottom: 60px; -} -.browser-warning-text { - margin-bottom: 0; -} -.overflow-auto { - overflow: auto; -} -.font-size-normal { - font-size: 1em !important; -} -.container_compact, -.container_compact.fluid { - max-width: 1440px; -} -.min-width_none { - min-width: 0; -} -.inherit-width { - max-width: 100%; -} -.flex-0-0 { - flex: 0 0 auto; -} -.border { - border: 1px solid rgba(0,0,0,0.12); -} -.border-dashed { - border-bottom: 1px dashed rgba(0,0,0,0.12); -} -.border-bottom-0 { - border-bottom-width: 0; -} -.border-bottom-1 { - border-bottom: 1px solid rgba(0,0,0,0.12); -} -.border-top-0 { - border-top-width: 0; -} -.border-top-1 { - border-top: 1px solid rgba(0,0,0,0.12); -} -.assistive-color { - color: #707070; -} -.outlined-picture { - background-color: #f8f8f8; - border: 1px solid #000; -} -.outlined-picture_gray { - border-color: #e5e5e5; -} -.outlined-picture .c-icon, -.picture-placeholder .c-icon { - color: #dedede; -} -.multiline-code { - white-space: pre-wrap; - font-family: 'Roboto Mono', monospace; - font-size: 13px; -} -.truncate-text, -.truncator__truncate { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} -.truncator { - display: flex; - min-width: 0; - align-items: center; -} -.truncator__keep { - flex: 0 0 auto; -} -._clamp-lines, -.clamp-lines-2, -.clamp-lines-3, -.clamp-lines-4 { - display: -webkit-box; - overflow: hidden; - -webkit-box-orient: vertical; -} -.clamp-lines-2 { - -webkit-line-clamp: 2; -} -.clamp-lines-3 { - -webkit-line-clamp: 3; -} -.clamp-lines-4 { - -webkit-line-clamp: 4; -} -._display_inline-block { - display: inline-block; -} -._display_flex { - display: flex; -} -._display_flex-wrap { - display: flex; - flex-wrap: wrap; -} -._display_flex-center { - display: flex; - align-items: center; -} -.placeholder-image { - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZAAAADhCAMAAADRaBMuAAAARVBMVEUAAADh4eHh4eHg4ODf39/f39/g4ODh4eHf39/f39/g4ODf39/g4ODf39/f39/f39/g4ODg4ODh4eHf39/f39/m5ubf39+Jo7sIAAAAF3RSTlMAj3//QCC/n3Aw7xDfgGBQr89fkKAfsCGTTG8AAAQ/SURBVHgB7dvpmqs6DoVhpYQZbOFAJ933f6d9Rs5cJI4ooufU9/7fE9r2WjaU4E0AAAAAAAAAAAAAAAAAAAAAXHgEoXxox0MIJKn2PIVABlUdeQxhTPqjXHgQUZj+ZOZBBFH1F4lHEUIy/UUvMVB5N50gROXdmMRA5d2Mgne76obqG6jybi4SA5V3MwlCVF6l+oZLdKpvqMq7sSJ4m0X/bhYESHSqb7zKuxnkrbjECpfrVN6g1ZfKu6kSApWXXH+nVTdhqy+Vd5OTBEDlDZDrVN5I1ZdEj79EqLybUXCeSTfRqi+JTvUNoOozkpyKSyxyPYqLbqi+ESR9kgleV9LU1Z903VQclZdcdyvdOKxZ/2Rd5uvUmuj+6otyvZh+Ji81tVdePmR8WRn7rA+sl6lhgZDrDl2f9SlrTW2Vl+rbrnyYNhhSa6JvrvIMxpG10ZAaKi8fMrbZxvHCSBZtNcs+dKYv+pCqzXKSHUiLvs5mbTcIPvefrA6zjFk3/uqLMqiHla32HlJ9kUxdqvxk1lZV0LJdtV7ejrrxXGnhQ52S/Goyqm+AeQyykWTe6otBnXJypFEvaJlH+7aTzFN9cVEv8zW2VdCUH+3VNWVtMQra59EUAtOL1Red+iX5u1FbXARtu337BeHtlZnC1M2S/KOV6nt8gHgSOeV3VF8CxOQzY+tvA1O/Kp/qz7/SYsMa5HMpU31bJD1Akh0z1bfFoH432VPs5Fwn0ZPsqmGqL4nemOt8yFjVz45bhnzI2Ktfd/A6nEkQl0EeG897m0vFSvJYydpg4QziMMszbnpO9SXSrRy3N1J9V3Wrx7UH3uamgyuv8/6EK61R3dKBw6f69uo1HHglQPUteuCniv6eRa5f1Ws+8k+j+t7Uyb5yPRoR0qweeq9M9c3qs0iTu+6i+k7qlL64ZF/I9CbDl/95k3wrs7pY+vJ7gZ6S1aCecOzpKFlPszNKhBUG4lggvt7LlZapw3D4/wCqb/ZV3naLY/DfwaGXWP6TIbmuDsN8lisD+TJVwEAYCB/tvqX2ks8MhJP60f4re3DXk8ku3PRcWXZh1HP1sgudnut/sgtFzzXKPlis1otFT1UkElJ9lVBI9UEeQY51tYh7rAhBjXUsRMm8nfq2F75JHkMXrGMhxzqmY9ZzmDQg1uNEOm6xFgiSnmEWRDqtW5IGpEioBMEcK0FQLNYCQRfskI4lVqKjWKwNCx0b1rc5r1uRQHgxkpNEQoxc5TVIOdYdFqYcax6oerS7wKMGmwdq1gPdBF6TxcoPJIv10zlIvR4hdxII76vWJDjM1WLFOdJdPawTHKyao10ViYMk6ZMgzr7VdxIEI2EcJ0ij6bPywjjOcL3rM/qxCM5R6j0/mkYSnKobF9N/kvvbtcg7oHTjbenN9CfZ1mUYr6yMfy0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAfAFTgo7mGhZ5cAAAAAElFTkSuQmCC); -} -.horizontal-list > :not(:last-child)::after { - content: '\2022'; - margin: 0 7px; - display: inline-block; - color: #707070; -} -.divider { - display: block; - flex: 1 1 0px; - max-width: 100%; - height: 0px; - max-height: 0px; - border: solid; - border-width: thin 0 0 0; - border-color: #e0e0e0; - transition: inherit; -} -.divider_vertical { - align-self: stretch; - border: solid; - border-width: 0 thin 0 0; - border-color: #e0e0e0; - display: inline-flex; - height: inherit; - min-height: 100%; - max-height: 100%; - max-width: 0px; - width: 0px; - vertical-align: text-bottom; -} -.nowrap-cell { - white-space: nowrap; -} -#updateBrowserWarning { - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - z-index: 3; - display: none; - vertical-align: middle; - text-align: center; - white-space: nowrap; - background-color: #fff; -} -#updateBrowserWarning:after { - content: ""; - display: inline-block; - height: 100%; - vertical-align: middle; -} -#updateBrowserWarning .message { - display: inline-block; - vertical-align: middle; - color: #212121; -} -#updateBrowserWarning .message .message__title { - margin-bottom: 24px; - font-size: 24px; - font-weight: 500; - line-height: 1; -} -#updateBrowserWarning .message p { - line-height: 20px; - margin: 0; -} -#updateBrowserWarning .message .message__icon { - display: inline-block; - width: 56px; - height: 56px; - margin-bottom: 48px; - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADgAAAA4CAMAAACfWMssAAAApVBMVEUAAADvx0zyyUzyykzyyEz0ylXvx1Dvx0jxyUvvz0Dvz1Dvx0ryyU3xx0zyykzyyU3yyUz0yUvvykrxyEvyx0ryyEzzykzvxUrxyUvxzE7vx0zvyUnxyUzyyUzvyUzwyEvyyEzxyUvzyEzvylDzyUzyyUv1yErxxkvyykvyyUzyyUzzy0zxyUvyyk3yyEzyyUzxx0vyyE3xyEzxyEvyyE3xyEzyyUwjqgGbAAAANnRSTlMAQP6/vwEgIN4QEGDfgL7er18wcGC+bzDfX0FQz+9Qr+5fbzDP309wn7+uf8+e7+6gru7fr29GUEDAAAABL0lEQVR4XuXU13LCMBCF4SOZSK4YSAiEFlJ7L/v+jxYuktmMbK+1lxm++3+OPJaNfZY7szPJddH5aE4/ytHYIY5JKJCMY7KSWtTXkOUJdbh1ujlWC+UxSbZLdHggmT2R9vSloX4vEzS4kiLUGUKvFOUegSMKrYwxi0sKWBOEJYUGAA4SCg3lQQ57JhMhlCYdxYc2AzvShIdgI0VIp2DPmrDmLichlB7yQhc6/DK60PzH0FOLdbKzbgsnwutg8p27IoVUuHKiU7AbRWfPwLzm6/BguIsPp/iriAr5pGweG6ZAz+SjMWax6hpkQ4ryhJDfUoTUo2FD/ewMLSoS8Q9OX1boUFndHtuk1Ck1EPhh1+jUQ1akVjnH6dQG7WCJOL54e/+NPz6/HDSymdlxGfbYN5W5RuTbEk06AAAAAElFTkSuQmCC); -} -#updateBrowserWarning .message .message__suggested-browsers { - margin-top: 40px; - color: #707070; -} -.recaptcha-position { - left: calc(100vw / 4 * 3 - 200px) !important; - top: -80px !important; - margin: auto 0 !important; -} -.recaptcha-position-parent { - left: 0 !important; -} -.grecaptcha-badge { - box-shadow: none !important; - border-radius: none !important; -} -.detail-item a { - text-decoration: none; -} -.detail-item a:hover { - text-decoration: underline; -} -a { - color: var(--theme_accent); - cursor: pointer; -} -.overflow-container { - position: absolute; - top: 0; - right: 0; - left: 0; - bottom: 0; - pointer-events: none; -} -.overflowing .overflow-container:before, -.overflowing .overflow-container:after { - content: ""; - position: absolute; - top: 0; - width: 96px; - height: 100%; - opacity: 0; - transition: opacity 0.2s ease; - z-index: 1; - pointer-events: none; -} -.overflowing .overflow-container:after { - right: 0; - background: linear-gradient(90deg, transparent, rgba(255,255,255,0.66) 50%, #fff 90%, #fff); -} -.overflowing .overflow-container:before { - left: 0; - background: linear-gradient(270deg, transparent, rgba(255,255,255,0.66) 50%, #fff 90%, #fff); -} -.overflowing_right .overflow-container:after, -.overflowing_both .overflow-container:after { - opacity: 1; -} -.overflowing_left .overflow-container:before, -.overflowing_both .overflow-container:before { - opacity: 1; -} -.highlighted { - background: #f2c94c; -} -input[type=text][materialize] { - appearance: none; - -webkit-appearance: none; - -moz-appearance: none; - width: 100%; - padding: 12px; - background: rgba(0,0,0,0.01); - border: 1px solid rgba(0,0,0,0.12); - border-radius: 2px; - color: #212121; - font-family: Roboto, "Helvetica Neue", sans-serif; - font-size: 14; - font-style: normal; - font-weight: 400; - line-height: 1.2em; -} -input[type=text][materialize]:focus-visible { - outline-width: 0; - border-color: var(--theme_accent); -} -input[type=text][materialize]:disabled { - border-style: dashed; -} -input[type=password][materialize] { - appearance: none; - -webkit-appearance: none; - -moz-appearance: none; - width: 100%; - padding: 12px; - background: rgba(0,0,0,0.01); - border: 1px solid rgba(0,0,0,0.12); - border-radius: 2px; - color: #212121; - font-family: Roboto, "Helvetica Neue", sans-serif; - font-size: 14; - font-style: normal; - font-weight: 400; - line-height: 1.2em; -} -input[type=password][materialize]:focus-visible { - outline-width: 0; - border-color: var(--theme_accent); -} -input[type=password][materialize]:disabled { - border-style: dashed; -} -textarea[materialize] { - appearance: none; - -webkit-appearance: none; - -moz-appearance: none; - width: 100%; - padding: 12px; - background: rgba(0,0,0,0.01); - border: 1px solid rgba(0,0,0,0.12); - border-radius: 2px; - color: #212121; - font-family: Roboto, "Helvetica Neue", sans-serif; - font-size: 14; - font-style: normal; - font-weight: 400; - line-height: 1.2em; -} -textarea[materialize]:focus-visible { - outline-width: 0; - border-color: var(--theme_accent); -} -textarea[materialize]:disabled { - border-style: dashed; -} -input[type=radio][materialize] { - appearance: none; - -webkit-appearance: none; - -moz-appearance: none; - margin: 0; - background: rgba(0,0,0,0.01); - width: 24px; - height: 24px; - border: 3px solid #666; - border-radius: 50%; - cursor: pointer; -} -input[type=radio][materialize]:checked { - background: radial-gradient(circle, var(--theme_accent) 45%, rgba(255,255,255,0) 45%); - border-color: var(--theme_accent); -} -input[type=radio][materialize]:focus-visible { - outline-width: 0; - border-color: var(--theme_accent); -} -input[type=checkbox][materialize] { - appearance: none; - -webkit-appearance: none; - -moz-appearance: none; - margin: 3px; - background: rgba(0,0,0,0.01); - width: 18px; - height: 18px; - border: 3px solid #666; - border-radius: 2px; - cursor: pointer; -} -input[type=checkbox][materialize]:checked { - border-color: var(--theme_accent); - background-color: var(--theme_accent); - position: relative; -} -input[type=checkbox][materialize]:checked:after { - content: url("data:image/svg+xml;utf8,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20width=%2212%22%20height=%2212%22%20viewBox=%220%200%2024%2024%22%3E%3Cpath%20d=%22M0%200h24v24H0z%22%20fill=%22none%22/%3E%3Cpath%20fill=%22white%22%20d=%22M9%2022l-10-10.598%202.798-2.859%207.149%207.473%2013.144-14.016%202.909%202.806z%22/%3E%3C/svg%3E"); - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; -} -input[type=checkbox][materialize]:focus-visible { - outline-width: 0; - border-color: var(--theme_accent); -} -label[materialize] { - color: #212121; - font-family: Roboto, "Helvetica Neue", sans-serif; - font-size: 14; - font-style: normal; - font-weight: 400; - line-height: 1.2em; -} -label[materialize][for] { - cursor: pointer; -} -select[materialize] { - appearance: none; - -webkit-appearance: none; - -moz-appearance: none; - width: 100%; - padding: 12px; - background: rgba(0,0,0,0.01); - border: 1px solid rgba(0,0,0,0.12); - border-radius: 2px; - background-image: url("data:image/svg+xml;utf8,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20width=%2224%22%20height=%2224%22%20viewBox=%220%200%2024%2024%22%3E%3Cpath%20d=%22M0%200h24v24H0z%22%20fill=%22none%22/%3E%3Cpath%20fill=%22rgba%280,0,0,0.57%29%22%20d=%22M7%2010l5%205%205-5z,%20M9%2022l-10-10.598%202.798-2.859%207.149%207.473%2013.144-14.016%202.909%202.806z%22/%3E%3C/svg%3E"); - background-repeat: no-repeat; - background-position: 100% center; - color: #212121; - font-family: Roboto, "Helvetica Neue", sans-serif; - font-size: 14; - font-style: normal; - font-weight: 400; - line-height: 1.2em; -} -select[materialize]::-ms-expand { - display: none; -} -select[materialize]:focus-visible { - outline-width: 0; - border-color: var(--theme_accent); -} -select[materialize]:disabled { - border-style: dashed; -} - -/*!***********************************************************************!*\ - !*** css ./node_modules/css-loader/dist/cjs.js!./ui/styles/index.css ***! - \***********************************************************************/ -/* -Copyright (c) 2023, Ingram Micro -All rights reserved. -*/ -:root { - --theme_primary: #1565c0; - --theme_primary_rgb: 21,101,192; - --theme_accent: #4797f2; - --theme_accent_rgb: 71,151,242; - --theme_contrast: #ffffff; - --theme_contrast_rgb: 255,255,255; -} - -body { - font-family: "Roboto", sans-serif; -} - diff --git a/connect_ext_ppr/tasks_manager.py b/connect_ext_ppr/tasks_manager.py index 97cab81..6cabcdf 100644 --- a/connect_ext_ppr/tasks_manager.py +++ b/connect_ext_ppr/tasks_manager.py @@ -14,15 +14,15 @@ from connect_ext_ppr.models.task import Task -async def validate_ppr(): +def validate_ppr(): return True -async def apply_ppr_and_delegate_to_marketplaces(): +def apply_ppr_and_delegate_to_marketplaces(): return True -async def delegate_to_l2(): +def delegate_to_l2(): return True @@ -33,7 +33,35 @@ async def delegate_to_l2(): } -async def main_process(deployment_request_id, config): +def execute_tasks(db, tasks): + was_succesfull = False + for task in tasks: + db.refresh(task, with_for_update=True) + if task.status == TasksStatusChoices.pending: + task.status = TasksStatusChoices.processing + task.started_at = datetime.utcnow() + db.add(task) + db.commit() + + try: + was_succesfull = TASK_PER_TYPE.get(task.type)() + task.status = TasksStatusChoices.done + if not was_succesfull: + task.status = TasksStatusChoices.error + except Exception: + was_succesfull = False + task.status = TasksStatusChoices.error + + task.finished_at = datetime.utcnow() + db.add(task) + db.commit() + if not was_succesfull: + break + + return was_succesfull + + +def main_process(deployment_request_id, config): with get_db_ctx_manager(config) as db: deployment_request = db.query(DeploymentRequest).options( @@ -55,32 +83,17 @@ async def main_process(deployment_request_id, config): deployment_request=deployment_request.id, ).order_by(Task.id).all() - deployment_request_status = DeploymentRequestStatusChoices.done - for task in tasks: - db.refresh(task, with_for_update=True) - if task.status == TasksStatusChoices.pending: - task.status = TasksStatusChoices.processing - task.started_at = datetime.utcnow() - db.add(task) - db.commit() - - was_succesfull = await TASK_PER_TYPE.get(task.type)() - task.status = TasksStatusChoices.done - if not was_succesfull: - task.status = TasksStatusChoices.error - task.finished_at = datetime.utcnow() - db.add(task) - db.commit() - - if not was_succesfull: - deployment_request_status = DeploymentRequestStatusChoices.error - break + was_succesfull = execute_tasks(db, tasks) db.refresh(deployment_request, with_for_update=True) + if deployment_request.status == DeploymentRequestStatusChoices.aborting: deployment_request.status = DeploymentRequestStatusChoices.aborted + elif was_succesfull: + deployment_request.status = DeploymentRequestStatusChoices.done else: - deployment_request.status = deployment_request_status + deployment_request.status = DeploymentRequestStatusChoices.error + db.add(deployment_request) db.commit() @@ -88,6 +101,7 @@ async def main_process(deployment_request_id, config): deployment_last_ppr = db.query(PPRVersion).filter_by( deployment=deployment.id, ).order_by(PPRVersion.version.desc()).first() + if ( deployment_last_ppr.version == deployment_request.ppr.version and deployment_request.delegate_l2 @@ -97,4 +111,4 @@ async def main_process(deployment_request_id, config): db.add(deployment) db.commit() - return deployment_request.status + return deployment_request.status diff --git a/connect_ext_ppr/validator.py b/connect_ext_ppr/validator.py new file mode 100644 index 0000000..851c31e --- /dev/null +++ b/connect_ext_ppr/validator.py @@ -0,0 +1,64 @@ +from fastapi import status + +from connect_ext_ppr.errors import ExtensionValidationError + + +def validate_deployment(deployment, account_id): + """ + Validates that the deployment belongs to the account + """ + if deployment.account_id != account_id: + raise ExtensionValidationError.VAL_001( + format_kwargs={ + 'field': 'deployment', + 'id': deployment.id, + }, + status_code=status.HTTP_400_BAD_REQUEST, + ) + + +def validate_ppr_version_belongs_to_deployment(ppr, deployment): + """ + Validates that the ppr can be asociated to DR + """ + if ppr.deployment != deployment.id: + raise ExtensionValidationError.VAL_001( + format_kwargs={'field': 'ppr', 'id': ppr.id}, + status_code=status.HTTP_400_BAD_REQUEST, + ) + + +def validate_dr_marketplaces(dr_marketplaces, dep_marketplaces): + """ + Validates that all the DR's marketplaces belong to the associated deployment + """ + diff = list(set(dr_marketplaces) - set(dep_marketplaces)) + if diff: + diff.sort() + raise ExtensionValidationError.VAL_002( + format_kwargs={ + 'field': 'marketplaces', + 'values': diff, + }, + status_code=status.HTTP_400_BAD_REQUEST, + ) + + +def validate_marketplaces_ppr(ppr, dr_marketplaces, dep_marketplaces): + """ + Validates that we can apply the ppr to all marketplaces + """ + dep_mkplc_map = {m.marketplace: m for m in dep_marketplaces} + mkplcs_w_erros = [] + for marketplace in dr_marketplaces: + if dep_mkplc_map[marketplace].ppr_id and dep_mkplc_map[marketplace].ppr_id > ppr.id: + mkplcs_w_erros.append(marketplace) + + if mkplcs_w_erros: + raise ExtensionValidationError.VAL_004( + format_kwargs={ + 'entity': 'marketplaces', + 'values': list(mkplcs_w_erros), + }, + status_code=status.HTTP_400_BAD_REQUEST, + ) diff --git a/connect_ext_ppr/webapp.py b/connect_ext_ppr/webapp.py index bfcd30b..15d311e 100644 --- a/connect_ext_ppr/webapp.py +++ b/connect_ext_ppr/webapp.py @@ -20,8 +20,8 @@ get_installation_client, ) from connect.eaas.core.extension import WebApplicationBase +from fastapi import BackgroundTasks, Depends, Request, Response, status from fastapi.responses import JSONResponse -from fastapi import Depends, Request, Response, status from sqlalchemy import desc, exists from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.orm import joinedload, selectinload, Session @@ -30,6 +30,7 @@ from connect_ext_ppr.db import ( create_db, get_cbc_extension_db, + get_config, get_db, VerboseBaseSession, ) @@ -44,13 +45,19 @@ from connect_ext_ppr.models.file import File from connect_ext_ppr.models.ppr import PPRVersion from connect_ext_ppr.models.task import Task -from connect_ext_ppr.service import add_deployments, create_ppr, validate_configuration from connect_ext_ppr.models.replicas import Product +from connect_ext_ppr.service import ( + add_deployments, + add_new_deployment_request, + create_ppr, + validate_configuration, +) from connect_ext_ppr.schemas import ( BatchProcessResponseSchema, BatchSchema, ConfigurationCreateSchema, ConfigurationSchema, + DeploymentRequestCreateSchema, DeploymentRequestSchema, DeploymentSchema, HubSchema, @@ -67,6 +74,7 @@ prepare_file, process_batch, ) +from connect_ext_ppr.tasks_manager import main_process from connect_ext_ppr.utils import ( _get_extension_client, _get_installation, @@ -86,6 +94,12 @@ get_task_schema, get_user_data_from_auth_token, ) +from connect_ext_ppr.validator import ( + validate_deployment, + validate_dr_marketplaces, + validate_marketplaces_ppr, + validate_ppr_version_belongs_to_deployment, +) @web_app(router) @@ -99,6 +113,54 @@ }, ) class ConnectExtensionXvsWebApplication(WebApplicationBase): + # example route for creation of deployment request + @router.post( + '/deployments/requests', + summary='Create a new deployment request', + response_model=DeploymentRequestSchema, + ) + def add_dep_request( + self, + deployment_request: DeploymentRequestCreateSchema, + background_tasks: BackgroundTasks, + client: ConnectClient = Depends(get_installation_client), + db: VerboseBaseSession = Depends(get_db), + installation: dict = Depends(get_installation), + config: dict = Depends(get_config), + logger: Logger = Depends(get_logger), + ): + account_id = installation['owner']['id'] + deployment = db.query(Deployment).filter_by(id=deployment_request.deployment.id).first() + validate_deployment(deployment, account_id) + + open_dr = db.query(DeploymentRequest).filter( + DeploymentRequest.deployment_id.like(deployment_request.deployment.id), + DeploymentRequest.status.in_( + [DeploymentRequest.STATUSES.pending, DeploymentRequest.STATUSES.processing], + ), + ) + + if db.query(open_dr.exists()).scalar(): + raise ExtensionHttpError.EXT_017() + + ppr = db.query(PPRVersion).filter_by(id=deployment_request.ppr.id).first() + validate_ppr_version_belongs_to_deployment(ppr, deployment) + + dr_marketplaces = [m.id for m in deployment_request.marketplaces.choices] + validate_dr_marketplaces( + dr_marketplaces, + [m.marketplace for m in deployment.marketplaces], + ) + validate_marketplaces_ppr(ppr, dr_marketplaces, deployment.marketplaces) + + instance = add_new_deployment_request( + db, deployment_request, deployment, account_id, logger, + ) + + background_tasks.add_task(main_process, instance.id, config) + + hub = get_client_object(client, 'hubs', instance.deployment.hub_id) + return get_deployment_request_schema(instance, hub) @router.get( '/deployments/requests', @@ -281,20 +343,6 @@ def get_deployments( ) return response_list - @router.post( - '/deployments/requests', - summary='Create a new deployment request', - response_model=DeploymentRequestSchema, - status_code=status.HTTP_201_CREATED, - ) - def add_dep_request(self, db: VerboseBaseSession = Depends(get_db)): - deployment = db.query(Deployment).first() - instance = DeploymentRequest(deployment_id=deployment.id) - db.set_next_verbose(instance, 'deployment') - db.commit() - db.refresh(instance) - return instance - @router.get( '/deployments/{deployment_id}/configurations', summary='List all configuration available for the deployment', @@ -531,7 +579,7 @@ def get_marketplaces_by_deployment( mkplc_configs = db.query(MarketplaceConfiguration).options( selectinload(MarketplaceConfiguration.ppr), - ).filter_by(deployment=deployment_id) + ).filter_by(deployment_id=deployment_id) mkplc_ids = [m.marketplace for m in mkplc_configs] diff --git a/tests/api/test_deployment_requests.py b/tests/api/test_deployment_requests.py index 8eac0c6..12dfd01 100644 --- a/tests/api/test_deployment_requests.py +++ b/tests/api/test_deployment_requests.py @@ -1,8 +1,11 @@ import pytest +from sqlalchemy import null + +from connect_ext_ppr.models.deployment import DeploymentRequest, MarketplaceConfiguration +from connect_ext_ppr.models.task import Task def test_list_deployments_requests( - dbsession, mocker, deployment_factory, deployment_request_factory, @@ -58,13 +61,11 @@ def test_list_deployments_requests( def test_get_deployment_request( - dbsession, mocker, deployment_factory, deployment_request_factory, installation, api_client, - connect_client, ): hub_data = { 'id': 'HB-0000-0001', @@ -115,7 +116,6 @@ def test_get_deployment_request( def test_get_deployment_request_not_found( - dbsession, deployment_factory, deployment_request_factory, installation, @@ -223,3 +223,514 @@ def test_list_deployment_request_tasks_not_found( assert error == { 'error_code': 'EXT_001', 'errors': [f'Object `{bad_dr.id}` not found.'], } + + +def test_create_deployment_request( + mocker, + dbsession, + deployment_factory, + marketplace_config_factory, + ppr_version_factory, + installation, + api_client, +): + hub_data = { + 'id': 'HB-0000-0001', + 'name': 'Another Hub for the best', + } + mocker.patch('connect_ext_ppr.webapp.get_client_object', side_effect=[hub_data]) + + dep = deployment_factory(account_id=installation['owner']['id'], hub_id=hub_data['id']) + ppr = ppr_version_factory(deployment=dep) + + marketplace_config_factory(deployment=dep, marketplace_id='MP-124') + marketplace_config_factory(deployment=dep, marketplace_id='MP-123', ppr_id=ppr.id) + + body = { + 'deployment': {'id': dep.id}, + 'ppr': {'id': ppr.id}, + 'manually': True, + 'delegate_l2': True, + 'marketplaces': { + 'choices': [{'id': 'MP-123'}], + 'all': False, + }, + } + response = api_client.post( + '/api/deployments/requests', + installation=installation, + json=body, + ) + + deployment_request = dbsession.query(DeploymentRequest).first() + + assert response.status_code == 200, response.json() + data = response.json() + events = data.pop('events') + assert data == { + 'id': deployment_request.id, + 'deployment': { + 'id': dep.id, + 'product': { + 'id': dep.product.id, + 'name': dep.product.name, + 'icon': dep.product.logo, + }, + 'hub': hub_data, + }, + 'ppr': { + 'id': ppr.id, + 'version': ppr.version, + }, + 'status': DeploymentRequest.STATUSES.pending.value, + 'manually': True, + 'delegate_l2': True, + } + assert list(events.keys()) == ['created'] + assert list(events['created'].keys()) == ['at', 'by'] + assert events['created']['by'] == installation['owner']['id'] + + assert dbsession.query(MarketplaceConfiguration).filter_by( + marketplace='MP-123', + deployment_request=deployment_request.id, + ).filter( + MarketplaceConfiguration.deployment_id.is_(null()), + MarketplaceConfiguration.ppr_id.is_(null()), + ).count() == 1 + + tasks = dbsession.query(Task).order_by(Task.id) + assert tasks.count() == 3 + assert tasks[0].id == f'TSK-{deployment_request.id[5:]}-000' + assert tasks[0].type == Task.TYPES.ppr_validation + assert tasks[1].id == f'TSK-{deployment_request.id[5:]}-001' + assert tasks[1].type == Task.TYPES.apply_and_delegate + assert tasks[2].id == f'TSK-{deployment_request.id[5:]}-002' + assert tasks[2].type == Task.TYPES.delegate_to_l2 + + +def test_create_deployment_request_without_delegation_to_l2( + mocker, + dbsession, + deployment_factory, + marketplace_config_factory, + ppr_version_factory, + installation, + api_client, +): + hub_data = { + 'id': 'HB-0000-0001', + 'name': 'Another Hub for the best', + } + mocker.patch('connect_ext_ppr.webapp.get_client_object', side_effect=[hub_data]) + + dep = deployment_factory(account_id=installation['owner']['id'], hub_id=hub_data['id']) + ppr = ppr_version_factory(deployment=dep) + + marketplace_config_factory(deployment=dep, marketplace_id='MP-124') + marketplace_config_factory(deployment=dep, marketplace_id='MP-123', ppr_id=ppr.id) + + body = { + 'deployment': {'id': dep.id}, + 'ppr': {'id': ppr.id}, + 'manually': True, + 'delegate_l2': False, + 'marketplaces': { + 'choices': [{'id': 'MP-123'}], + 'all': False, + }, + } + response = api_client.post( + '/api/deployments/requests', + installation=installation, + json=body, + ) + + deployment_request = dbsession.query(DeploymentRequest).first() + + assert response.status_code == 200, response.json() + data = response.json() + events = data.pop('events') + assert data == { + 'id': deployment_request.id, + 'deployment': { + 'id': dep.id, + 'product': { + 'id': dep.product.id, + 'name': dep.product.name, + 'icon': dep.product.logo, + }, + 'hub': hub_data, + }, + 'ppr': { + 'id': ppr.id, + 'version': ppr.version, + }, + 'status': DeploymentRequest.STATUSES.pending.value, + 'manually': True, + 'delegate_l2': False, + } + assert list(events.keys()) == ['created'] + assert list(events['created'].keys()) == ['at', 'by'] + assert events['created']['by'] == installation['owner']['id'] + + tasks = dbsession.query(Task).order_by(Task.id) + assert tasks.count() == 2 + assert tasks[0].id == f'TSK-{deployment_request.id[5:]}-000' + assert tasks[0].type == Task.TYPES.ppr_validation + assert tasks[1].id == f'TSK-{deployment_request.id[5:]}-001' + assert tasks[1].type == Task.TYPES.apply_and_delegate + + +def test_create_deployment_request_with_all_marketplaces( + mocker, + dbsession, + deployment_factory, + marketplace_config_factory, + ppr_version_factory, + installation, + api_client, +): + hub_data = { + 'id': 'HB-0000-0001', + 'name': 'Another Hub for the best', + } + mocker.patch('connect_ext_ppr.webapp.get_client_object', side_effect=[hub_data]) + + dep = deployment_factory(account_id=installation['owner']['id'], hub_id=hub_data['id']) + ppr = ppr_version_factory(deployment=dep) + + marketplace_config_factory(deployment=dep, marketplace_id='MP-124') + marketplace_config_factory(deployment=dep, marketplace_id='MP-123', ppr_id=ppr.id) + + body = { + 'deployment': {'id': dep.id}, + 'ppr': {'id': ppr.id}, + 'manually': True, + 'marketplaces': { + 'choices': [], + 'all': True, + }, + } + response = api_client.post( + '/api/deployments/requests', + installation=installation, + json=body, + ) + + deployment_request = dbsession.query(DeploymentRequest).first() + + assert response.status_code == 200, response.json() + data = response.json() + events = data.pop('events') + assert data == { + 'id': deployment_request.id, + 'deployment': { + 'id': dep.id, + 'product': { + 'id': dep.product.id, + 'name': dep.product.name, + 'icon': dep.product.logo, + }, + 'hub': hub_data, + }, + 'ppr': { + 'id': ppr.id, + 'version': ppr.version, + }, + 'status': DeploymentRequest.STATUSES.pending.value, + 'manually': True, + 'delegate_l2': False, + } + assert list(events.keys()) == ['created'] + assert list(events['created'].keys()) == ['at', 'by'] + assert events['created']['by'] == installation['owner']['id'] + + assert dbsession.query(MarketplaceConfiguration).filter_by( + deployment_request=deployment_request.id, + ).filter(MarketplaceConfiguration.deployment_id.is_(null())).count() == 2 + + +def test_create_deployment_request_invalid_deployment( + deployment_factory, + ppr_version_factory, + installation, + api_client, +): + deployment_factory(account_id=installation['owner']['id']) + dep = deployment_factory(account_id='PA-123-456') + ppr = ppr_version_factory(deployment=dep) + + body = { + 'deployment': {'id': dep.id}, + 'ppr': { + 'id': ppr.id, + }, + 'manually': True, + 'delegate_l2': True, + 'marketplaces': {'all': True}, + } + + response = api_client.post( + '/api/deployments/requests', + installation=installation, + json=body, + ) + + assert response.status_code == 400 + assert response.json()['error_code'] == 'VAL_001' + assert response.json()['errors'] == [f'deployment: {dep.id} not found.'] + + +def test_create_deployment_request_invalid_ppr( + deployment_factory, + ppr_version_factory, + installation, + api_client, +): + dep = deployment_factory(account_id=installation['owner']['id']) + other_dep = deployment_factory(account_id='PA-123-456') + ppr = ppr_version_factory(deployment=other_dep) + + body = { + 'deployment': {'id': dep.id}, + 'ppr': {'id': ppr.id}, + 'manually': True, + 'delegate_l2': True, + 'marketplaces': {'all': True}, + } + + response = api_client.post( + '/api/deployments/requests', + installation=installation, + json=body, + ) + + assert response.status_code == 400 + assert response.json()['error_code'] == 'VAL_001' + assert response.json()['errors'] == [f'ppr: {ppr.id} not found.'] + + +def test_create_deployment_invalid_marketplace( + mocker, + deployment_factory, + marketplace_config_factory, + ppr_version_factory, + installation, + api_client, +): + hub_data = { + 'id': 'HB-0000-0001', + 'name': 'Another Hub for the best', + } + mocker.patch('connect_ext_ppr.webapp.get_client_object', side_effect=[hub_data]) + + dep = deployment_factory(account_id=installation['owner']['id'], hub_id=hub_data['id']) + ppr = ppr_version_factory(deployment=dep) + other_dep = deployment_factory(hub_id=hub_data['id']) + + marketplace_config_factory(deployment=dep, marketplace_id='MP-124') + marketplace_config_factory(deployment=dep, marketplace_id='MP-123', ppr_id=ppr.id) + marketplace_config_factory(deployment=other_dep, marketplace_id='MP-126', ppr_id=ppr.id) + + body = { + 'deployment': {'id': dep.id}, + 'ppr': {'id': ppr.id}, + 'manually': True, + 'delegate_l2': True, + 'marketplaces': { + 'choices': [{'id': 'MP-125'}, {'id': 'MP-123'}, {'id': 'MP-126'}], + 'all': False, + }, + } + response = api_client.post( + '/api/deployments/requests', + installation=installation, + json=body, + ) + + assert response.status_code == 400 + assert response.json()['error_code'] == 'VAL_002', response.json() + assert response.json()['errors'] == [ + 'marketplaces: This values [\'MP-125\', \'MP-126\'] are invalid.', + ] + + +@pytest.mark.parametrize('choices', ([], None)) +def test_create_deployment_invalid_all_false_w_empty_choices( + choices, + mocker, + deployment_factory, + marketplace_config_factory, + ppr_version_factory, + installation, + api_client, +): + hub_data = { + 'id': 'HB-0000-0001', + 'name': 'Another Hub for the best', + } + mocker.patch('connect_ext_ppr.webapp.get_client_object', side_effect=[hub_data]) + + dep = deployment_factory(account_id=installation['owner']['id'], hub_id=hub_data['id']) + ppr = ppr_version_factory(deployment=dep) + other_dep = deployment_factory(account_id=installation['owner']['id'], hub_id=hub_data['id']) + + marketplace_config_factory(deployment=dep, marketplace_id='MP-124') + marketplace_config_factory(deployment=dep, marketplace_id='MP-123', ppr_id=ppr.id) + marketplace_config_factory(deployment=other_dep, marketplace_id='MP-126', ppr_id=ppr.id) + + body = { + 'deployment': {'id': dep.id}, + 'ppr': {'id': ppr.id}, + 'manually': True, + 'delegate_l2': True, + 'marketplaces': { + 'choices': choices, + 'all': False, + }, + } + response = api_client.post( + '/api/deployments/requests', + installation=installation, + json=body, + ) + + assert response.status_code == 400 + assert response.json()['error_code'] == 'VAL_003' + assert response.json()['errors'] == ['At least one choice needs to be specified.'] + + +def test_create_deployment_invalid_all_false_wo_choices( + mocker, + deployment_factory, + marketplace_config_factory, + ppr_version_factory, + installation, + api_client, +): + hub_data = { + 'id': 'HB-0000-0001', + 'name': 'Another Hub for the best', + } + mocker.patch('connect_ext_ppr.webapp.get_client_object', side_effect=[hub_data]) + + dep = deployment_factory(account_id=installation['owner']['id'], hub_id=hub_data['id']) + ppr = ppr_version_factory(deployment=dep) + other_dep = deployment_factory(account_id=installation['owner']['id'], hub_id=hub_data['id']) + + marketplace_config_factory(deployment=dep, marketplace_id='MP-124') + marketplace_config_factory(deployment=dep, marketplace_id='MP-123', ppr_id=ppr.id) + marketplace_config_factory(deployment=other_dep, marketplace_id='MP-126', ppr_id=ppr.id) + + body = { + 'deployment': {'id': dep.id}, + 'ppr': {'id': ppr.id}, + 'manually': True, + 'delegate_l2': True, + 'marketplaces': { + 'all': False, + }, + } + response = api_client.post( + '/api/deployments/requests', + installation=installation, + json=body, + ) + + assert response.status_code == 400 + assert response.json()['error_code'] == 'VAL_003' + assert response.json()['errors'] == ['At least one choice needs to be specified.'] + + +def test_create_deployment_invalid_ppr_for_marketplace( + mocker, + deployment_factory, + marketplace_config_factory, + ppr_version_factory, + file_factory, + installation, + api_client, +): + hub_data = { + 'id': 'HB-0000-0001', + 'name': 'Another Hub for the best', + } + mocker.patch('connect_ext_ppr.webapp.get_client_object', side_effect=[hub_data]) + + dep = deployment_factory(account_id=installation['owner']['id'], hub_id=hub_data['id']) + ppr = ppr_version_factory(deployment=dep, version=1, id='PPRFL-123') + ppr_file = file_factory(id='FL-123') + ppr2 = ppr_version_factory(deployment=dep, version=2, id='PPRFL-124', file=ppr_file.id) + + marketplace_config_factory(deployment=dep, marketplace_id='MP-124') + marketplace_config_factory(deployment=dep, marketplace_id='MP-123', ppr_id=ppr2.id) + marketplace_config_factory(deployment=dep, marketplace_id='MP-126', ppr_id=ppr.id) + + body = { + 'deployment': {'id': dep.id}, + 'ppr': {'id': ppr.id}, + 'manually': True, + 'delegate_l2': True, + 'marketplaces': { + 'choices': [{'id': 'MP-123'}, {'id': 'MP-126'}, {'id': 'MP-124'}], + 'all': False, + }, + } + response = api_client.post( + '/api/deployments/requests', + installation=installation, + json=body, + ) + + assert response.status_code == 400 + assert response.json()['error_code'] == 'VAL_004', response.json() + assert response.json()['errors'] == [ + 'Cannot applied PPR to marketplaces [\'MP-123\'].', + ] + + +def test_create_deployment_request_w_open_request( + mocker, + deployment_factory, + deployment_request_factory, + marketplace_config_factory, + ppr_version_factory, + file_factory, + installation, + api_client, +): + hub_data = { + 'id': 'HB-0000-0001', + 'name': 'Another Hub for the best', + } + mocker.patch('connect_ext_ppr.webapp.get_client_object', side_effect=[hub_data]) + + dep = deployment_factory(account_id=installation['owner']['id'], hub_id=hub_data['id']) + deployment_request_factory(deployment=dep, status='pending') + ppr = ppr_version_factory(deployment=dep, version=1, id='PPRFL-123') + ppr_file = file_factory(id='FL-123') + ppr2 = ppr_version_factory(deployment=dep, version=2, id='PPRFL-124', file=ppr_file.id) + + marketplace_config_factory(deployment=dep, marketplace_id='MP-123', ppr_id=ppr2.id) + + body = { + 'deployment': {'id': dep.id}, + 'ppr': {'id': ppr.id}, + 'manually': True, + 'delegate_l2': True, + 'marketplaces': { + 'choices': [{'id': 'MP-123'}], + 'all': False, + }, + } + response = api_client.post( + '/api/deployments/requests', + installation=installation, + json=body, + ) + + assert response.status_code == 400 + assert response.json()['error_code'] == 'EXT_017', response.json() + assert response.json()['errors'] == [ + 'Cannot create a new request, an open one already exists.', + ] diff --git a/tests/conftest.py b/tests/conftest.py index 4f08e39..f675b35 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -185,7 +185,8 @@ def _build_task( if not deployment_request: deployment_request = deployment_request_factory() - task_id = f'TSK-{deployment_request.id[4:]}-{task_index}' + _, suffix = deployment_request.id.split('-', 1) + task_id = f'TSK-{suffix}-{task_index}' task = Task( id=task_id, deployment_request=deployment_request.id, @@ -266,10 +267,10 @@ def _build_file( @pytest.fixture -def marketplace_config_factory(dbsession, ppr_version_factory): +def marketplace_config_factory(dbsession): def _build_mc(deployment, marketplace_id, ppr_id=None): mp = MarketplaceConfiguration( - deployment=deployment.id, + deployment_id=deployment.id, marketplace=marketplace_id, ppr_id=ppr_id, ) diff --git a/tests/models.py/test_deployment.py b/tests/models.py/test_deployment.py index 473fab7..dd6da03 100644 --- a/tests/models.py/test_deployment.py +++ b/tests/models.py/test_deployment.py @@ -4,6 +4,7 @@ from connect_ext_ppr.db import VerboseSessionError from connect_ext_ppr.models.deployment import Deployment, DeploymentRequest from connect_ext_ppr.models.replicas import Product +from connect_ext_ppr.models.task import Task def _get_id_prefix_or_body(id_: str, idx: int): @@ -130,3 +131,35 @@ def test_validate_unique_constraint_deployment(dbsession, deployment): assert ( 'duplicate key value violates unique constraint "prd_account_hub_key"' in exc.value.args[0] ) + + +@pytest.mark.parametrize( + 'initial_tasks_count', + (0, 1), +) +def test_generate_all_next_verbose_id( + dbsession, + deployment_factory, + deployment_request_factory, + initial_tasks_count, + task_factory, +): + dep = deployment_factory() + dr = deployment_request_factory(deployment=dep) + + for index in range(initial_tasks_count): + task_factory(deployment_request=dr, task_index=f'00{index}') + + tasks = [] + tasks.append(Task(deployment_request=dr.id)) + tasks.append(Task(deployment_request=dr.id)) + + dbsession.set_all_next_verbose(tasks, 'deployment_request') + dbsession.commit() + + _, suffix = dr.id.split('-', 1) + index = initial_tasks_count + for task in tasks: + dbsession.refresh(task) + assert f'TSK-{suffix}-00{index}' == task.id + index += 1 diff --git a/tests/test_service.py b/tests/test_service.py index 48ba209..35a72e0 100644 --- a/tests/test_service.py +++ b/tests/test_service.py @@ -63,7 +63,7 @@ def test_add_mutiples_deployments( new_dep = dbsession.query(Deployment).filter_by(hub_id=hub_id).first() assert new_dep is not None assert dbsession.query(MarketplaceConfiguration).filter_by( - deployment=new_dep.id, + deployment_id=new_dep.id, marketplace=marketplace_id, ).filter(MarketplaceConfiguration.id.is_not(null())).count() == 1 diff --git a/tests/test_tasks_manager.py b/tests/test_tasks_manager.py index 20ce030..371be15 100644 --- a/tests/test_tasks_manager.py +++ b/tests/test_tasks_manager.py @@ -17,23 +17,19 @@ ) -@pytest.mark.asyncio -async def test_apply_ppr_and_delegate_to_marketplaces(): - assert await apply_ppr_and_delegate_to_marketplaces() +def test_apply_ppr_and_delegate_to_marketplaces(): + assert apply_ppr_and_delegate_to_marketplaces() -@pytest.mark.asyncio -async def test_delegate_to_l2(): - assert await delegate_to_l2() +def test_delegate_to_l2(): + assert delegate_to_l2() -@pytest.mark.asyncio -async def test_validate_ppr(): - assert await validate_ppr() +def test_validate_ppr(): + assert validate_ppr() -@pytest.mark.asyncio -async def test_main_process( +def test_main_process( dbsession, deployment_factory, deployment_request_factory, @@ -46,7 +42,7 @@ async def test_main_process( task_factory(deployment_request=dr, task_index='0001', type=TaskTypesChoices.ppr_validation) task_factory(deployment_request=dr, task_index='0002', type=TaskTypesChoices.apply_and_delegate) task_factory(deployment_request=dr, task_index='0003', type=TaskTypesChoices.delegate_to_l2) - assert await main_process(dr.id, {}) == DeploymentRequestStatusChoices.done + assert main_process(dr.id, {}) == DeploymentRequestStatusChoices.done assert dbsession.query(Deployment).filter_by(status=DeploymentStatusChoices.synced).count() == 1 assert dbsession.query(DeploymentRequest).filter_by( @@ -59,8 +55,7 @@ async def test_main_process( ).count() == 3 -@pytest.mark.asyncio -async def test_main_process_wo_l2_delegation( +def test_main_process_wo_l2_delegation( dbsession, deployment_factory, deployment_request_factory, @@ -72,7 +67,7 @@ async def test_main_process_wo_l2_delegation( dr = deployment_request_factory(deployment=dep, delegate_l2=False, ppr=ppr) task_factory(deployment_request=dr, task_index='0001', type=TaskTypesChoices.ppr_validation) task_factory(deployment_request=dr, task_index='0002', type=TaskTypesChoices.apply_and_delegate) - assert await main_process(dr.id, {}) == DeploymentRequestStatusChoices.done + assert main_process(dr.id, {}) == DeploymentRequestStatusChoices.done assert dbsession.query(Deployment).filter_by( status=DeploymentStatusChoices.pending, @@ -87,8 +82,7 @@ async def test_main_process_wo_l2_delegation( ).count() == 2 -@pytest.mark.asyncio -async def test_main_process_deployment_w_new_ppr_version( +def test_main_process_deployment_w_new_ppr_version( dbsession, file_factory, deployment_factory, @@ -96,16 +90,16 @@ async def test_main_process_deployment_w_new_ppr_version( task_factory, ppr_version_factory, ): - file = file_factory(id='MFL-123') + ppr_file = file_factory(id='MFL-123') dep = deployment_factory() dr_ppr = ppr_version_factory( - id='PPR-1234', file=file.id, product_version=1, deployment=dep) + id='PPR-1234', file=ppr_file.id, product_version=1, deployment=dep) ppr_version_factory(id='PPR-123', product_version=2, deployment=dep) dr = deployment_request_factory(deployment=dep, delegate_l2=False, ppr=dr_ppr) task_factory(deployment_request=dr, task_index='0001', type=TaskTypesChoices.ppr_validation) task_factory(deployment_request=dr, task_index='0002', type=TaskTypesChoices.apply_and_delegate) task_factory(deployment_request=dr, task_index='0003', type=TaskTypesChoices.delegate_to_l2) - assert await main_process(dr.id, {}) == DeploymentRequestStatusChoices.done + assert main_process(dr.id, {}) == DeploymentRequestStatusChoices.done assert dbsession.query(Deployment).filter_by( status=DeploymentStatusChoices.pending, @@ -120,7 +114,6 @@ async def test_main_process_deployment_w_new_ppr_version( ).count() == 3 -@pytest.mark.asyncio @pytest.mark.parametrize( ('type_function_to_mock', 'done_tasks', 'tasks_w_errors', 'pending_tasks'), ( @@ -129,7 +122,7 @@ async def test_main_process_deployment_w_new_ppr_version( (TaskTypesChoices.delegate_to_l2, 2, 1, 0), ), ) -async def test_main_process_ends_w_error( +def test_main_process_ends_w_error( dbsession, deployment_factory, deployment_request_factory, @@ -148,17 +141,14 @@ async def test_main_process_ends_w_error( task_factory(deployment_request=dr, task_index='0002', type=TaskTypesChoices.apply_and_delegate) task_factory(deployment_request=dr, task_index='0003', type=TaskTypesChoices.delegate_to_l2) - def mock_dict_get(key): - if key == type_function_to_mock: - return mocker.AsyncMock(return_value=False) - return mocker.AsyncMock(return_value=True) + my_mock = mocker.Mock() - my_mock = mocker.AsyncMock() - my_mock.get = mock_dict_get - import connect_ext_ppr - connect_ext_ppr.tasks_manager.TASK_PER_TYPE = my_mock + def mock_get(key): + return lambda: key != type_function_to_mock + my_mock.get = mock_get - assert await main_process(dr.id, {}) == DeploymentRequestStatusChoices.error + mocker.patch('connect_ext_ppr.tasks_manager.TASK_PER_TYPE', my_mock) + assert main_process(dr.id, {}) == DeploymentRequestStatusChoices.error assert dbsession.query(Deployment).filter_by( status=DeploymentStatusChoices.pending, @@ -184,7 +174,6 @@ def mock_dict_get(key): ).count() == pending_tasks -@pytest.mark.asyncio @pytest.mark.parametrize( ('task_statuses', 'done_tasks', 'aborted_tasks'), ( @@ -205,7 +194,7 @@ def mock_dict_get(key): ), ), ) -async def test_main_process_w_aborted_tasks( +def test_main_process_w_aborted_tasks( dbsession, deployment_factory, deployment_request_factory, @@ -254,7 +243,7 @@ def change_dr_status(instance, attribute_names=None, with_for_update=None): dbsession.refresh = change_dr_status - assert await main_process(dr.id, {}) == DeploymentRequestStatusChoices.aborted + assert main_process(dr.id, {}) == DeploymentRequestStatusChoices.aborted assert dbsession.query(Deployment).filter_by( status=DeploymentStatusChoices.pending, @@ -271,8 +260,7 @@ def change_dr_status(instance, attribute_names=None, with_for_update=None): ).count() == aborted_tasks -@pytest.mark.asyncio -async def test_main_process_w_aborted_deployment_request( +def test_main_process_w_aborted_deployment_request( dbsession, deployment_factory, deployment_request_factory, @@ -311,7 +299,7 @@ async def test_main_process_w_aborted_deployment_request( status=TasksStatusChoices.aborted, ) - assert await main_process(dr.id, {}) == DeploymentRequestStatusChoices.aborted + assert main_process(dr.id, {}) == DeploymentRequestStatusChoices.aborted assert dbsession.query(Deployment).filter_by( status=DeploymentStatusChoices.pending, @@ -323,3 +311,66 @@ async def test_main_process_w_aborted_deployment_request( assert dbsession.query(Task).filter( Task.status == TasksStatusChoices.aborted, ).count() == 3 + + +@pytest.mark.parametrize( + ('type_function_to_mock', 'done_tasks', 'tasks_w_errors', 'pending_tasks'), + ( + (TaskTypesChoices.ppr_validation, 0, 1, 2), + (TaskTypesChoices.apply_and_delegate, 1, 1, 1), + (TaskTypesChoices.delegate_to_l2, 2, 1, 0), + ), +) +def test_main_process_ends_w_task_exception( + dbsession, + deployment_factory, + deployment_request_factory, + done_tasks, + tasks_w_errors, + pending_tasks, + type_function_to_mock, + mocker, + task_factory, + ppr_version_factory, +): + dep = deployment_factory() + ppr = ppr_version_factory(id='PPR-123', product_version=1, deployment=dep, version=1) + dr = deployment_request_factory(deployment=dep, delegate_l2=True, ppr=ppr) + task_factory(deployment_request=dr, task_index='0001', type=TaskTypesChoices.ppr_validation) + task_factory(deployment_request=dr, task_index='0002', type=TaskTypesChoices.apply_and_delegate) + task_factory(deployment_request=dr, task_index='0003', type=TaskTypesChoices.delegate_to_l2) + + my_mock = mocker.Mock() + + def mock_get(key): + if key == type_function_to_mock: + raise Exception('Unexpected Error') + return lambda: True + + my_mock.get = mock_get + + mocker.patch('connect_ext_ppr.tasks_manager.TASK_PER_TYPE', my_mock) + assert main_process(dr.id, {}) == DeploymentRequestStatusChoices.error + + assert dbsession.query(Deployment).filter_by( + status=DeploymentStatusChoices.pending, + ).count() == 1 + assert dbsession.query(DeploymentRequest).filter_by( + status=DeploymentRequestStatusChoices.error, + ).count() == 1 + + assert dbsession.query(Task).filter( + Task.status == TasksStatusChoices.done, + Task.started_at.is_not(null()), + Task.finished_at.is_not(null()), + ).count() == done_tasks + assert dbsession.query(Task).filter( + Task.status == TasksStatusChoices.error, + Task.started_at.is_not(null()), + Task.finished_at.is_not(null()), + ).count() == tasks_w_errors + assert dbsession.query(Task).filter( + Task.status == TasksStatusChoices.pending, + Task.started_at.is_(null()), + Task.finished_at.is_(null()), + ).count() == pending_tasks