Commit 0090cdab authored by Hando Lukats's avatar Hando Lukats
Browse files

Merge branch 'develop' into 'master'

Release: merge 'develop' into 'master' created by Hando Lukats

See merge request teis/public-web-client!638
parents a9f965f2 3504122f
{
"name": "te-is",
"version": "1.24.1",
"version": "1.25.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
......
{
"name": "te-is",
"version": "1.24.1",
"version": "1.25.0",
"license": "MIT",
"scripts": {
"ng": "ng",
......
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from '@official/features/home/containers/home/home.component';
import { SupervisionPlanListComponent } from '../supervision-plan/containers/supervision-plan-list/supervision-plan-list.component';
import { CompanySearchComponent } from '../company-search/containers/company-search/company-search.component';
......@@ -51,9 +51,7 @@ import { OfficialClassifiersListComponent } from '@official/features/settings/fe
import { OfficialClassifierDefinitionItemsComponent } from '@official/features/settings/features/classifier-definitions-settings/containers/official-classifier-definition-items/official-classifier-definition-items.component';
import { RolesComponent } from '../settings/features/roles/containers/roles/roles.component';
import { RoleDetailsComponent } from '../settings/features/roles/containers/role-details/role-details.component';
import {
OfficialClassifierDefinitionItemDetailsComponent,
} from '@official/features/settings/features/classifier-definitions-settings/containers/official-classifier-definition-item-details/official-classifier-definition-item-details.component';
import { OfficialClassifierDefinitionItemDetailsComponent, } from '@official/features/settings/features/classifier-definitions-settings/containers/official-classifier-definition-item-details/official-classifier-definition-item-details.component';
import { MessageDefinitionsListComponent } from '@official/features/settings/features/message-definitions/containers/message-definitions-list/message-definitions-list.component';
import { MessageDefinitionsDetailedComponent } from '@official/features/settings/features/message-definitions/containers/message-definitions-detailed/message-definitions-detailed.component';
import { TaskDefinitionsListComponent } from '../settings/features/task-definitions/containers/task-definitions-list/task-definitions-list.component';
......@@ -75,6 +73,7 @@ import { RiskFactorsDetailsComponent } from '@official/features/settings/feature
import { AssignmentsComponent } from '@official/features/company-details/containers/assignments/assignments.component';
import { RiskAssessmentsListComponent } from '@official/features/office-risk-assessments/containers/risk-assessments-list/risk-assessments-list.component';
import { RiskAssessmentFilesComponent } from '@official/features/office-risk-assessments/containers/risk-assessment-files/risk-assessment-files.component';
import { ProceedingsTopicsComponent } from '@official/features/proceedings/containers/proceedings-topics/proceedings-topics.component';
const routes: Routes = [
{
......@@ -283,6 +282,10 @@ const routes: Routes = [
path: 'general',
component: ProceedingsGeneralComponent,
},
{
path: 'topics',
component: ProceedingsTopicsComponent,
},
{
path: 'documents',
component: ProceedingsDocumentsComponent,
......
<ng-container *ngIf="!form">
<ng-container *ngFor="let second of data">
<div class="inspection-topic-hierarchy" *ngIf="second.children.length">
<div class="inspection-topic-hierarchy__level__second">
<strong>{{ second?.name }}</strong>
</div>
<div class="inspection-topic-hierarchy__level__third" *ngFor="let third of second.children">
<span>{{ third?.name }}</span>
<span class="source">{{third?.source?.source?.name}}</span>
<p class="explanation">{{ third?.attributes[0]?.value }}</p>
</div>
</div>
</ng-container>
</ng-container>
<ng-container *ngIf="form">
<ng-container [formGroup]="form" *ngFor="let second of data">
<div class="inspection-topic-hierarchy" *ngIf="second.children.length">
<div class="inspection-topic-hierarchy__level__second">
<teis-checkbox
[name]="second?.code"
[formControlName]="second?.code">
<strong>{{ second?.name }}</strong>
</teis-checkbox>
</div>
<div class="inspection-topic-hierarchy__level__third" *ngFor="let third of second.children">
<span class="source">{{ third?.source?.source?.name }}</span>
<teis-checkbox
[name]="third?.code"
[source]="third?.source?.source?.code"
[formControlName]="third?.code">
</teis-checkbox>
<span>{{ third?.name }}</span>
<p class="explanation">{{ third?.attributes[0]?.value }}</p>
</div>
</div>
</ng-container>
</ng-container>
\ No newline at end of file
@import '~@ska-angular/assets/assets/scss/abstracts/_custom-variables.scss';
.inspection-topic-hierarchy {
border-top: $gray-lighter 1px solid;
&:first-child {
border-top: unset;
}
&__level {
&__second {
padding: 1rem;
padding-left: 3rem;
border-bottom: $gray-lighter 1px solid;
&:last-child {
border-bottom: unset;
}
}
&__third {
padding: 1rem;
padding-left: 6rem;
border-bottom: $gray-lighter 1px solid;
.explanation {
font-style: italic;
color: $gray-light;
}
&:last-child {
border-bottom: unset;
}
}
}
}
.source {
float: right;
color: $gray-light;
}
\ No newline at end of file
import { Component, Input } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { InspectionTopicsItem } from '@teis/services/supervision-plan/supervision-plan.models';
@Component({
selector: 'teis-proceeding-topic-hierarchy',
templateUrl: './proceeding-inspection-topic-hierarchy.component.html',
styleUrls: ['./proceeding-inspection-topic-hierarchy.component.scss'],
})
export class ProceedingInspectionTopicHierarchyComponent {
@Input() data: InspectionTopicsItem[] = [];
@Input() form: FormGroup;
}
......@@ -4,10 +4,12 @@ import { AvailableTabs } from '@teis/modules/tabs/components/tehik-tabs/tehik-ta
import { Subscription } from 'rxjs';
import { TranslateService } from '@ngx-translate/core';
import { ProceedingsFacade } from '../../proceedings.facade.service';
import { Router, ActivatedRoute } from '@angular/router';
import { ActivatedRoute, Router } from '@angular/router';
import { TabContainer } from '@teis/modules/tabs/tab-container';
import { filter } from 'rxjs/operators';
import { ProceedingDetails } from '@teis/services/proceedings/proceedings.model';
import { TeisFeatureFlagsService } from '@teis/services/feature-flags/feature-flags.service';
import { FeatureFlag } from '@teis/services/feature-flags/feature-flags.model';
@Component({
selector: 'proceedings-detailed',
......@@ -30,6 +32,8 @@ export class ProceedingsDetailedComponent extends TabContainer implements OnInit
public proceeding: ProceedingDetails;
public companyDetailsUrl: string;
public chatSubTitle: string;
featureFlags = FeatureFlag;
inspectionTopicsVisible: boolean;
private subscriptions$: Subscription[];
@ViewChild('chatButton', { static: false }) chatButton;
......@@ -38,6 +42,7 @@ export class ProceedingsDetailedComponent extends TabContainer implements OnInit
private translate: TranslateService,
public router: Router,
public route: ActivatedRoute,
private featureFlagsService: TeisFeatureFlagsService,
) {
super(route, router);
}
......@@ -53,6 +58,15 @@ export class ProceedingsDetailedComponent extends TabContainer implements OnInit
}
ngOnInit() {
this.inspectionTopicsVisible = this.featureFlagsService.isFeatureOn(this.featureFlags.INSPECTIONTOPICS_VISIBLE);
if (this.inspectionTopicsVisible) {
this.proceedingTabs.splice(1, 0, {
name: 'topics',
title: 'topics',
privileges: ['TI_VIEW_PROCEEDINGS'],
});
}
const proceedingId$ = this.route.params.subscribe(({ id }) => {
this.facade.getSingleProceeding(id);
});
......
import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { combineLatest, Subscription } from 'rxjs';
import { ProceedingsFacade } from '@official/features/proceedings/proceedings.facade.service';
import { filter, tap, mergeMap } from 'rxjs/operators';
import { filter, mergeMap, tap } from 'rxjs/operators';
import { StatusChangeComponent } from '@teis/modules/status-button/status-change/status-change.component';
import { ConfirmationOptions } from '@teis/modules/modal/confirmation/confirmation.component';
import { TranslateService } from '@ngx-translate/core';
......@@ -61,7 +61,6 @@ export class ProceedingStatusComponent implements OnInit, OnDestroy {
changeStatus(status: ClassifierItemDto) {
if (status.id === this.proceeding.status.id) return;
const confirmationOptionsPresets: { [id: string]: ConfirmationOptions } = {
PROCEEDING_STATUS__PENDING: {
description: this.translate.instant('proceeding_status_change_pending_description', { status: this.proceeding.status.name.toLowerCase() }),
......
<teis-modal
[loading]="loading"
[icon]="'icon-mult-select'"
[title]="'edit_topics_title' | translate">
<teis-form-layout [colsize]="20">
<form *ngIf="form" [formGroup]="form" (ngSubmit)="submit(form)">
<teis-content-collapse [toggleable]="true" *ngFor="let node of tree">
<ng-container preview>
<teis-checkbox
[name]="node?.code"
[formControlName]="node?.code">
<h4 class="m-0">{{ node?.name | titlecase }}</h4>
</teis-checkbox>
</ng-container>
<ng-container preview-actions>
<teis-proceedings-topics-preview-actions
[total]="form.get(node.code).value.total"
[selected]="form.get(node.code).value.selected">
</teis-proceedings-topics-preview-actions>
</ng-container>
<ng-container content>
<teis-proceeding-topic-hierarchy
[form]="form"
[data]="node?.children">
</teis-proceeding-topic-hierarchy>
</ng-container>
</teis-content-collapse>
<teis-flex>
<form-button-with-confirmation
id="formCancel"
[form]="form"
[buttonBackLabel]="'cancel' | translate "
(confirm)="cancel()">
</form-button-with-confirmation>
<button
id="formSubmit"
teis-button
teis-submitting
type="submit">
{{ 'save' | translate }}
</button>
</teis-flex>
</form>
</teis-form-layout>
</teis-modal>
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Subscription } from 'rxjs';
import { concatMap, filter } from 'rxjs/operators';
import { FormGroup } from '@angular/forms';
import { ClassifierItemDto } from '@teis/services/classifiers/classifiers.models';
import { ProceedingsFacade } from '@official/features/proceedings/proceedings.facade.service';
import {
handleInspectionTopicFormValueChanges,
ProceedingsTopicsService
} from '@official/features/proceedings/services/proceedings-topics.service';
import { ProceedingDetails } from '@teis/services/proceedings/proceedings.model';
@Component({
selector: 'teis-supervision-plan-topics-edit',
templateUrl: './proceedings-topics-edit.component.html',
styleUrls: ['./proceedings-topics-edit.component.scss'],
})
export class ProceedingsTopicsEditComponent implements OnInit, OnDestroy {
detail: ProceedingDetails;
tree = [];
form: FormGroup;
available: ClassifierItemDto[] = [];
loading: boolean = false;
subscriptions$: Subscription[] = [];
constructor(private facade: ProceedingsFacade,
private topicsService: ProceedingsTopicsService) {}
ngOnInit() {
this.loading = true;
const detail$ = this.facade.proceedingDetails
.pipe(
filter(detail => detail !== null),
concatMap((detail: any) => {
this.detail = detail;
return this.facade.fetchInspectionTopicsForm(detail.id);
}))
.subscribe(({ tree, available, form }) => {
this.tree = tree;
this.available = available;
this.form = form;
const formControlValues$ = Object.keys(this.form.controls)
.map(key => this.form.get(key).valueChanges
.subscribe((value) => {
handleInspectionTopicFormValueChanges(key, value, available, form);
}));
this.loading = false;
this.subscriptions$ = [...this.subscriptions$, ...formControlValues$];
});
this.subscriptions$ = [...this.subscriptions$, detail$];
}
ngOnDestroy() {
if (this.subscriptions$.length) this.subscriptions$.forEach(sub => sub.unsubscribe());
}
submit(form: FormGroup) {
this.facade.submitInspectionTopicsForm(this.detail, form);
}
cancel() {
this.facade.closeModal();
}
}
<span class="topics-summary">
<ng-container *ngIf="!selected || selected === 0">
{{ 'no_topics_selected' | translate }}
</ng-container>
<ng-container *ngIf="total !== selected">
<ng-container *ngIf="selected === 1">
{{ 'one_amount_topics_selected' | translate: { count: selected } }}
</ng-container>
<ng-container *ngIf="selected > 1">
{{ 'n_amount_topics_selected' | translate: { count: selected } }}
</ng-container>
</ng-container>
<ng-container *ngIf="total === selected && selected !== 0">
{{ 'all_topics_selected' | translate: { count: selected } }}
</ng-container>
</span>
@import '~@ska-angular/assets/assets/scss/abstracts/_custom-variables.scss';
.topics-summary {
font-size: 0.75rem;
color: $gray-light;
}
import { Component, Input } from '@angular/core';
@Component({
selector: 'teis-proceedings-topics-preview-actions',
templateUrl: './proceedings-topics-preview-actions.component.html',
styleUrls: ['./proceedings-topics-preview-actions.component.scss'],
})
export class ProceedingsTopicsPreviewActionsComponent {
@Input() selected: number;
@Input() total: number;
}
<block [loading]="(loading | async)?.topics && (loading | async)?.detail">
<teis-header
variant="block"
[title]="'Kontrolli teemad'">
<button teis-button *ngIf="canEdit()"
id="editSupervisionPlanTopics"
variant="secondary"
(click)="edit()">
{{ 'edit' | translate }}
</button>
</teis-header>
<alert *ngIf="canceled" variant="info"
[closeable]="false"
[message]="'no_topics' | translate"></alert>
<ng-container *ngIf="!canceled">
<teis-content-collapse [toggleable]="node.selected" *ngFor="let node of (topics | async).tree">
<ng-container preview>
<h4 class="m-0">{{ node?.name | titlecase }}</h4>
</ng-container>
<ng-container preview-actions>
<teis-proceedings-topics-preview-actions
[total]="node.total"
[selected]="node.selected">
</teis-proceedings-topics-preview-actions>
</ng-container>
<ng-container content>
<teis-proceeding-topic-hierarchy
[data]="node?.children">
</teis-proceeding-topic-hierarchy>
</ng-container>
</teis-content-collapse>
</ng-container>
<ng-container *ngIf="detail?.status?.code === 'CLOSED'">
<teis-content-collapse [toggleable]="node?.selected" *ngFor="let node of (topics | async).topics">
<ng-container preview>
<h4 class="m-0">{{ node.topic.inspectionTopicName | titlecase }}</h4>
</ng-container>
<ng-container preview-actions>
<teis-proceedings-topics-preview-actions
[selected]="node?.selected">
</teis-proceedings-topics-preview-actions>
</ng-container>
<ng-container content>
<ng-container *ngFor="let second of node?.topic?.children">
<div class="inspection-topic-hierarchy" *ngIf="second?.children.length">
<div class="inspection-topic-hierarchy__level__second">
<strong>{{ second?.inspectionTopicName }}</strong>
</div>
<div class="inspection-topic-hierarchy__level__third" *ngFor="let third of second?.children">
<p>{{ third?.inspectionTopicName }}</p>
<p class="explanation">{{ third?.inspectionTopicDescription }}</p>
<div class="source">{{'source' | translate}} {{ third?.source?.name }}</div>
</div>
</div>
</ng-container>
</ng-container>
</teis-content-collapse>
</ng-container>
</block>
@import '~@ska-angular/assets/assets/scss/abstracts/_custom-variables.scss';
.inspection-topic-hierarchy {
border-top: $gray-lighter 1px solid;
&:first-child {
border-top: unset;
}
&__level {
&__second {
padding: 1rem;
padding-left: 3rem;
border-bottom: $gray-lighter 1px solid;
&:last-child {
border-bottom: unset;
}
}
&__third {
padding: 1rem;
padding-left: 6rem;
border-bottom: $gray-lighter 1px solid;
.explanation {
font-style: italic;
color: $gray-light;
}
&:last-child {
border-bottom: unset;
}
}
}
}
.source {
text-align: right;
color: $gray-light;
}
\ No newline at end of file
import { Component, OnInit } from '@angular/core';
import { Subscription } from 'rxjs';
import { filter } from 'rxjs/operators';
import { SupervisionPlanTopicsService } from '@teis/services/supervision-plan/supervision-plan-topics.service';
import { AuthorizationService } from '@teis/services/authorization/authorization.service';
import { FeatureFlag } from '@teis/services/feature-flags/feature-flags.model';
import { TeisFeatureFlagsService } from '@teis/services/feature-flags/feature-flags.service';
import { SupervisionPlanFacadeService } from '@official/features/supervision-plan/supervision-plan-facade.service';
import { ProceedingsFacade } from '@official/features/proceedings/proceedings.facade.service';
import { ActivatedRoute } from '@angular/router';
import { ProceedingDetails } from '@teis/services/proceedings/proceedings.model';
import { ProceedingsTopicsEditComponent } from '@official/features/proceedings/containers/proceedings-topics-edit/proceedings-topics-edit.component';
@Component({
selector: 'teis-proceedings-topics',
templateUrl: './proceedings-topics.component.html',
styleUrls: ['./proceedings-topics.component.scss'],
})
export class ProceedingsTopicsComponent implements OnInit {
detail: ProceedingDetails;
public loading = this.facade.loading;
topics = this.proceedingsFacade.topics;
featureFlags = FeatureFlag;
inspectionTopicsVisible: boolean;
canceled: boolean = false;
private subscriptions$: Subscription[];
constructor(private facade: SupervisionPlanFacadeService,
private superVisionPlanService: SupervisionPlanTopicsService,
private authorization: AuthorizationService,
private featureFlagsService: TeisFeatureFlagsService,
private proceedingsFacade: ProceedingsFacade,
public route: ActivatedRoute) {}
ngOnInit() {
this.inspectionTopicsVisible = this.featureFlagsService.isFeatureOn(this.featureFlags.INSPECTIONTOPICS_VISIBLE);
const proceedingDetails$ = this.proceedingsFacade.proceedingDetails.pipe(
filter(proceeding => proceeding !== null),
).subscribe((proceeding) => {
this.detail = proceeding;
if (proceeding.status.code !== 'CANCELED' && proceeding.status.code !== 'CLOSED') {
this.proceedingsFacade.fetchInspectionTopicsWithClassifiers(proceeding.id);
} else if (proceeding.status.code === 'CLOSED') {
this.proceedingsFacade.fetchInspectionTopics(proceeding.id);
} else {
this.canceled = true;
}
});
this.subscriptions$ = [proceedingDetails$];
}
ngOnDestroy() {
this.subscriptions$.forEach(subscription => subscription.unsubscribe());
}
canEdit() {
return this.inspectionTopicsVisible && this.detail.status.code !== 'CLOSED' && this.detail.status.code !== 'CANCELED'
&& this.authorization.hasSomePermission(['TI_MANAGE_PROCEEDINGS']);
}
edit() {
this.facade.openWithComponent(ProceedingsTopicsEditComponent);
}
}
......@@ -44,6 +44,12 @@ import { ViolationsApi } from '@teis/services/violations/violations-api.service'
import { ViolationActsService } from '@teis/services/violation-acts/violation-acts.service';
import { PersonDto } from '@teis/services/person/persons.models';
import { ClassifierItemDto } from '@teis/services/classifiers/classifiers.models';
import {
ProceedingInspectionTopicDto,
SupervisionInspectionTopicsData,
SupervisionPlanTopicsDto
} from '@teis/services/supervision-plan/supervision-plan.models';
import { ProceedingsTopicsService } from '@official/features/proceedings/services/proceedings-topics.service';
interface Loading {
loading?: boolean;
......@@ -92,6 +98,7 @@ export class ProceedingsFacade {
private currentUser: User;
private violationActsFilterSettings: ProceduralAct[];
private violationActPolls$: BehaviorSubject<string[]> = new BehaviorSubject([]);