3069-client.shelving #1029

Merged
joan merged 16 commits from 3069-client.shelving into dev 2022-08-05 09:18:56 +00:00
38 changed files with 1006 additions and 0 deletions
Showing only changes of commit f00fb0dc3f - Show all commits

View File

@ -18,6 +18,7 @@
"modules/supplier/front/**/*",
"modules/ticket/front/**/*",
"modules/travel/front/**/*",
"modules/shelving/front/**/*",
"modules/worker/front/**/*",
"modules/zone/front/**/*"
]

View File

@ -21,6 +21,7 @@ export default function moduleImport(moduleName) {
case 'entry' : return import('entry/front');
case 'account' : return import('account/front');
case 'supplier' : return import('supplier/front');
case 'shelving' : return import('shelving/front');
case 'monitor' : return import('monitor/front');
}
}

View File

@ -13,6 +13,7 @@ import './modules/route/front/module.js';
import './modules/ticket/front/module.js';
import './modules/travel/front/module.js';
import './modules/worker/front/module.js';
import './modules/shelving/front/module.js';
core.run(vnInterceptor => {
vnInterceptor.setApiPath(null);

View File

@ -0,0 +1,52 @@
module.exports = Self => {
Self.remoteMethod('getSummary', {
description: 'Returns the shelving summary',
accessType: 'READ',
accepts: {
arg: 'code',
type: 'string',
required: true,
description: 'The shelving code',
http: {source: 'path'}
},
returns: {
type: 'object',
root: true
},
http: {
path: `/:code/getSummary`,
verb: 'GET'
}
});
Self.getSummary = async code => {
let filter = {
where: {code: code},
fields: [
'code',
'parkingFk',
'priority',
'userFk',
'isRecyclable'
],
include: [
{
relation: 'parking'
},
{
relation: 'worker',
scope: {
fields: ['id', 'userFk'],
include: {
relation: 'user',
scope: {
fields: ['id', 'nickname']
}
}
}
}
]
};
return Self.app.models.Shelving.findOne(filter);
};
};

View File

@ -0,0 +1,8 @@
{
"Parking": {
"dataSource": "vn"
},
"Shelving": {
"dataSource": "vn"
}
}

View File

@ -0,0 +1,33 @@
{
"name": "Parking",
"base": "VnModel",
"options": {
"mysql": {
"table": "parking"
}
},
"properties": {
"id": {
"type": "number",
"id": true,
"description": "Identifier"
},
"column": {
"type": "string",
"required": true
},
"row": {
"type": "string",
"required": true
},
"sectorFk": {
"type": "number"
},
"code": {
"type": "string"
},
"pickingOrder": {
"type": "number"
}
}
}

View File

@ -0,0 +1,3 @@
module.exports = Self => {
require('../methods/shelving/getSummary')(Self);
};

View File

@ -0,0 +1,48 @@
{
"name": "Shelving",
"base": "VnModel",
"options": {
"mysql": {
"table": "shelving"
}
},
"properties": {
"id": {
"type": "string",
"id": true,
"description": "Identifier",
"mysql": {
"columnName": "code"
}
},
"parkingFk": {
"type": "number",
"required": true
},
"isPrinted": {
"type": "boolean",
"required": true
},
"priority": {
"type": "number"
},
"userFk": {
"type": "number"
},
"isRecyclable": {
"type": "boolean"
}
},
"relations": {
"parking": {
"type": "belongsTo",
"model": "Parking",
"foreignKey": "parkingFk"
},
"worker": {
"type": "belongsTo",
"model": "Worker",
"foreignKey": "userFk"
}
}
}

View File

@ -0,0 +1,52 @@
<mg-ajax path="Shelvings/{{patch.params.id}}" options="vnPatch"></mg-ajax>
<vn-watcher
vn-id="watcher"
data="$ctrl.shelving"
form="form"
save="patch">
</vn-watcher>
<form name="form" ng-submit="watcher.submit()" class="vn-w-md">
<vn-card class="vn-pa-lg">
<vn-vertical>
<vn-horizontal>
<vn-textfield
label="Code"
ng-model="$ctrl.shelving.id"
rule
vn-focus>
</vn-textfield>
<vn-autocomplete
vn-one
url="Parkings"
label="Parking"
show-field="id"
value-field="id"
ng-model="$ctrl.shelving.parkingFk">
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-textfield
label="Priority"
ng-model="$ctrl.shelving.priority"
rule>
</vn-textfield>
<vn-check
label="Recyclable"
ng-model="$ctrl.shelving.isRecyclable">
</vn-check>
</vn-horizontal>
</vn-vertical>
</vn-card>
<vn-button-bar>
<vn-submit
disabled="!watcher.dataChanged()"
label="Save">
</vn-submit>
<vn-button
class="cancel"
label="Undo changes"
disabled="!watcher.dataChanged()"
ng-click="watcher.loadOriginalData()">
</vn-button>
</vn-button-bar>
</form>

View File

@ -0,0 +1,10 @@
import ngModule from '../module';
import Section from 'salix/components/section';
ngModule.vnComponent('vnShelvingBasicData', {
template: require('./index.html'),
controller: Section,
bindings: {
shelving: '<'
}
});

View File

@ -0,0 +1,5 @@
Notes: Notas
Active: Activo
Verified: Verificado
PayMethodChecked: Método de pago validado
Responsible for approving invoices: Responsable de aprobar las facturas

View File

@ -0,0 +1,8 @@
<vn-portal slot="menu">
<vn-shelving-descriptor
shelving="$ctrl.shelving"
on-change="$ctrl.reload()">
</vn-shelving-descriptor>
<vn-left-menu source="card"></vn-left-menu>
</vn-portal>
<ui-view></ui-view>

View File

@ -0,0 +1,29 @@
import ngModule from '../module';
import ModuleCard from 'salix/components/module-card';
class Controller extends ModuleCard {
reload() {
const filter = {
include: [
{relation: 'worker',
scope: {
fields: ['userFk'],
include: {
relation: 'user',
scope: {
fields: ['nickname']
}
}
}},
{relation: 'parking'}
]
};
this.$http.get(`Shelvings/${this.$params.id}`, {filter})
.then(res => this.shelving = res.data);
}
}
ngModule.vnComponent('vnShelvingCard', {
template: require('./index.html'),
controller: Controller
});

View File

@ -0,0 +1,30 @@
<vn-watcher
vn-id="watcher"
url="Shelvings"
data="$ctrl.shelving"
insert-mode="true"
form="form">
</vn-watcher>
<form name="form" vn-http-submit="$ctrl.onSubmit()" class="vn-w-md">
<vn-card class="vn-pa-lg">
<vn-vertical>
<vn-textfield
label="Code"
ng-model="$ctrl.shelving.id"
rule
vn-focus>
</vn-textfield>
</vn-vertical>
</vn-card>
<vn-button-bar>
<vn-submit
disabled="!watcher.dataChanged()"
label="Create">
</vn-submit>
<vn-button
class="cancel"
label="Cancel"
ui-sref="shelving.index">
</vn-button>
</vn-button-bar>
</form>

View File

@ -0,0 +1,15 @@
import ngModule from '../module';
import Section from 'salix/components/section';
export default class Controller extends Section {
onSubmit() {
return this.$.watcher.submit().then(res =>
this.$state.go('shelving.card.basicData', {id: res.data.id})
);
}
}
ngModule.vnComponent('vnShelvingCreate', {
template: require('./index.html'),
controller: Controller
});

View File

@ -0,0 +1,122 @@
import './index';
describe('Client', () => {
describe('Component vnClientCreate', () => {
vicent marked this conversation as resolved
Review

fdescribe

fdescribe
let $scope;
let $state;
let controller;
beforeEach(ngModule('client'));
beforeEach(inject(($componentController, $rootScope, _$state_) => {
$scope = $rootScope.$new();
$state = _$state_;
$scope.watcher = {
submit: () => {
return {
then: callback => {
callback({data: {id: '1234'}});
}
};
}
};
const $element = angular.element('<vn-client-create></vn-client-create>');
controller = $componentController('vnClientCreate', {$element, $scope});
}));
vicent marked this conversation as resolved
Review

de donde sale la id 1234? este test es raro

de donde sale la id 1234? este test es raro
it('should define and set scope, state and client properties', () => {
expect(controller.$).toBe($scope);
expect(controller.$state).toBe($state);
expect(controller.client.active).toBe(true);
});
describe('onSubmit()', () => {
it(`should call submit() on the watcher then expect a callback`, () => {
jest.spyOn($state, 'go');
controller.onSubmit();
expect(controller.$state.go).toHaveBeenCalledWith('client.card.basicData', {id: '1234'});
});
});
describe('province() setter', () => {
it(`should set countryFk property`, () => {
controller.client.countryFk = null;
controller.province = {
id: 1,
name: 'New york',
country: {
id: 2,
name: 'USA'
}
};
expect(controller.client.countryFk).toEqual(2);
});
});
describe('town() setter', () => {
it(`should set provinceFk property`, () => {
controller.town = {
provinceFk: 1,
code: 46001,
province: {
id: 1,
name: 'New york',
country: {
id: 2,
name: 'USA'
}
},
postcodes: []
};
expect(controller.client.provinceFk).toEqual(1);
});
it(`should set provinceFk property and fill the postalCode if there's just one`, () => {
controller.town = {
provinceFk: 1,
code: 46001,
province: {
id: 1,
name: 'New york',
country: {
id: 2,
name: 'USA'
}
},
postcodes: [{code: '46001'}]
};
expect(controller.client.provinceFk).toEqual(1);
expect(controller.client.postcode).toEqual('46001');
});
});
describe('postcode() setter', () => {
it(`should set the town, provinceFk and contryFk properties`, () => {
controller.postcode = {
townFk: 1,
code: 46001,
town: {
id: 1,
name: 'New York',
province: {
id: 1,
name: 'New york',
country: {
id: 2,
name: 'USA'
}
}
}
};
expect(controller.client.city).toEqual('New York');
expect(controller.client.provinceFk).toEqual(1);
expect(controller.client.countryFk).toEqual(2);
});
});
});
});

View File

@ -0,0 +1,11 @@
Name: Nombre
Tax number: NIF/CIF
Business name: Razón social
Web user: Usuario Web
Email: E-mail
Create and edit: Crear y editar
You can save multiple emails: >-
Puede guardar varios correos electrónicos encadenándolos mediante comas
sin espacios, ejemplo: user@dominio.com, user2@dominio.com siendo el primer
correo electrónico el principal
The type of business must be filled in basic data: El tipo de negocio debe estar rellenado en datos básicos

View File

@ -0,0 +1,45 @@
<vn-descriptor-content
module="shelving"
description="$ctrl.shelving.id"
summary="$ctrl.$.summary">
<slot-menu>
<vn-item
ng-click="deleteShelving.show()"
name="deleteShelving"
translate>
Delete
</vn-item>
</slot-menu>
<slot-body>
<div class="attributes">
<vn-label-value
label="Code"
value="{{$ctrl.shelving.id}}">
</vn-label-value>
<vn-label-value
label="Parking"
value="{{$ctrl.shelving.parking.code}}">
</vn-label-value>
<vn-label-value
label="Worker">
<span
ng-click="workerDescriptor.show($event, $ctrl.shelving.userFk)"
class="link">
{{::$ctrl.shelving.worker.user.nickname}}
</span>
</vn-label-value>
</div>
</slot-body>
</vn-descriptor-content>
<vn-confirm
vn-id="delete-shelving"
on-accept="$ctrl.onDelete()"
question="Are you sure you want to continue?"
message="Shelving will be removed">
</vn-confirm>
<vn-popup vn-id="summary">
<vn-shelving-summary shelving="$ctrl.shelving"></vn-shelving-summary>
</vn-popup>
<vn-worker-descriptor-popover
vn-id="workerDescriptor">
</vn-worker-descriptor-popover>

View File

@ -0,0 +1,66 @@
import ngModule from '../module';
import Descriptor from 'salix/components/descriptor';
class Controller extends Descriptor {
get shelving() {
return this.entity;
}
set shelving(value) {
this.entity = value;
}
onDelete() {
return this.$http.delete(`Shelvings/${this.shelving.id}`)
.then(() => this.$state.go('shelving.index'))
.then(() => this.vnApp.showSuccess(this.$t('Shelving removed')));
}
// loadData() {
// const filter = {
// fields: [
// 'id',
// 'name',
// 'nickname',
// 'nif',
// 'payMethodFk',
// 'payDemFk',
// 'payDay',
// 'isActive',
// 'isSerious',
// 'account'
// ],
// include: [
// {
// relation: 'payMethod',
// scope: {
// fields: ['id', 'name']
// }
// },
// {
// relation: 'payDem',
// scope: {
// fields: ['id', 'payDem']
// }
// },
// {
// relation: 'client',
// scope: {
// fields: ['id', 'fi']
// }
// }
// ]
// };
// return this.getData(`Suppliers/${this.id}`, {filter})
// .then(res => this.supplier = res.data);
// }
}
ngModule.vnComponent('vnShelvingDescriptor', {
template: require('./index.html'),
controller: Controller,
bindings: {
shelving: '<'
}
});

View File

@ -0,0 +1,64 @@
import './index.js';
describe('Supplier Component vnSupplierDescriptor', () => {
let $httpBackend;
let controller;
let $httpParamSerializer;
const supplier = {id: 1};
beforeEach(ngModule('supplier'));
beforeEach(inject(($componentController, _$httpBackend_, _$httpParamSerializer_) => {
$httpBackend = _$httpBackend_;
$httpParamSerializer = _$httpParamSerializer_;
controller = $componentController('vnSupplierDescriptor', {$element: null}, {supplier});
}));
describe('loadData()', () => {
it('should perform ask for the supplier', () => {
const filter = {
fields: [
'id',
'name',
'nickname',
'nif',
'payMethodFk',
'payDemFk',
'payDay',
'isActive',
'isSerious',
'account'
],
include: [
{
relation: 'payMethod',
scope: {
fields: ['id', 'name']
}
},
{
relation: 'payDem',
scope: {
fields: ['id', 'payDem']
}
},
{
relation: 'client',
scope: {
fields: ['id', 'fi']
}
}
]
};
const serializedParams = $httpParamSerializer({filter});
let query = `Suppliers/${controller.supplier.id}?${serializedParams}`;
jest.spyOn(controller, 'getData');
$httpBackend.expect('GET', query).respond({id: 1});
controller.loadData();
$httpBackend.flush();
expect(controller.getData).toHaveBeenCalledTimes(1);
});
});
});

View File

@ -0,0 +1,7 @@
Tax number: NIF / CIF
All entries with current supplier: Todas las entradas con el proveedor actual
Go to client: Ir al cliente
Verified supplier: Proveedor verificado
Unverified supplier: Proveedor no verificado
Inactive supplier: Proveedor inactivo
Create invoiceIn: Crear factura recibida

View File

@ -0,0 +1,10 @@
export * from './module';
import './basic-data';
import './card';
import './create';
import './descriptor';
import './index/';
import './main';
import './search-panel';
import './summary';

View File

@ -0,0 +1,43 @@
<vn-auto-search
model="model">
</vn-auto-search>
<vn-data-viewer
model="model"
class="vn-w-sm">
<vn-card>
<div class="vn-list separated">
<a
ng-repeat="shelving in model.data track by shelving.id"
ui-sref="shelving.card.summary(::{id: shelving.id})"
translate-attr="{title: 'View shelving'}"
class="vn-item search-result">
<vn-item-section>
<h6>{{::shelving.id}}</h6>
<div>{{::shelving.parking.code}}</div>
<div>{{::shelving.priority}}</div>
</vn-item-section>
<vn-item-section side>
<vn-icon-button
vn-click-stop="$ctrl.preview(shelving)"
vn-tooltip="Preview"
icon="preview">
</vn-icon-button>
</vn-item-section>
</a>
</div>
</vn-card>
</vn-data-viewer>
<vn-popup vn-id="summary">
<vn-shelving-summary
shelving="$ctrl.selectedShelving">
</vn-shelving-summary>
</vn-popup>
<a
ui-sref="shelving.create"
vn-tooltip="New shelving"
vn-bind="+"
vn-acl-action="remove"
fixed-bottom-right>
<vn-float-button icon="add"></vn-float-button>
</a>

View File

@ -0,0 +1,14 @@
import ngModule from '../module';
import Section from 'salix/components/section';
export default class Controller extends Section {
preview(shelving) {
this.selectedShelving = shelving;
this.$.summary.show();
}
}
ngModule.vnComponent('vnShelvingIndex', {
template: require('./index.html'),
controller: Controller
});

View File

@ -0,0 +1,5 @@
Payment deadline: Plazo de pago
Pay day: Dia de pago
Account: Cuenta
Pay method: Metodo de pago
Tax number: Nif

View File

@ -0,0 +1 @@
Accounts: Cuentas

View File

@ -0,0 +1,18 @@
<vn-crud-model
vn-id="model"
url="Shelvings"
filter="$ctrl.filter"
limit="20">
</vn-crud-model>
<vn-portal slot="topbar">
<vn-searchbar
panel="vn-shelving-search-panel"
info="Search shelving by code"
model="model"
expr-builder="$ctrl.exprBuilder(param, value)">
</vn-searchbar>
</vn-portal>
<vn-portal slot="menu">
<vn-left-menu></vn-left-menu>
</vn-portal>
<ui-view></ui-view>

View File

@ -0,0 +1,33 @@
import ngModule from '../module';
import ModuleMain from 'salix/components/module-main';
export default class Shelving extends ModuleMain {
constructor($element, $) {
super($element, $);
this.filter = {
include: [
{relation: 'parking'}
],
};
}
$onInit() {
console.log(this.$params);
}
exprBuilder(param, value) {
switch (param) {
case 'search':
return {id: {like: `%${value}%`}};
case 'parkingFk':
case 'userFk':
case 'isRecyclable':
return {[param]: value};
}
}
}
ngModule.vnComponent('vnShelving', {
controller: Shelving,
template: require('./index.html')
});

View File

@ -0,0 +1,3 @@
import {ng} from 'core/vendor';
export default ng.module('shelving', ['salix']);

View File

@ -0,0 +1,71 @@
{
"module": "shelving",
"name": "Shelvings",
"icon" : "contact_support",
"dependencies": [],
"validations" : true,
"menus": {
"main": [
{"state": "shelving.index", "icon": "contact_support"}
],
"card": [
{"state": "shelving.card.basicData", "icon": "settings"},
{"state": "shelving.card.log", "icon": "history"}
]
},
"keybindings": [
{"key": "s", "state": "shelving.index"}
],
"routes": [
{
"url": "/shelving",
"state": "shelving",
"abstract": true,
"component": "vn-shelving",
"description": "Shelvings"
},
{
"url": "/index?q",
"state": "shelving.index",
"component": "vn-shelving-index",
"description": "Shelvings"
},
{
"url": "/create",
"state": "shelving.create",
"component": "vn-shelving-create",
"description": "New shelving"
},
{
"url": "/:id",
"state": "shelving.card",
"abstract": true,
"component": "vn-shelving-card"
},
{
"url": "/summary",
"state": "shelving.card.summary",
"component": "vn-shelving-summary",
"description": "Summary",
"params": {
"shelving": "$ctrl.shelving"
}
},
{
"url": "/basic-data",
"state": "shelving.card.basicData",
"component": "vn-shelving-basic-data",
"description": "Basic data",
"acl": ["administrative"],
vicent marked this conversation as resolved
Review

Administrative es el ACL correcto?
Ha de etar solo basicData con ACL?

Administrative es el ACL correcto? Ha de etar solo basicData con ACL?
"params": {
"shelving": "$ctrl.shelving"
}
},
{
"url" : "/log",
"state": "shelving.card.log",
"component": "vn-shelving-log",
"description": "Log"
}
]
}

View File

@ -0,0 +1,43 @@
<div class="search-panel">
<form ng-submit="$ctrl.onSearch()">
<vn-horizontal>
<vn-textfield
vn-one
label="General search"
ng-model="filter.search"
info="Search shelvings by code"
vn-focus>
</vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-autocomplete
vn-one
url="Parkings"
label="Parking"
show-field="code"
value-field="id"
ng-model="filter.parkingFk">
</vn-autocomplete>
<vn-autocomplete
vn-one
url="Workers"
label="Worker"
search-function="{or: [{id: $search}, {firstName: {like: $search}}]}"
show-field="firstName"
value-field="id"
ng-model="filter.userFk">
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-check
vn-one
label="Recyclable"
ng-model="filter.isRecyclable"
triple-state="true">
</vn-check>
</vn-horizontal>
<vn-horizontal class="vn-mt-lg">
<vn-submit label="Search"></vn-submit>
</vn-horizontal>
</form>
</div>

View File

@ -0,0 +1,7 @@
import ngModule from '../module';
import SearchPanel from 'core/components/searchbar/search-panel';
ngModule.vnComponent('vnShelvingSearchPanel', {
template: require('./index.html'),
controller: SearchPanel
});

View File

@ -0,0 +1,4 @@
Province: Provincia
Country: País
Tax number: NIF / CIF
Search suppliers by id, name or alias: Busca proveedores por id, nombre o alias

View File

@ -0,0 +1,51 @@
<vn-card class="summary">
<h5>
<a ng-if="::$ctrl.summary.id"
vn-tooltip="Go to the shelving"
ui-sref="shelving.card.summary({id: {{::$ctrl.summary.id}}})"
name="goToSummary">
<vn-icon-button icon="launch"></vn-icon-button>
</a>
<span>{{::$ctrl.summary.id}}</span>
</h5>
<vn-horizontal>
<vn-one>
<h4>
<a
ui-sref="shelving.card.basicData({id: $ctrl.summary.id})"
target="_self">
<span translate vn-tooltip="Go to">Basic data</span>
</a>
</h4>
<vn-vertical>
<vn-label-value
label="Code"
value="{{::$ctrl.summary.id}}">
</vn-label-value>
<vn-label-value
label="Parking"
value="{{::$ctrl.summary.parking.code}}">
</vn-label-value>
<vn-label-value
label="Priority"
value="{{::$ctrl.summary.priority}}">
</vn-label-value>
<vn-label-value label="Worker">
<span
ng-click="workerDescriptor.show($event, $ctrl.summary.userFk)"
class="link">
{{$ctrl.summary.worker.user.nickname}}
</span>
</vn-label-value>
<vn-check
label="Recyclable"
ng-model="$ctrl.summary.isRecyclable"
disabled="true">
</vn-check>
</vn-vertical>
</vn-one>
</vn-horizontal>
</vn-card>
<vn-worker-descriptor-popover
vn-id="workerDescriptor">
</vn-worker-descriptor-popover>

View File

@ -0,0 +1,41 @@
import ngModule from '../module';
import Summary from 'salix/components/summary';
import './style.scss';
class Controller extends Summary {
set shelving(value) {
this._shelving = value;
this.summary = null;
if (!value) return;
const filter = {
include: [
{relation: 'worker',
scope: {
fields: ['userFk'],
include: {
relation: 'user',
scope: {
fields: ['nickname']
}
}
}},
{relation: 'parking'}
]
};
this.$http.get(`Shelvings/${value.id}`, {filter})
.then(res => this.summary = res.data);
}
get shelving() {
return this._shelving;
}
}
ngModule.vnComponent('vnShelvingSummary', {
template: require('./index.html'),
controller: Controller,
bindings: {
shelving: '<'
}
});

View File

@ -0,0 +1,32 @@
import './index';
describe('Supplier', () => {
describe('Component vnSupplierSummary', () => {
let controller;
let $httpBackend;
let $scope;
beforeEach(ngModule('supplier'));
beforeEach(inject(($componentController, _$httpBackend_, $rootScope) => {
$httpBackend = _$httpBackend_;
$scope = $rootScope.$new();
const $element = angular.element('<vn-supplier-summary></vn-supplier-summary>');
controller = $componentController('vnSupplierSummary', {$element, $scope});
}));
describe('getSummary()', () => {
it('should perform a get asking for the supplier data', () => {
controller.supplier = {id: 1};
const query = `Suppliers/${controller.supplier.id}/getSummary`;
$httpBackend.expectGET(query).respond({id: 1});
controller.getSummary();
$httpBackend.flush();
expect(controller.summary).toEqual({id: 1});
});
});
});
});

View File

@ -0,0 +1,12 @@
Verified: Verificado
Country: País
Tax number: NIF / CIF
Search suppliers by id, name or alias: Busca proveedores por id, nombre o alias
Is Farmer: Es agrícola
Sage tax type: Tipo de impuesto Sage
Sage transaction type: Tipo de transacción Sage
Sage withholding: Retencion Sage
Go to the supplier: Ir al proveedor
Responsible: Responsable
Supplier activity: Actividad proveedor
Healt register: Pasaporte sanitario

View File

@ -0,0 +1,7 @@
@import "variables";
vn-client-summary {
.alert span {
color: $color-alert
}
}