...
 
Commits (3)
{
"name": "generate-model",
"name": "generate-task",
"version": "0.0.0",
"lockfileVersion": 1,
"requires": true,
......
{
"name": "generate-model",
"name": "generate-task",
"version": "0.0.0",
"description": "A blank schematics",
"scripts": {
......
......@@ -3,8 +3,8 @@
"schematics": {
"generate-model": {
"description": "A blank schematic.",
"factory": "./generate-model/index#generateModel",
"schema": "./generate-model/schema.json"
"factory": "./generate-task/index#generateTask",
"schema": "./generate-task/schema.json"
}
}
}
import { ModuleWithProviders, NgModule } from '@angular/core';
@NgModule({
imports: [
SharedModule,
],
declarations: [],
providers: [],
})
export class <%= classify(name) %>Module {
}
import {NgModule} from '@angular/core';
import {RouterModule, Routes} from '@angular/router';
import {<%= classify(name) %>Component} from './<%= dasherize(name) %>.component';
const routes: Routes = [
{
path: '',
canActivate: [AuthGuard],
component: <%= classify(name) %>Component,
},
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class <%= classify(name) %>RoutingModule {
}
<div class="wrapper max-height" fxLayout="column">
<div class="table-paginator-row">
<div class="loading-bar">
<mat-progress-bar *ngIf="isLoadingResults" mode="indeterminate"></mat-progress-bar>
</div>
<div class="paginator-row">
<button (click)="openCreateDialog()" class="paginator-margin-left"
color="primary" data-cy="app<%= classify(name) %>CreateBtn" mat-raised-button>
CREATE
</button>
<button (click)="onDeleteAllSelected()" [disabled]="selectedRows.selected.length < 1" class="new-resource-btn"
color="warn" data-cy="app<%= classify(name) %>DeleteBtn"
mat-icon-button matTooltip="Delete selected">
<mat-icon>delete</mat-icon>
</button>
<mat-paginator [length]="resultsLength" [pageSizeOptions]="[25, 50, 100]" showFirstLastButtons>
</mat-paginator>
</div>
</div>
<div [appScrollTop]="tableData" class="tasks-table overflow-auto">
<table [dataSource]="tableData" mat-table
matSort matSortDirection="asc"
multiTemplateDataRows>
<ng-container matColumnDef="select">
<th *matHeaderCellDef mat-header-cell>
<mat-checkbox (change)="$event ? masterToggle() : null" [checked]="selectedRows.hasValue() && isAllSelected()"
[indeterminate]="selectedRows.hasValue() && !isAllSelected()">
</mat-checkbox>
</th>
<td *matCellDef="let row" mat-cell>
<mat-checkbox (change)="$event ? selectedRows.toggle(row) : null" (click)="$event.stopPropagation()"
[checked]="selectedRows.isSelected(row)">
</mat-checkbox>
</td>
</ng-container>
<ng-container matColumnDef="id">
<th *matHeaderCellDef mat-header-cell mat-sort-header> Id</th>
<td *matCellDef="let element" mat-cell> {{element.id}}</td>
</ng-container>
<ng-container matColumnDef="description">
<th *matHeaderCellDef mat-header-cell mat-sort-header> Description</th>
<td *matCellDef="let element" mat-cell> {{element.description}}</td>
</ng-container>
<ng-container matColumnDef="task__time_started">
<th *matHeaderCellDef mat-header-cell mat-sort-header> Time started</th>
<td *matCellDef="let element" mat-cell><span
*ngIf="element.task">{{element.task.time_started | date:'y-M-d H:mm:ss'}}</span>
</td>
</ng-container>
<ng-container matColumnDef="task__time_completed">
<th *matHeaderCellDef mat-header-cell mat-sort-header> Time completed</th>
<td *matCellDef="let element" mat-cell>
<span
*ngIf="element.task && element.task.time_completed">{{element.task.time_completed | date:'y-M-d H:mm:ss'}}</span>
<span *ngIf="element.task && !element.task.time_completed">-</span>
</td>
</ng-container>
<ng-container matColumnDef="task__status">
<th *matHeaderCellDef mat-header-cell mat-sort-header> Task</th>
<td *matCellDef="let element" mat-cell>
<mat-progress-bar *ngIf="element.task && element.task.step !== 'training'" [value]="element.task.progress"
mode="determinate">
</mat-progress-bar>
<mat-progress-bar *ngIf="element.task && element.task.step === 'training' && element.task.status !== 'failed'"
[value]="element.task.progress" mode="indeterminate">
</mat-progress-bar>
<mat-hint *ngIf="element.task">{{element.task.status}} {{element.task.step}}</mat-hint>
</td>
</ng-container>
<ng-container matColumnDef="expandedDetail">
<td *matCellDef="let element" [attr.colspan]="displayedColumns.length" mat-cell>
<div *ngIf="element == expandedElement" [@detailExpand] class="element-detail">
<div class="flex-col m-l-r-5" fxFlex="50">
<table class="simple-table">
<tr>
<th class="mat-body-strong">Resource id</th>
<td>{{element.id}}</td>
</tr>
<tr>
<th class="mat-body-strong">Task id</th>
<td>{{element.task.id}}</td>
</tr>
<tr>
<th class="mat-body-strong">Status</th>
<td>{{element.task.status}}</td>
</tr>
<tr>
<th class="mat-body-strong">Progress</th>
<td>{{element.task.progress}}</td>
</tr>
<tr>
<th class="mat-body-strong">Step</th>
<td>{{element.task.step}}</td>
</tr>
<tr>
<th class="mat-body-strong">Errors</th>
<td>{{element.task.errors}}</td>
</tr>
<tr>
<th class="mat-body-strong">Last Update</th>
<td>{{element.task.last_update | date:'y-M-d H:mm:ss'}}</td>
</tr>
</table>
</div>
</div>
</td>
</ng-container>
<tr *matHeaderRowDef="displayedColumns; sticky: true" mat-header-row></tr>
<tr (click)="expandedElement = expandedElement === element ? null : element" *matRowDef="let element; columns: displayedColumns;"
[class.expanded-row]="expandedElement === element"
class="element-row"
mat-row></tr>
<tr *matRowDef="let row; columns: ['expandedDetail']" class="detail-row" mat-row></tr>
</table>
</div>
</div>
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { <%= classify(name) %>Component } from './<%= dasherize(name) %>.component';
import {HttpClientTestingModule} from '@angular/common/http/testing';
import {RouterTestingModule} from '@angular/router/testing';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
describe('<%= classify(name) %>Component', () => {
let component: <%= classify(name) %>Component;
let fixture: ComponentFixture<<%= classify(name) %>Component>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ <%= classify(name) %>Component ],
imports: [
SharedModule, HttpClientTestingModule, RouterTestingModule, BrowserAnimationsModule
],
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(<%= classify(name) %>Component);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
......@@ -7,6 +7,7 @@ import {MatTableDataSource} from '@angular/material/table';
import {SelectionModel} from '@angular/cdk/collections';
import {MatSort} from '@angular/material/sort';
import {MatPaginator} from '@angular/material/paginator';
import { Create<%= classify(name) %>DialogComponent } from './create-<%= dasherize(name) %>-dialog/create-<%= dasherize(name) %>-dialog.component';
@Component({
selector: 'app-<%= dasherize(name) %>',
......@@ -97,7 +98,7 @@ export class <%= classify(name) %>Component implements OnInit, OnDestroy, AfterV
/** Whether the number of selected elements matches the total number of rows. */
isAllSelected(): void {
isAllSelected(): boolean {
const numSelected = this.selectedRows.selected.length;
const numRows = this.tableData.data.length;
return numSelected === numRows;
......@@ -107,7 +108,7 @@ export class <%= classify(name) %>Component implements OnInit, OnDestroy, AfterV
masterToggle(): void {
this.isAllSelected() ?
this.selectedRows.clear() :
this.tableData.data.forEach(row => this.selectedRows.select(row));
(this.tableData.data as <%= classify(name) %>[]).forEach(row => this.selectedRows.select(row));
}
......@@ -137,7 +138,7 @@ export class <%= classify(name) %>Component implements OnInit, OnDestroy, AfterV
removeSelectedRows(): void {
this.selectedRows.selected.forEach((selected: <%= classify(name) %>) => {
const index: number = this.tableData.data.findIndex(<%= camelize(name) %> => <%= camelize(name) %>.id === selected.id);
const index: number = (this.tableData.data as <%= classify(name) %>[]).findIndex(<%= camelize(name) %> => <%= camelize(name) %>.id === selected.id);
this.tableData.data.splice(index, 1);
this.tableData.data = [...this.tableData.data];
});
......
import { ModuleWithProviders, NgModule } from '@angular/core';
import {<%= classify(name) %>Component} from './<%= dasherize(name) %>.component';
import { Create<%= classify(name) %>DialogComponent } from './create-<%= dasherize(name) %>-dialog/create-<%= dasherize(name) %>-dialog.component';
import {<%= classify(name) %>RoutingModule} from './<%= dasherize(name) %>-routing.module';
@NgModule({
imports: [
SharedModule,
<%= classify(name) %>RoutingModule,
],
declarations: [
<%= classify(name) %>Component,
Create<%= classify(name) %>DialogComponent
],
providers: [],
})
export class <%= classify(name) %>Module {
}
<h1 mat-dialog-title>New <%= classify(name) %> task</h1>
<div mat-dialog-content>
<form (ngSubmit)="onSubmit(<%= camelize(name) %>Form.value)" [formGroup]="<%= camelize(name) %>Form" class="flex-col">
<mat-form-field data-cy="app<%= classify(name) %>CreateDialogDesc">
<input [errorStateMatcher]="matcher" autocomplete="off" formControlName="descriptionFormControl" matInput
placeholder="Description" required>
<mat-error *ngIf="<%= camelize(name) %>Form.get('descriptionFormControl')?.hasError('required')">
Description is <strong>required</strong>
</mat-error>
</mat-form-field>
<mat-form-field data-cy="app<%= classify(name) %>CreateDialogIndices">
<mat-label>Indices</mat-label>
<mat-select (openedChange)="indicesOpenedChange($event)" [disableOptionCentering]="true"
formControlName="indicesFormControl" multiple panelClass="select-panel-reveal-input" required>
<mat-option *ngFor="let projectIndex of projectIndices" [value]="projectIndex">
{{projectIndex.index}}
</mat-option>
</mat-select>
<mat-error *ngIf="<%= camelize(name) %>Form.get('indicesFormControl')?.hasError('required')">
Select at least <strong>1 index</strong>
</mat-error>
</mat-form-field>
<mat-form-field>
<mat-label>Select Fields</mat-label>
<mat-select [disableOptionCentering]="true" formControlName="fieldsFormControl"
multiple panelClass="select-panel-reveal-input">
<mat-option *ngFor="let fields of fieldsUnique" [value]="fields.path">
{{fields.path}}
</mat-option>
</mat-select>
</mat-form-field>
<div class="flex-col">
<div class="flex-row">
<div class="flex-item-left">
<button class="flex-item-left" mat-button mat-dialog-close type="button">Close</button>
</div>
<div class="flex-item-right">
<button [disabled]="!<%= camelize(name) %>Form.valid" data-cy="app<%= classify(name) %>CreateDialogSubmit" mat-button type="submit">
Create
</button>
</div>
</div>
</div>
</form>
</div>
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { Create<%= classify(name) %>DialogComponent } from './create-<%= dasherize(name) %>-dialog.component';
import {HttpClientTestingModule} from '@angular/common/http/testing';
import {RouterTestingModule} from '@angular/router/testing';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {MatDialogRef} from '@angular/material/dialog';
describe('Create<%= classify(name) %>DialogComponent', () => {
let component: Create<%= classify(name) %>DialogComponent;
let fixture: ComponentFixture<Create<%= classify(name) %>DialogComponent>;
const mockDialogRef = {
close: jasmine.createSpy('close')
};
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
SharedModule, HttpClientTestingModule, RouterTestingModule, BrowserAnimationsModule
],
providers: [
{
provide: MatDialogRef,
useValue: mockDialogRef
}],
declarations: [ Create<%= classify(name) %>DialogComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(Create<%= classify(name) %>DialogComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import {Component, OnDestroy, OnInit} from '@angular/core';
import {MatDialogRef} from '@angular/material/dialog';
import {of, Subject} from 'rxjs';
import {ErrorStateMatcher} from '@angular/material/core';
import {mergeMap, takeUntil} from 'rxjs/operators';
import {FormControl, FormGroup, Validators} from '@angular/forms';
import {HttpErrorResponse} from '@angular/common/http';
@Component({
selector: 'app-create-<%= dasherize(name) %>-dialog',
templateUrl: './create-<%= dasherize(name) %>-dialog.component.html',
styleUrls: ['./create-<%= dasherize(name) %>-dialog.component.scss']
})
export class Create<%= classify(name) %>DialogComponent implements OnInit, OnDestroy {
<%= camelize(name) %>Form = new FormGroup({
descriptionFormControl: new FormControl('', [Validators.required]),
indicesFormControl: new FormControl([], [Validators.required]),
fieldsFormControl: new FormControl([]),
});
matcher: ErrorStateMatcher = new LiveErrorStateMatcher();
currentProject: Project;
destroyed$: Subject<boolean> = new Subject<boolean>();
fieldsUnique: Field[] = [];
projectIndices: ProjectIndex[] = [];
projectFields: ProjectIndex[];
constructor(private dialogRef: MatDialogRef<Create<%= classify(name) %>DialogComponent>,
private projectService: ProjectService,
private <%= camelize(name) %>Service: <%= classify(name) %>Service,
private logService: LogService,
private projectStore: ProjectStore) {
}
ngOnInit(): void {
this.projectStore.getSelectedProjectIndices().pipe(takeUntil(this.destroyed$)).subscribe(currentProjIndices => {
if (currentProjIndices) {
const indicesForm = this.<%= camelize(name) %>Form.get('indicesFormControl');
indicesForm?.setValue(currentProjIndices);
this.getFieldsForIndices(currentProjIndices);
}
});
this.projectStore.getProjectIndices().pipe(takeUntil(this.destroyed$)).subscribe(projIndices => {
if (projIndices) {
this.projectIndices = projIndices;
}
});
}
onSubmit(formData: {
descriptionFormControl: string;
indicesFormControl: ProjectIndex[]; fieldsFormControl: string[];
}): void {
const body = {
description: formData.descriptionFormControl,
indices: formData.indicesFormControl.map(x => [{name: x.index}]).flat(),
fields: formData.fieldsFormControl
};
this.<%= camelize(name) %>Service.create<%= classify(name) %>Task(this.currentProject.id, body).subscribe(resp => {
if (resp && !(resp instanceof HttpErrorResponse)) {
this.logService.snackBarMessage(`Created new task: ${resp.description}`, 2000);
this.dialogRef.close(resp);
} else if (resp instanceof HttpErrorResponse) {
this.logService.snackBarError(resp, 5000);
}
});
}
getFieldsForIndices(indices: ProjectIndex[]): void {
this.projectFields = ProjectIndex.cleanProjectIndicesFields(indices, ['text'], []);
this.fieldsUnique = UtilityFunctions.getDistinctByProperty<Field>(this.projectFields.map(y => y.fields).flat(), (y => y.path));
}
public indicesOpenedChange(opened: unknown): void {
const indicesForm = this.<%= camelize(name) %>Form.get('indicesFormControl');
// true is opened, false is closed, when selecting something and then deselecting it the formcontrol returns empty array
if (!opened && (indicesForm?.value && indicesForm.value.length > 0)) {
this.getFieldsForIndices(indicesForm?.value);
}
}
ngOnDestroy(): void {
this.destroyed$.next(true);
this.destroyed$.complete();
}
}
......@@ -32,7 +32,7 @@ export function setupOptions(host: Tree, options: any): Tree {
}
// You don't have to export the function as default. You can also have more than one rule factory
// per file.
export function generateModel(options: any): Rule {
export function generateTask(options: any): Rule {
return (tree: Tree, _context: SchematicContext) => {
const workspaceConfig = tree.read('/angular.json');
if (!workspaceConfig) {
......@@ -65,7 +65,77 @@ export function generateModel(options: any): Rule {
]);
return chain([
generateTaskServices(options),
generateTaskTypes(options),
mergeWith(templateSource)
]);
};
}
export function generateTaskServices(options: any): Rule {
return (tree: Tree, _context: SchematicContext) => {
const workspaceConfig = tree.read('/angular.json');
if (!workspaceConfig) {
throw new SchematicsException('Could not find Angular workspace configuration');
}
// convert workspace to string
const workspaceContent = workspaceConfig.toString();
// parse workspace string into JSON object
const workspace: experimental.workspace.WorkspaceSchema = JSON.parse(workspaceContent);
if (!options.project) {
options.project = workspace.defaultProject;
}
if (options.path === undefined) {
options.path = `${options.sourceDir}`;
}
const templateSource = apply(url('./services'), [
applyTemplates({
classify: strings.classify,
dasherize: strings.dasherize,
camelize: strings.camelize,
name: options.name
}),
move('/src/app/core/' + strings.dasherize(options.name))
]);
return mergeWith(templateSource);
};
}
export function generateTaskTypes(options: any): Rule {
return (tree: Tree, _context: SchematicContext) => {
const workspaceConfig = tree.read('/angular.json');
if (!workspaceConfig) {
throw new SchematicsException('Could not find Angular workspace configuration');
}
// convert workspace to string
const workspaceContent = workspaceConfig.toString();
// parse workspace string into JSON object
const workspace: experimental.workspace.WorkspaceSchema = JSON.parse(workspaceContent);
if (!options.project) {
options.project = workspace.defaultProject;
}
if (options.path === undefined) {
options.path = `${options.sourceDir}`;
}
const templateSource = apply(url('./types'), [
applyTemplates({
classify: strings.classify,
dasherize: strings.dasherize,
camelize: strings.camelize,
name: options.name
}),
move('/src/app/shared/types/tasks/')
]);
return mergeWith(templateSource);
};
}
import { TestBed } from '@angular/core/testing';
import { <%= classify(name) %>Service } from './<%= dasherize(name) %>.service';
import {RouterTestingModule} from '@angular/router/testing';
import {HttpClientTestingModule} from '@angular/common/http/testing';
describe('<%= classify(name) %>Service', () => {
let service: <%= classify(name) %>Service;
beforeEach(() => {
TestBed.configureTestingModule({imports: [
RouterTestingModule,
SharedModule,
HttpClientTestingModule
]});
service = TestBed.inject(<%= classify(name) %>Service);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});
import {Injectable} from '@angular/core';
import {HttpClient, HttpErrorResponse} from '@angular/common/http';
import {Observable} from 'rxjs';
import {catchError, tap} from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class <%= classify(name) %>Service {
apiUrl = environment.apiHost + environment.apiBasePath;
constructor(private http: HttpClient,
private logService: LogService) {
}
get<%= classify(name) %>Tasks(projectId: number, params = ''): Observable<ResultsWrapper<<%= classify(name) %>> | HttpErrorResponse> {
return this.http.get<ResultsWrapper<<%= classify(name) %>>>(`${this.apiUrl}/projects/${projectId}/<%= dasherize(name) %>/?${params}`).pipe(
tap(e => this.logService.logStatus(e, 'get<%= classify(name) %>Tasks')),
catchError(this.logService.handleError<ResultsWrapper<<%= classify(name) %>>>('get<%= classify(name) %>Tasks')));
}
create<%= classify(name) %>Task(projectId: number, body: unknown): Observable<<%= classify(name) %> | HttpErrorResponse> {
return this.http.post<<%= classify(name) %>>(`${this.apiUrl}/projects/${projectId}/<%= dasherize(name) %>/`, body).pipe(
tap(e => this.logService.logStatus(e, 'create<%= classify(name) %>Task')),
catchError(this.logService.handleError<<%= classify(name) %>>('create<%= classify(name) %>Task')));
}
bulkDelete<%= classify(name) %>Tasks(projectId: number, body: unknown): Observable<{ 'num_deleted': number, 'deleted_types': { string: number }[] } | HttpErrorResponse> {
return this.http.post<{ 'num_deleted': number, 'deleted_types': { string: number }[] }>
(`${this.apiUrl}/projects/${projectId}/<%= dasherize(name) %>/bulk_delete/`, body).pipe(
tap(e => this.logService.logStatus(e, 'bulkDelete<%= classify(name) %>Tasks')),
catchError(this.logService.handleError<{ 'num_deleted': number, 'deleted_types': { string: number }[] }>('bulkDelete<%= classify(name) %>Tasks')));
}
}
interface Index {
id: number;
is_open: boolean;
url: string;
name: string;
}
interface Task {
id: number;
status: string;
progress: number;
step: string;
errors: string;
time_started: Date;
last_update: Date;
time_completed?: any;
total: number;
num_processed: number;
}
export interface <%= classify(name) %> {
id: number;
url: string;
indices: Index[];
description: string;
task: Task;
fields: string[];
}
@import "../../../../variables/variables";
table {
width: 100%;
......
@import "../../../../variables/variables";
table {
width: 100%;
......
@import "src/variables/variables";
table {
width: 100%;
......
@import "src/variables/variables";
table {
width: 100%;
......
@import "src/variables/variables";
table {
width: 100%;
......
@import "src/variables/variables";
table {
width: 100%;
......
@import "src/variables/variables";
@import "../../variables/variables";
table {
width: 100%;
......
@import "../../../../variables/variables";
.wrapper {
height: 100%;
......
@import "../../../variables/variables";
table {
width: 100%;
......
@import "../../../variables/variables";
table {
width: 100%;
......
......@@ -34,3 +34,41 @@
white-space: pre-line;
}
}
.tasks-table{
table {
width: 100%;
}
.mat-cell {
word-break: break-word;
}
.mat-column-task__status {
max-width: 160px;
}
tr.element-row:not(.expanded-row):hover {
background: #eeeeee;
}
tr.element-row:not(.expanded-row):active {
background: #efefef;
}
tr.detail-row {
height: 0;
}
.element-row td {
border-bottom-width: 0;
}
.element-detail {
overflow: hidden;
display: flex;
flex-direction: row;
}
}
......@@ -4,7 +4,7 @@
export const environment = {
// apiUrl: 'https://rest-dev.texta.ee/api/v1',
apiHost: 'http://localhost',
apiHost: 'https://rest-dev.texta.ee',
apiBasePath: '/api/v1',
production: false
};
......
/* You can add global styles to this file, and also import other style files */
@import "./variables/variables";
@import "library-overrides";
@import "components";
@use "sass:map";
@use "./variables/variables";
@use "library-overrides";
@use "components";
// might be problematic todo
div {
box-sizing: border-box;
......@@ -116,19 +117,19 @@ pre {
}
.accent-text {
color: $accent;
color: variables.$accent;
}
.primary-text {
color: $primary;
color: variables.$primary;
}
.warn-text {
color: $warn;
color: variables.$warn;
}
.action-text {
color: $primary;
color: variables.$primary;
}
......@@ -149,7 +150,7 @@ pre {
}
.table-actions-wrapper {
background-color: map-get($background, card);
background-color: map.get(variables.$background, card);
border-top-left-radius: 8.5px;
border-top-right-radius: 8.5px;
......
@import '~@angular/material/theming';
@use "sass:map";
@use '~@angular/material/theming';
// Define the default theme (same as the example above).
$texta-primary: mat-palette($mat-indigo);
$texta-accent: mat-palette($mat-pink, A200, A100, A400);
$texta-warn: mat-palette($mat-red);
$texta-primary: theming.mat-palette(theming.$mat-indigo);
$texta-accent: theming.mat-palette(theming.$mat-pink, A200, A100, A400);
$texta-warn: theming.mat-palette(theming.$mat-red);
$texta-theme: mat-light-theme($texta-primary, $texta-accent);
$texta-theme: theming.mat-light-theme($texta-primary, $texta-accent);
$navbar-height: 56px;
$primary: mat-color($texta-primary);
$accent: mat-color($texta-accent);
$warn: mat-color($texta-warn);
$primary: theming.mat-color($texta-primary);
$accent: theming.mat-color($texta-accent);
$warn: theming.mat-color($texta-warn);
$foreground: map-get($texta-theme, foreground);
$background: map-get($texta-theme, background);
$foreground: map.get($texta-theme, foreground);
$background: map.get($texta-theme, background);