mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2026-09-09 18:03:21 +00:00
[ACS-5991] ESLint fixes and code quality improvements (#8893)
* prefer-optional-chain: core * prefer-optional-chain: content, fix typings * prefer-optional-chain: process, fix typings * prefer-optional-chain: process-cloud, fix typings, fix ts configs and eslint * [ci: force] sonar errors fixes, insights lib * [ci:force] fix security issues * [ci:force] fix metadata e2e bug, js assignment bugs * [ci:force] fix lint issue * [ci:force] fix tests
This commit is contained in:
+16
-39
@@ -13,14 +13,9 @@ module.exports = {
|
|||||||
],
|
],
|
||||||
overrides: [
|
overrides: [
|
||||||
{
|
{
|
||||||
files: [
|
files: ['*.ts'],
|
||||||
'*.ts'
|
|
||||||
],
|
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
project: [
|
project: [path.join(__dirname, 'tsconfig.json'), path.join(__dirname, 'e2e/tsconfig.e2e.json')],
|
||||||
path.join(__dirname, 'tsconfig.json'),
|
|
||||||
path.join(__dirname, 'e2e/tsconfig.e2e.json')
|
|
||||||
],
|
|
||||||
createDefaultProgram: true
|
createDefaultProgram: true
|
||||||
},
|
},
|
||||||
extends: [
|
extends: [
|
||||||
@@ -28,12 +23,7 @@ module.exports = {
|
|||||||
'plugin:@angular-eslint/ng-cli-compat--formatting-add-on',
|
'plugin:@angular-eslint/ng-cli-compat--formatting-add-on',
|
||||||
'plugin:@angular-eslint/template/process-inline-templates'
|
'plugin:@angular-eslint/template/process-inline-templates'
|
||||||
],
|
],
|
||||||
plugins: [
|
plugins: ['eslint-plugin-unicorn', 'eslint-plugin-rxjs', 'ban', 'license-header'],
|
||||||
'eslint-plugin-unicorn',
|
|
||||||
'eslint-plugin-rxjs',
|
|
||||||
'ban',
|
|
||||||
'license-header'
|
|
||||||
],
|
|
||||||
rules: {
|
rules: {
|
||||||
'ban/ban': [
|
'ban/ban': [
|
||||||
'error',
|
'error',
|
||||||
@@ -49,24 +39,15 @@ module.exports = {
|
|||||||
'error',
|
'error',
|
||||||
{
|
{
|
||||||
type: 'element',
|
type: 'element',
|
||||||
prefix: [
|
prefix: ['adf', 'app'],
|
||||||
'adf',
|
|
||||||
'app'
|
|
||||||
],
|
|
||||||
style: 'kebab-case'
|
style: 'kebab-case'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
'@angular-eslint/directive-selector': [
|
'@angular-eslint/directive-selector': [
|
||||||
'error',
|
'error',
|
||||||
{
|
{
|
||||||
type: [
|
type: ['element', 'attribute'],
|
||||||
'element',
|
prefix: ['adf', 'app'],
|
||||||
'attribute'
|
|
||||||
],
|
|
||||||
prefix: [
|
|
||||||
'adf',
|
|
||||||
'app'
|
|
||||||
],
|
|
||||||
style: 'kebab-case'
|
style: 'kebab-case'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -80,6 +61,7 @@ module.exports = {
|
|||||||
accessibility: 'explicit'
|
accessibility: 'explicit'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
'@typescript-eslint/prefer-optional-chain': 'warn',
|
||||||
'@typescript-eslint/no-inferrable-types': 'off',
|
'@typescript-eslint/no-inferrable-types': 'off',
|
||||||
'@typescript-eslint/no-require-imports': 'off',
|
'@typescript-eslint/no-require-imports': 'off',
|
||||||
'@typescript-eslint/no-var-requires': 'error',
|
'@typescript-eslint/no-var-requires': 'error',
|
||||||
@@ -103,10 +85,8 @@ module.exports = {
|
|||||||
'@typescript-eslint/member-ordering': 'off',
|
'@typescript-eslint/member-ordering': 'off',
|
||||||
'prefer-arrow/prefer-arrow-functions': 'off',
|
'prefer-arrow/prefer-arrow-functions': 'off',
|
||||||
|
|
||||||
'brace-style': [
|
'brace-style': 'off',
|
||||||
'error',
|
'@typescript-eslint/brace-style': 'error',
|
||||||
'1tbs'
|
|
||||||
],
|
|
||||||
'comma-dangle': 'error',
|
'comma-dangle': 'error',
|
||||||
'default-case': 'error',
|
'default-case': 'error',
|
||||||
'import/order': 'off',
|
'import/order': 'off',
|
||||||
@@ -158,20 +138,21 @@ module.exports = {
|
|||||||
allowTernary: true
|
allowTernary: true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
'license-header/header': ['error',
|
'license-header/header': [
|
||||||
|
'error',
|
||||||
[
|
[
|
||||||
'/*!',
|
'/*!',
|
||||||
' * @license',
|
' * @license',
|
||||||
' * Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.',
|
' * Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.',
|
||||||
' *',
|
' *',
|
||||||
' * Licensed under the Apache License, Version 2.0 (the \"License\");',
|
' * Licensed under the Apache License, Version 2.0 (the "License");',
|
||||||
' * you may not use this file except in compliance with the License.',
|
' * you may not use this file except in compliance with the License.',
|
||||||
' * You may obtain a copy of the License at',
|
' * You may obtain a copy of the License at',
|
||||||
' *',
|
' *',
|
||||||
' * http://www.apache.org/licenses/LICENSE-2.0',
|
' * http://www.apache.org/licenses/LICENSE-2.0',
|
||||||
' *',
|
' *',
|
||||||
' * Unless required by applicable law or agreed to in writing, software',
|
' * Unless required by applicable law or agreed to in writing, software',
|
||||||
' * distributed under the License is distributed on an \"AS IS\" BASIS,',
|
' * distributed under the License is distributed on an "AS IS" BASIS,',
|
||||||
' * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.',
|
' * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.',
|
||||||
' * See the License for the specific language governing permissions and',
|
' * See the License for the specific language governing permissions and',
|
||||||
' * limitations under the License.',
|
' * limitations under the License.',
|
||||||
@@ -181,13 +162,9 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
files: [
|
files: ['*.html'],
|
||||||
'*.html'
|
extends: ['plugin:@angular-eslint/template/recommended'],
|
||||||
],
|
|
||||||
extends: [
|
|
||||||
'plugin:@angular-eslint/template/recommended'
|
|
||||||
],
|
|
||||||
rules: {}
|
rules: {}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
};
|
||||||
|
|||||||
+8
-30
@@ -1,14 +1,10 @@
|
|||||||
path = require('path');
|
path = require('path');
|
||||||
module.exports = {
|
module.exports = {
|
||||||
extends: '../.eslintrc.js',
|
extends: '../.eslintrc.js',
|
||||||
ignorePatterns: [
|
ignorePatterns: ['!**/*'],
|
||||||
'!**/*'
|
|
||||||
],
|
|
||||||
overrides: [
|
overrides: [
|
||||||
{
|
{
|
||||||
files: [
|
files: ['*.ts'],
|
||||||
'*.ts'
|
|
||||||
],
|
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
project: [
|
project: [
|
||||||
path.join(__dirname, 'tsconfig.app.json'),
|
path.join(__dirname, 'tsconfig.app.json'),
|
||||||
@@ -17,33 +13,21 @@ module.exports = {
|
|||||||
],
|
],
|
||||||
createDefaultProgram: true
|
createDefaultProgram: true
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: ['eslint-plugin-unicorn', 'eslint-plugin-rxjs'],
|
||||||
'eslint-plugin-unicorn',
|
|
||||||
'eslint-plugin-rxjs'
|
|
||||||
],
|
|
||||||
rules: {
|
rules: {
|
||||||
'@angular-eslint/component-selector': [
|
'@angular-eslint/component-selector': [
|
||||||
'error',
|
'error',
|
||||||
{
|
{
|
||||||
type: 'element',
|
type: 'element',
|
||||||
prefix: [
|
prefix: ['adf', 'app'],
|
||||||
'adf',
|
|
||||||
'app'
|
|
||||||
],
|
|
||||||
style: 'kebab-case'
|
style: 'kebab-case'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
'@angular-eslint/directive-selector': [
|
'@angular-eslint/directive-selector': [
|
||||||
'error',
|
'error',
|
||||||
{
|
{
|
||||||
type: [
|
type: ['element', 'attribute'],
|
||||||
'element',
|
prefix: ['adf', 'app'],
|
||||||
'attribute'
|
|
||||||
],
|
|
||||||
prefix: [
|
|
||||||
'adf',
|
|
||||||
'app'
|
|
||||||
],
|
|
||||||
style: 'kebab-case'
|
style: 'kebab-case'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -60,10 +44,6 @@ module.exports = {
|
|||||||
'@typescript-eslint/no-inferrable-types': 'off',
|
'@typescript-eslint/no-inferrable-types': 'off',
|
||||||
'@typescript-eslint/no-require-imports': 'off',
|
'@typescript-eslint/no-require-imports': 'off',
|
||||||
'@typescript-eslint/no-var-requires': 'error',
|
'@typescript-eslint/no-var-requires': 'error',
|
||||||
'brace-style': [
|
|
||||||
'error',
|
|
||||||
'1tbs'
|
|
||||||
],
|
|
||||||
'comma-dangle': 'error',
|
'comma-dangle': 'error',
|
||||||
'default-case': 'error',
|
'default-case': 'error',
|
||||||
'import/order': 'off',
|
'import/order': 'off',
|
||||||
@@ -86,10 +66,8 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
files: [
|
files: ['*.html'],
|
||||||
'*.html'
|
|
||||||
],
|
|
||||||
rules: {}
|
rules: {}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* eslint-disable brace-style */
|
|
||||||
import { test as base } from '@playwright/test';
|
import { test as base } from '@playwright/test';
|
||||||
import { BaseStories } from '../../page-object';
|
import { BaseStories } from '../../page-object';
|
||||||
import { ComponentTitles } from '../../models/component-titles.model';
|
import { ComponentTitles } from '../../models/component-titles.model';
|
||||||
@@ -29,9 +28,15 @@ interface Pages {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const test = base.extend<Pages>({
|
export const test = base.extend<Pages>({
|
||||||
processServicesCloud: async ({ page }, use) => { await use(new BaseStories(page, ComponentTitles.processServicesCloud)); },
|
processServicesCloud: async ({ page }, use) => {
|
||||||
peopleComponent: async ({ page }, use) => { await use(new PeopleComponent(page)); },
|
await use(new BaseStories(page, ComponentTitles.processServicesCloud));
|
||||||
groupComponent: async ({ page }, use) => { await use(new GroupComponent(page)); }
|
},
|
||||||
|
peopleComponent: async ({ page }, use) => {
|
||||||
|
await use(new PeopleComponent(page));
|
||||||
|
},
|
||||||
|
groupComponent: async ({ page }, use) => {
|
||||||
|
await use(new GroupComponent(page));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export { expect } from '@playwright/test';
|
export { expect } from '@playwright/test';
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import { $, by, element, Key, protractor, ElementFinder } from 'protractor';
|
|||||||
import { BrowserActions, BrowserVisibility, DropdownPage, TestElement, Logger } from '@alfresco/adf-testing';
|
import { BrowserActions, BrowserVisibility, DropdownPage, TestElement, Logger } from '@alfresco/adf-testing';
|
||||||
|
|
||||||
export class MetadataViewPage {
|
export class MetadataViewPage {
|
||||||
|
|
||||||
title = $(`div[info-drawer-title]`);
|
title = $(`div[info-drawer-title]`);
|
||||||
expandedAspect = $(`mat-expansion-panel-header[aria-expanded='true']`);
|
expandedAspect = $(`mat-expansion-panel-header[aria-expanded='true']`);
|
||||||
aspectTitle = `mat-panel-title`;
|
aspectTitle = `mat-panel-title`;
|
||||||
@@ -48,8 +47,10 @@ export class MetadataViewPage {
|
|||||||
saveMetadataButton = $(`[data-automation-id='save-metadata']`);
|
saveMetadataButton = $(`[data-automation-id='save-metadata']`);
|
||||||
resetMetadataButton = $(`[data-automation-id='reset-metadata']`);
|
resetMetadataButton = $(`[data-automation-id='reset-metadata']`);
|
||||||
|
|
||||||
private getMetadataGroupLocator = async (groupName: string): Promise<ElementFinder> => $(`mat-expansion-panel[data-automation-id="adf-metadata-group-${groupName}"]`);
|
private getMetadataGroupLocator = async (groupName: string): Promise<ElementFinder> =>
|
||||||
private getExpandedMetadataGroupLocator = async (groupName: string): Promise<ElementFinder> => $(`mat-expansion-panel[data-automation-id="adf-metadata-group-${groupName}"] > mat-expansion-panel-header`);
|
$(`mat-expansion-panel[data-automation-id="adf-metadata-group-${groupName}"]`);
|
||||||
|
private getExpandedMetadataGroupLocator = async (groupName: string): Promise<ElementFinder> =>
|
||||||
|
$(`mat-expansion-panel[data-automation-id="adf-metadata-group-${groupName}"] > mat-expansion-panel-header`);
|
||||||
|
|
||||||
async getTitle(): Promise<string> {
|
async getTitle(): Promise<string> {
|
||||||
return BrowserActions.getText(this.title);
|
return BrowserActions.getText(this.title);
|
||||||
@@ -132,7 +133,9 @@ export class MetadataViewPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async clickOnPropertiesTab(): Promise<void> {
|
async clickOnPropertiesTab(): Promise<void> {
|
||||||
const propertiesTab = element(by.cssContainingText(`.adf-info-drawer-layout-content div.mat-tab-labels div .mat-tab-label-content`, `Properties`));
|
const propertiesTab = element(
|
||||||
|
by.cssContainingText(`.adf-info-drawer-layout-content div.mat-tab-labels div .mat-tab-label-content`, `Properties`)
|
||||||
|
);
|
||||||
await BrowserActions.click(propertiesTab);
|
await BrowserActions.click(propertiesTab);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,7 +211,9 @@ export class MetadataViewPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getMetadataGroupTitle(groupName: string): Promise<string> {
|
async getMetadataGroupTitle(groupName: string): Promise<string> {
|
||||||
const group = $('mat-expansion-panel[data-automation-id="adf-metadata-group-' + groupName + '"] > mat-expansion-panel-header > span > mat-panel-title');
|
const group = $(
|
||||||
|
'mat-expansion-panel[data-automation-id="adf-metadata-group-' + groupName + '"] > mat-expansion-panel-header > span > mat-panel-title'
|
||||||
|
);
|
||||||
return BrowserActions.getText(group);
|
return BrowserActions.getText(group);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,7 +230,7 @@ export class MetadataViewPage {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
await type.waitVisible();
|
await type.waitVisible();
|
||||||
const isPresent = type.isPresent();
|
const isPresent = await type.isPresent();
|
||||||
if (isPresent) {
|
if (isPresent) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,43 +16,41 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
var FormDefinitionFieldModel = function (details) {
|
var FormDefinitionFieldModel = function (details) {
|
||||||
|
this.fieldType = undefined;
|
||||||
this.fieldType;
|
this.id = undefined;
|
||||||
this.id;
|
this.name = undefined;
|
||||||
this.name;
|
this.value = undefined;
|
||||||
this.value;
|
this.type = undefined;
|
||||||
this.type;
|
this.required = undefined;
|
||||||
this.required;
|
this.readOnly = undefined;
|
||||||
this.readOnly;
|
this.overrideId = undefined;
|
||||||
this.overrideId;
|
this.colspan = undefined;
|
||||||
this.colspan;
|
this.placeholder = undefined;
|
||||||
this.placeholder;
|
this.minLength = undefined;
|
||||||
this.minLength;
|
this.maxLength = undefined;
|
||||||
this.maxLength;
|
this.minValue = undefined;
|
||||||
this.minValue;
|
this.maxValue = undefined;
|
||||||
this.maxValue;
|
this.regexPattern = undefined;
|
||||||
this.regexPattern;
|
this.optionType = undefined;
|
||||||
this.optionType;
|
this.hasEmptyValue = undefined;
|
||||||
this.hasEmptyValue;
|
this.options = undefined;
|
||||||
this.options;
|
this.restUrl = undefined;
|
||||||
this.restUrl;
|
this.restResponsePath = undefined;
|
||||||
this.restResponsePath;
|
this.restIdProperty = undefined;
|
||||||
this.restIdProperty;
|
this.setRestLabelProperty = undefined;
|
||||||
this.setRestLabelProperty;
|
this.tab = undefined;
|
||||||
this.tab;
|
this.className = undefined;
|
||||||
this.className;
|
this.dateDisplayFormat = undefined;
|
||||||
this.dateDisplayFormat;
|
|
||||||
this.layout = {};
|
this.layout = {};
|
||||||
this.sizeX;
|
this.sizeX = undefined;
|
||||||
this.sizeY;
|
this.sizeY = undefined;
|
||||||
this.row;
|
this.row = undefined;
|
||||||
this.col;
|
this.col = undefined;
|
||||||
this.columnDefinitions;
|
this.columnDefinitions = undefined;
|
||||||
this.visibilityCondition;
|
this.visibilityCondition = undefined;
|
||||||
this.numberOfColumns;
|
this.numberOfColumns = undefined;
|
||||||
this.fields = {};
|
this.fields = {};
|
||||||
|
|
||||||
Object.assign(this, details);
|
Object.assign(this, details);
|
||||||
};
|
};
|
||||||
module.exports = FormDefinitionFieldModel;
|
module.exports = FormDefinitionFieldModel;
|
||||||
|
|
||||||
|
|||||||
@@ -16,14 +16,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
var FormModel = function (details) {
|
var FormModel = function (details) {
|
||||||
|
this.id = undefined;
|
||||||
this.id;
|
this.name = undefined;
|
||||||
this.name;
|
this.description = undefined;
|
||||||
this.description;
|
this.modelId = undefined;
|
||||||
this.modelId;
|
this.appDefinitionId = undefined;
|
||||||
this.appDefinitionId;
|
this.appDeploymentId = undefined;
|
||||||
this.appDeploymentId;
|
this.tenantId = undefined;
|
||||||
this.tenantId;
|
|
||||||
|
|
||||||
this.getName = function () {
|
this.getName = function () {
|
||||||
return this.name;
|
return this.name;
|
||||||
|
|||||||
@@ -23,9 +23,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
var Task = function (details) {
|
var Task = function (details) {
|
||||||
|
this.processInstanceId = undefined;
|
||||||
this.processInstanceId;
|
this.sort = undefined;
|
||||||
this.sort;
|
|
||||||
|
|
||||||
Object.assign(this, details);
|
Object.assign(this, details);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -16,11 +16,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
var TaskAssigneeModel = function (details) {
|
var TaskAssigneeModel = function (details) {
|
||||||
|
this.id = undefined;
|
||||||
this.id;
|
this.firstName = undefined;
|
||||||
this.firstName;
|
this.lastName = undefined;
|
||||||
this.lastName;
|
this.email = undefined;
|
||||||
this.email;
|
|
||||||
|
|
||||||
this.getFirstName = function () {
|
this.getFirstName = function () {
|
||||||
return this.firstName;
|
return this.firstName;
|
||||||
@@ -38,12 +37,11 @@ var TaskAssigneeModel = function (details) {
|
|||||||
return this.email;
|
return this.email;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.getEntireName = function() {
|
this.getEntireName = function () {
|
||||||
return this.firstName + " " + this.getLastName();
|
return this.firstName + ' ' + this.getLastName();
|
||||||
};
|
};
|
||||||
|
|
||||||
Object.assign(this, details);
|
Object.assign(this, details);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = TaskAssigneeModel;
|
module.exports = TaskAssigneeModel;
|
||||||
|
|||||||
+12
-13
@@ -18,19 +18,18 @@
|
|||||||
var TaskAssigneeModel = require('./TaskAssigneeModel');
|
var TaskAssigneeModel = require('./TaskAssigneeModel');
|
||||||
|
|
||||||
var TaskModel = function (details) {
|
var TaskModel = function (details) {
|
||||||
|
this.id = undefined;
|
||||||
this.id;
|
this.name = undefined;
|
||||||
this.name;
|
this.description = undefined;
|
||||||
this.description;
|
this.category = undefined;
|
||||||
this.category;
|
this.created = undefined;
|
||||||
this.created;
|
this.dueDate = undefined;
|
||||||
this.dueDate;
|
this.priority = undefined;
|
||||||
this.priority;
|
this.parentTaskName = undefined;
|
||||||
this.parentTaskName;
|
this.parentTaskId = undefined;
|
||||||
this.parentTaskId;
|
this.formKey = undefined;
|
||||||
this.formKey;
|
this.duration = undefined;
|
||||||
this.duration;
|
this.endDate = undefined;
|
||||||
this.endDate;
|
|
||||||
this.assignee = {};
|
this.assignee = {};
|
||||||
|
|
||||||
this.getName = function () {
|
this.getName = function () {
|
||||||
|
|||||||
@@ -62,10 +62,6 @@
|
|||||||
"@typescript-eslint/no-inferrable-types": "off",
|
"@typescript-eslint/no-inferrable-types": "off",
|
||||||
"@typescript-eslint/no-require-imports": "off",
|
"@typescript-eslint/no-require-imports": "off",
|
||||||
"@typescript-eslint/no-var-requires": "error",
|
"@typescript-eslint/no-var-requires": "error",
|
||||||
"brace-style": [
|
|
||||||
"error",
|
|
||||||
"1tbs"
|
|
||||||
],
|
|
||||||
"comma-dangle": "error",
|
"comma-dangle": "error",
|
||||||
"default-case": "error",
|
"default-case": "error",
|
||||||
"import/order": "off",
|
"import/order": "off",
|
||||||
|
|||||||
@@ -18,33 +18,24 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { Observable, from, throwError } from 'rxjs';
|
import { Observable, from, throwError } from 'rxjs';
|
||||||
import { AlfrescoApiService, LogService } from '@alfresco/adf-core';
|
import { AlfrescoApiService, LogService } from '@alfresco/adf-core';
|
||||||
import {
|
import { AuditApi, AuditAppPaging, AuditAppEntry, AuditApp, AuditBodyUpdate, AuditEntryPaging, AuditEntryEntry } from '@alfresco/js-api';
|
||||||
AuditApi,
|
|
||||||
AuditAppPaging,
|
|
||||||
AuditAppEntry,
|
|
||||||
AuditApp,
|
|
||||||
AuditBodyUpdate,
|
|
||||||
AuditEntryPaging,
|
|
||||||
AuditEntryEntry
|
|
||||||
} from '@alfresco/js-api';
|
|
||||||
import { catchError } from 'rxjs/operators';
|
import { catchError } from 'rxjs/operators';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class AuditService {
|
export class AuditService {
|
||||||
|
|
||||||
private _auditApi: AuditApi;
|
private _auditApi: AuditApi;
|
||||||
get auditApi(): AuditApi {
|
get auditApi(): AuditApi {
|
||||||
this._auditApi = this._auditApi ?? new AuditApi(this.apiService.getInstance());
|
this._auditApi = this._auditApi ?? new AuditApi(this.apiService.getInstance());
|
||||||
return this._auditApi;
|
return this._auditApi;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(private apiService: AlfrescoApiService, private logService: LogService) {
|
constructor(private apiService: AlfrescoApiService, private logService: LogService) {}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a list of audit applications.
|
* Gets a list of audit applications.
|
||||||
|
*
|
||||||
* @param opts Options.
|
* @param opts Options.
|
||||||
* @returns a list of the audit applications.
|
* @returns a list of the audit applications.
|
||||||
*/
|
*/
|
||||||
@@ -53,14 +44,12 @@ export class AuditService {
|
|||||||
skipCount: 0
|
skipCount: 0
|
||||||
};
|
};
|
||||||
const queryOptions = Object.assign({}, defaultOptions, opts);
|
const queryOptions = Object.assign({}, defaultOptions, opts);
|
||||||
return from(this.auditApi.listAuditApps(queryOptions))
|
return from(this.auditApi.listAuditApps(queryOptions)).pipe(catchError((err: any) => this.handleError(err)));
|
||||||
.pipe(
|
|
||||||
catchError((err: any) => this.handleError(err))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get audit application info.
|
* Get audit application info.
|
||||||
|
*
|
||||||
* @param auditApplicationId The identifier of an audit application.
|
* @param auditApplicationId The identifier of an audit application.
|
||||||
* @param opts Options.
|
* @param opts Options.
|
||||||
* @returns status of an audit application.
|
* @returns status of an audit application.
|
||||||
@@ -70,14 +59,12 @@ export class AuditService {
|
|||||||
auditApplicationId
|
auditApplicationId
|
||||||
};
|
};
|
||||||
const queryOptions = Object.assign({}, defaultOptions, opts);
|
const queryOptions = Object.assign({}, defaultOptions, opts);
|
||||||
return from(this.auditApi.getAuditApp(queryOptions))
|
return from(this.auditApi.getAuditApp(queryOptions)).pipe(catchError((err: any) => this.handleError(err)));
|
||||||
.pipe(
|
|
||||||
catchError((err: any) => this.handleError(err))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update audit application info.
|
* Update audit application info.
|
||||||
|
*
|
||||||
* @param auditApplicationId The identifier of an audit application.
|
* @param auditApplicationId The identifier of an audit application.
|
||||||
* @param auditAppBodyUpdate The audit application to update.
|
* @param auditAppBodyUpdate The audit application to update.
|
||||||
* @param opts Options.
|
* @param opts Options.
|
||||||
@@ -86,14 +73,14 @@ export class AuditService {
|
|||||||
updateAuditApp(auditApplicationId: string, auditAppBodyUpdate: boolean, opts?: any): Observable<AuditApp | any> {
|
updateAuditApp(auditApplicationId: string, auditAppBodyUpdate: boolean, opts?: any): Observable<AuditApp | any> {
|
||||||
const defaultOptions = {};
|
const defaultOptions = {};
|
||||||
const queryOptions = Object.assign({}, defaultOptions, opts);
|
const queryOptions = Object.assign({}, defaultOptions, opts);
|
||||||
return from(this.auditApi.updateAuditApp(auditApplicationId, new AuditBodyUpdate({ isEnabled: auditAppBodyUpdate }), queryOptions))
|
return from(this.auditApi.updateAuditApp(auditApplicationId, new AuditBodyUpdate({ isEnabled: auditAppBodyUpdate }), queryOptions)).pipe(
|
||||||
.pipe(
|
|
||||||
catchError((err: any) => this.handleError(err))
|
catchError((err: any) => this.handleError(err))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List audit entries for an audit application.
|
* List audit entries for an audit application.
|
||||||
|
*
|
||||||
* @param auditApplicationId The identifier of an audit application.
|
* @param auditApplicationId The identifier of an audit application.
|
||||||
* @param opts Options.
|
* @param opts Options.
|
||||||
* @returns a list of audit entries.
|
* @returns a list of audit entries.
|
||||||
@@ -104,14 +91,14 @@ export class AuditService {
|
|||||||
maxItems: 100
|
maxItems: 100
|
||||||
};
|
};
|
||||||
const queryOptions = Object.assign({}, defaultOptions, opts);
|
const queryOptions = Object.assign({}, defaultOptions, opts);
|
||||||
return from(this.auditApi.listAuditEntriesForAuditApp(auditApplicationId, queryOptions))
|
return from(this.auditApi.listAuditEntriesForAuditApp(auditApplicationId, queryOptions)).pipe(
|
||||||
.pipe(
|
|
||||||
catchError((err: any) => this.handleError(err))
|
catchError((err: any) => this.handleError(err))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get audit entry.
|
* Get audit entry.
|
||||||
|
*
|
||||||
* @param auditApplicationId The identifier of an audit application.
|
* @param auditApplicationId The identifier of an audit application.
|
||||||
* @param auditEntryId The identifier of an audit entry.
|
* @param auditEntryId The identifier of an audit entry.
|
||||||
* @param opts Options.
|
* @param opts Options.
|
||||||
@@ -120,14 +107,14 @@ export class AuditService {
|
|||||||
getAuditEntry(auditApplicationId: string, auditEntryId: string, opts?: any): Observable<AuditEntryEntry> {
|
getAuditEntry(auditApplicationId: string, auditEntryId: string, opts?: any): Observable<AuditEntryEntry> {
|
||||||
const defaultOptions = {};
|
const defaultOptions = {};
|
||||||
const queryOptions = Object.assign({}, defaultOptions, opts);
|
const queryOptions = Object.assign({}, defaultOptions, opts);
|
||||||
return from(this.auditApi.getAuditEntry(auditApplicationId, auditEntryId, queryOptions))
|
return from(this.auditApi.getAuditEntry(auditApplicationId, auditEntryId, queryOptions)).pipe(
|
||||||
.pipe(
|
|
||||||
catchError((err: any) => this.handleError(err))
|
catchError((err: any) => this.handleError(err))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List audit entries for a node.
|
* List audit entries for a node.
|
||||||
|
*
|
||||||
* @param nodeId The identifier of a node.
|
* @param nodeId The identifier of a node.
|
||||||
* @param opts Options.
|
* @param opts Options.
|
||||||
* @returns
|
* @returns
|
||||||
@@ -137,36 +124,29 @@ export class AuditService {
|
|||||||
nodeId
|
nodeId
|
||||||
};
|
};
|
||||||
const queryOptions = Object.assign({}, defaultOptions, opts);
|
const queryOptions = Object.assign({}, defaultOptions, opts);
|
||||||
return from(this.auditApi.listAuditEntriesForNode(queryOptions))
|
return from(this.auditApi.listAuditEntriesForNode(queryOptions)).pipe(catchError((err: any) => this.handleError(err)));
|
||||||
.pipe(
|
|
||||||
catchError((err: any) => this.handleError(err))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Permanently delete audit entries for an audit application.
|
* Permanently delete audit entries for an audit application.
|
||||||
|
*
|
||||||
* @param auditApplicationId The identifier of an audit application.
|
* @param auditApplicationId The identifier of an audit application.
|
||||||
* @param where Audit entries to permanently delete for an audit application, given an inclusive time period or range of ids.
|
* @param where Audit entries to permanently delete for an audit application, given an inclusive time period or range of ids.
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
deleteAuditEntries(auditApplicationId: string, where: string): Observable<any> {
|
deleteAuditEntries(auditApplicationId: string, where: string): Observable<any> {
|
||||||
return from(this.auditApi.deleteAuditEntriesForAuditApp(auditApplicationId, where))
|
return from(this.auditApi.deleteAuditEntriesForAuditApp(auditApplicationId, where)).pipe(catchError((err: any) => this.handleError(err)));
|
||||||
.pipe(
|
|
||||||
catchError((err: any) => this.handleError(err))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Permanently delete an audit entry.
|
* Permanently delete an audit entry.
|
||||||
|
*
|
||||||
* @param auditApplicationId The identifier of an audit application.
|
* @param auditApplicationId The identifier of an audit application.
|
||||||
* @param auditEntryId The identifier of an audit entry.
|
* @param auditEntryId The identifier of an audit entry.
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
deleteAuditEntry(auditApplicationId: string, auditEntryId: string): Observable<any> {
|
deleteAuditEntry(auditApplicationId: string, auditEntryId: string): Observable<any> {
|
||||||
return from(this.auditApi.deleteAuditEntry(auditApplicationId, auditEntryId))
|
return from(this.auditApi.deleteAuditEntry(auditApplicationId, auditEntryId)).pipe(catchError((err: any) => this.handleError(err)));
|
||||||
.pipe(
|
|
||||||
catchError((err: any) => this.handleError(err))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleError(error: any): any {
|
private handleError(error: any): any {
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ export class BreadcrumbComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
parseRoute(node: Node): PathElement[] {
|
parseRoute(node: Node): PathElement[] {
|
||||||
if (node && node.path) {
|
if (node?.path) {
|
||||||
const route = (node.path.elements || []).slice();
|
const route = (node.path.elements || []).slice();
|
||||||
|
|
||||||
route.push({
|
route.push({
|
||||||
|
|||||||
@@ -43,27 +43,27 @@ export class EcmUserModel {
|
|||||||
capabilities?: Capabilities;
|
capabilities?: Capabilities;
|
||||||
|
|
||||||
constructor(obj?: any) {
|
constructor(obj?: any) {
|
||||||
this.id = obj && obj.id || null;
|
this.id = obj?.id || null;
|
||||||
this.firstName = obj && obj.firstName;
|
this.firstName = obj?.firstName;
|
||||||
this.lastName = obj && obj.lastName;
|
this.lastName = obj?.lastName;
|
||||||
this.description = obj && obj.description || null;
|
this.description = obj?.description || null;
|
||||||
this.avatarId = obj && obj.avatarId || null;
|
this.avatarId = obj?.avatarId || null;
|
||||||
this.email = obj && obj.email || null;
|
this.email = obj?.email || null;
|
||||||
this.skypeId = obj && obj.skypeId;
|
this.skypeId = obj?.skypeId;
|
||||||
this.googleId = obj && obj.googleId;
|
this.googleId = obj?.googleId;
|
||||||
this.instantMessageId = obj && obj.instantMessageId;
|
this.instantMessageId = obj?.instantMessageId;
|
||||||
this.jobTitle = obj && obj.jobTitle || null;
|
this.jobTitle = obj?.jobTitle || null;
|
||||||
this.location = obj && obj.location || null;
|
this.location = obj?.location || null;
|
||||||
this.company = obj && obj.company;
|
this.company = obj?.company;
|
||||||
this.mobile = obj && obj.mobile;
|
this.mobile = obj?.mobile;
|
||||||
this.telephone = obj && obj.telephone;
|
this.telephone = obj?.telephone;
|
||||||
this.statusUpdatedAt = obj && obj.statusUpdatedAt;
|
this.statusUpdatedAt = obj?.statusUpdatedAt;
|
||||||
this.userStatus = obj && obj.userStatus;
|
this.userStatus = obj?.userStatus;
|
||||||
this.enabled = obj && obj.enabled;
|
this.enabled = obj?.enabled;
|
||||||
this.emailNotificationsEnabled = obj && obj.emailNotificationsEnabled;
|
this.emailNotificationsEnabled = obj?.emailNotificationsEnabled;
|
||||||
this.aspectNames = obj && obj.aspectNames;
|
this.aspectNames = obj?.aspectNames;
|
||||||
this.properties = obj && obj.properties;
|
this.properties = obj?.properties;
|
||||||
this.capabilities = obj && obj.capabilities;
|
this.capabilities = obj?.capabilities;
|
||||||
}
|
}
|
||||||
|
|
||||||
isAdmin(): boolean {
|
isAdmin(): boolean {
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ export class ContentService {
|
|||||||
(currentPermission) => currentPermission.authorityId === userId
|
(currentPermission) => currentPermission.authorityId === userId
|
||||||
);
|
);
|
||||||
if (permissions.length) {
|
if (permissions.length) {
|
||||||
if (permission && permission.startsWith('!')) {
|
if (permission?.startsWith('!')) {
|
||||||
hasPermissions = !permissions.find((currentPermission) => currentPermission.name === permission.replace('!', ''));
|
hasPermissions = !permissions.find((currentPermission) => currentPermission.name === permission.replace('!', ''));
|
||||||
} else {
|
} else {
|
||||||
hasPermissions = !!permissions.find((currentPermission) => currentPermission.name === permission);
|
hasPermissions = !!permissions.find((currentPermission) => currentPermission.name === permission);
|
||||||
@@ -99,7 +99,7 @@ export class ContentService {
|
|||||||
hasPermissions = true;
|
hasPermissions = true;
|
||||||
} else if (permission === PermissionsEnum.NOT_CONSUMER) {
|
} else if (permission === PermissionsEnum.NOT_CONSUMER) {
|
||||||
hasPermissions = false;
|
hasPermissions = false;
|
||||||
} else if (permission && permission.startsWith('!')) {
|
} else if (permission?.startsWith('!')) {
|
||||||
hasPermissions = true;
|
hasPermissions = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -117,8 +117,8 @@ export class ContentService {
|
|||||||
hasAllowableOperations(node: Node, allowableOperation: AllowableOperationsEnum | string): boolean {
|
hasAllowableOperations(node: Node, allowableOperation: AllowableOperationsEnum | string): boolean {
|
||||||
let hasAllowableOperations = false;
|
let hasAllowableOperations = false;
|
||||||
|
|
||||||
if (node && node.allowableOperations) {
|
if (node?.allowableOperations) {
|
||||||
if (allowableOperation && allowableOperation.startsWith('!')) {
|
if (allowableOperation?.startsWith('!')) {
|
||||||
hasAllowableOperations = !node.allowableOperations.find(
|
hasAllowableOperations = !node.allowableOperations.find(
|
||||||
(currentOperation) => currentOperation === allowableOperation.replace('!', '')
|
(currentOperation) => currentOperation === allowableOperation.replace('!', '')
|
||||||
);
|
);
|
||||||
@@ -126,7 +126,7 @@ export class ContentService {
|
|||||||
hasAllowableOperations = !!node.allowableOperations.find((currentOperation) => currentOperation === allowableOperation);
|
hasAllowableOperations = !!node.allowableOperations.find((currentOperation) => currentOperation === allowableOperation);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (allowableOperation && allowableOperation.startsWith('!')) {
|
if (allowableOperation?.startsWith('!')) {
|
||||||
hasAllowableOperations = true;
|
hasAllowableOperations = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -221,7 +221,7 @@ export class NodesApiService {
|
|||||||
private cleanMetadataFromSemicolon(nodeEntry: NodeEntry): NodeMetadata {
|
private cleanMetadataFromSemicolon(nodeEntry: NodeEntry): NodeMetadata {
|
||||||
const metadata = {};
|
const metadata = {};
|
||||||
|
|
||||||
if (nodeEntry && nodeEntry.entry.properties) {
|
if (nodeEntry?.entry.properties) {
|
||||||
for (const key in nodeEntry.entry.properties) {
|
for (const key in nodeEntry.entry.properties) {
|
||||||
if (key) {
|
if (key) {
|
||||||
if (key.indexOf(':') !== -1) {
|
if (key.indexOf(':') !== -1) {
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ export class SitesService {
|
|||||||
*/
|
*/
|
||||||
getSiteNameFromNodePath(node: Node): string {
|
getSiteNameFromNodePath(node: Node): string {
|
||||||
let siteName = '';
|
let siteName = '';
|
||||||
if (node.path && node.path.elements) {
|
if (node.path?.elements) {
|
||||||
const foundNode = node.path.elements.find((pathNode) => pathNode.nodeType === 'st:site' && pathNode.name !== 'Sites');
|
const foundNode = node.path.elements.find((pathNode) => pathNode.nodeType === 'st:site' && pathNode.name !== 'Sites');
|
||||||
siteName = foundNode ? foundNode.name : '';
|
siteName = foundNode ? foundNode.name : '';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,12 +18,7 @@
|
|||||||
import { EventEmitter, Injectable } from '@angular/core';
|
import { EventEmitter, Injectable } from '@angular/core';
|
||||||
import { Minimatch } from 'minimatch';
|
import { Minimatch } from 'minimatch';
|
||||||
import { Subject } from 'rxjs';
|
import { Subject } from 'rxjs';
|
||||||
import {
|
import { FileUploadCompleteEvent, FileUploadDeleteEvent, FileUploadErrorEvent, FileUploadEvent } from '../events/file.event';
|
||||||
FileUploadCompleteEvent,
|
|
||||||
FileUploadDeleteEvent,
|
|
||||||
FileUploadErrorEvent,
|
|
||||||
FileUploadEvent
|
|
||||||
} from '../events/file.event';
|
|
||||||
import { FileModel, FileUploadProgress, FileUploadStatus } from '../models/file.model';
|
import { FileModel, FileUploadProgress, FileUploadStatus } from '../models/file.model';
|
||||||
import { AppConfigService, AlfrescoApiService } from '@alfresco/adf-core';
|
import { AppConfigService, AlfrescoApiService } from '@alfresco/adf-core';
|
||||||
import { filter } from 'rxjs/operators';
|
import { filter } from 'rxjs/operators';
|
||||||
@@ -81,10 +76,9 @@ export class UploadService {
|
|||||||
constructor(
|
constructor(
|
||||||
protected apiService: AlfrescoApiService,
|
protected apiService: AlfrescoApiService,
|
||||||
private appConfigService: AppConfigService,
|
private appConfigService: AppConfigService,
|
||||||
private discoveryApiService: DiscoveryApiService) {
|
private discoveryApiService: DiscoveryApiService
|
||||||
|
) {
|
||||||
this.discoveryApiService.ecmProductInfo$.pipe(filter(info => !!info))
|
this.discoveryApiService.ecmProductInfo$.pipe(filter((info) => !!info)).subscribe(({ status }) => {
|
||||||
.subscribe(({status}) => {
|
|
||||||
this.isThumbnailGenerationEnabled = status.isThumbnailGenerationEnabled;
|
this.isThumbnailGenerationEnabled = status.isThumbnailGenerationEnabled;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -108,8 +102,17 @@ export class UploadService {
|
|||||||
* @returns True if files in the queue are still uploading, false otherwise
|
* @returns True if files in the queue are still uploading, false otherwise
|
||||||
*/
|
*/
|
||||||
isUploading(): boolean {
|
isUploading(): boolean {
|
||||||
const finishedFileStates = [FileUploadStatus.Complete, FileUploadStatus.Cancelled, FileUploadStatus.Aborted, FileUploadStatus.Error, FileUploadStatus.Deleted];
|
const finishedFileStates = [
|
||||||
return this.queue.reduce((stillUploading: boolean, currentFile: FileModel) => stillUploading || finishedFileStates.indexOf(currentFile.status) === -1, false);
|
FileUploadStatus.Complete,
|
||||||
|
FileUploadStatus.Cancelled,
|
||||||
|
FileUploadStatus.Aborted,
|
||||||
|
FileUploadStatus.Error,
|
||||||
|
FileUploadStatus.Deleted
|
||||||
|
];
|
||||||
|
return this.queue.reduce(
|
||||||
|
(stillUploading: boolean, currentFile: FileModel) => stillUploading || finishedFileStates.indexOf(currentFile.status) === -1,
|
||||||
|
false
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -128,9 +131,7 @@ export class UploadService {
|
|||||||
* @returns Array of files that were not blocked from upload by the ignore list
|
* @returns Array of files that were not blocked from upload by the ignore list
|
||||||
*/
|
*/
|
||||||
addToQueue(...files: FileModel[]): FileModel[] {
|
addToQueue(...files: FileModel[]): FileModel[] {
|
||||||
const allowedFiles = files.filter((currentFile) =>
|
const allowedFiles = files.filter((currentFile) => this.filterElement(currentFile));
|
||||||
this.filterElement(currentFile)
|
|
||||||
);
|
|
||||||
this.queue = this.queue.concat(allowedFiles);
|
this.queue = this.queue.concat(allowedFiles);
|
||||||
this.queueChanged.next(this.queue);
|
this.queueChanged.next(this.queue);
|
||||||
return allowedFiles;
|
return allowedFiles;
|
||||||
@@ -217,7 +218,7 @@ export class UploadService {
|
|||||||
opts.renditions = 'doclib';
|
opts.renditions = 'doclib';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file.options && file.options.versioningEnabled !== undefined) {
|
if (file.options?.versioningEnabled !== undefined) {
|
||||||
opts.versioningEnabled = file.options.versioningEnabled;
|
opts.versioningEnabled = file.options.versioningEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,13 +241,7 @@ export class UploadService {
|
|||||||
const nodeBody: NodeBodyCreate = { ...file.options, name: file.name, nodeType: file.options.nodeType };
|
const nodeBody: NodeBodyCreate = { ...file.options, name: file.name, nodeType: file.options.nodeType };
|
||||||
delete nodeBody['versioningEnabled'];
|
delete nodeBody['versioningEnabled'];
|
||||||
|
|
||||||
return this.uploadApi.uploadFile(
|
return this.uploadApi.uploadFile(file.file, file.options.path, file.options.parentId, nodeBody, opts);
|
||||||
file.file,
|
|
||||||
file.options.path,
|
|
||||||
file.options.parentId,
|
|
||||||
nodeBody,
|
|
||||||
opts
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,7 +254,7 @@ export class UploadService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const files = this.queue
|
const files = this.queue
|
||||||
.filter(toUpload => !cached.includes(toUpload.name) && toUpload.status === FileUploadStatus.Pending)
|
.filter((toUpload) => !cached.includes(toUpload.name) && toUpload.status === FileUploadStatus.Pending)
|
||||||
.slice(0, threadsCount);
|
.slice(0, threadsCount);
|
||||||
|
|
||||||
return files;
|
return files;
|
||||||
@@ -274,13 +269,13 @@ export class UploadService {
|
|||||||
.on('abort', () => {
|
.on('abort', () => {
|
||||||
this.onUploadAborted(file);
|
this.onUploadAborted(file);
|
||||||
if (successEmitter) {
|
if (successEmitter) {
|
||||||
successEmitter.emit({value: 'File aborted'});
|
successEmitter.emit({ value: 'File aborted' });
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.on('error', (err) => {
|
.on('error', (err) => {
|
||||||
this.onUploadError(file, err);
|
this.onUploadError(file, err);
|
||||||
if (errorEmitter) {
|
if (errorEmitter) {
|
||||||
errorEmitter.emit({value: 'Error file uploaded'});
|
errorEmitter.emit({ value: 'Error file uploaded' });
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.on('success', (data) => {
|
.on('success', (data) => {
|
||||||
@@ -292,17 +287,16 @@ export class UploadService {
|
|||||||
this.deleteAbortedNodeVersion(data.entry.id, data.entry.properties['cm:versionLabel']);
|
this.deleteAbortedNodeVersion(data.entry.id, data.entry.properties['cm:versionLabel']);
|
||||||
}
|
}
|
||||||
if (successEmitter) {
|
if (successEmitter) {
|
||||||
successEmitter.emit({value: 'File deleted'});
|
successEmitter.emit({ value: 'File deleted' });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.onUploadComplete(file, data);
|
this.onUploadComplete(file, data);
|
||||||
if (successEmitter) {
|
if (successEmitter) {
|
||||||
successEmitter.emit({value: data});
|
successEmitter.emit({ value: data });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {});
|
||||||
});
|
|
||||||
|
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
@@ -316,10 +310,7 @@ export class UploadService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private onUploadProgress(
|
private onUploadProgress(file: FileModel, progress: FileUploadProgress): void {
|
||||||
file: FileModel,
|
|
||||||
progress: FileUploadProgress
|
|
||||||
): void {
|
|
||||||
if (file) {
|
if (file) {
|
||||||
file.progress = progress;
|
file.progress = progress;
|
||||||
file.status = FileUploadStatus.Progress;
|
file.status = FileUploadStatus.Progress;
|
||||||
@@ -330,9 +321,9 @@ export class UploadService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private onUploadError(file: FileModel, error: any): void {
|
private onUploadError(file: FileModel, error: { status?: number }): void {
|
||||||
if (file) {
|
if (file) {
|
||||||
file.errorCode = (error || {}).status;
|
file.errorCode = error?.status;
|
||||||
file.status = FileUploadStatus.Error;
|
file.status = FileUploadStatus.Error;
|
||||||
this.totalError++;
|
this.totalError++;
|
||||||
|
|
||||||
@@ -341,11 +332,7 @@ export class UploadService {
|
|||||||
delete this.cache[file.name];
|
delete this.cache[file.name];
|
||||||
}
|
}
|
||||||
|
|
||||||
const event = new FileUploadErrorEvent(
|
const event = new FileUploadErrorEvent(file, error, this.totalError);
|
||||||
file,
|
|
||||||
error,
|
|
||||||
this.totalError
|
|
||||||
);
|
|
||||||
this.fileUpload.next(event);
|
this.fileUpload.next(event);
|
||||||
this.fileUploadError.next(event);
|
this.fileUploadError.next(event);
|
||||||
}
|
}
|
||||||
@@ -361,12 +348,7 @@ export class UploadService {
|
|||||||
delete this.cache[file.name];
|
delete this.cache[file.name];
|
||||||
}
|
}
|
||||||
|
|
||||||
const event = new FileUploadCompleteEvent(
|
const event = new FileUploadCompleteEvent(file, this.totalComplete, data, this.totalAborted);
|
||||||
file,
|
|
||||||
this.totalComplete,
|
|
||||||
data,
|
|
||||||
this.totalAborted
|
|
||||||
);
|
|
||||||
this.fileUpload.next(event);
|
this.fileUpload.next(event);
|
||||||
this.fileUploadComplete.next(event);
|
this.fileUploadComplete.next(event);
|
||||||
}
|
}
|
||||||
@@ -415,20 +397,15 @@ export class UploadService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private deleteAbortedNode(nodeId: string) {
|
private deleteAbortedNode(nodeId: string) {
|
||||||
this.nodesApi.deleteNode(nodeId, {permanent: true})
|
this.nodesApi.deleteNode(nodeId, { permanent: true }).then(() => (this.abortedFile = undefined));
|
||||||
.then(() => (this.abortedFile = undefined));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private deleteAbortedNodeVersion(nodeId: string, versionId: string) {
|
private deleteAbortedNodeVersion(nodeId: string, versionId: string) {
|
||||||
this.versionsApi.deleteVersion(nodeId, versionId)
|
this.versionsApi.deleteVersion(nodeId, versionId).then(() => (this.abortedFile = undefined));
|
||||||
.then(() => (this.abortedFile = undefined));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private isSaveToAbortFile(file: FileModel): boolean {
|
private isSaveToAbortFile(file: FileModel): boolean {
|
||||||
return (
|
return file.size > MIN_CANCELLABLE_FILE_SIZE && file.progress.percent < MAX_CANCELLABLE_FILE_PERCENTAGE;
|
||||||
file.size > MIN_CANCELLABLE_FILE_SIZE &&
|
|
||||||
file.progress.percent < MAX_CANCELLABLE_FILE_PERCENTAGE
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private filterElement(file: FileModel) {
|
private filterElement(file: FileModel) {
|
||||||
@@ -454,12 +431,12 @@ export class UploadService {
|
|||||||
const fileRelativePath = currentFile.webkitRelativePath ? currentFile.webkitRelativePath : file.options.path;
|
const fileRelativePath = currentFile.webkitRelativePath ? currentFile.webkitRelativePath : file.options.path;
|
||||||
if (currentFile && fileRelativePath) {
|
if (currentFile && fileRelativePath) {
|
||||||
isAllowed =
|
isAllowed =
|
||||||
this.excludedFoldersList.filter((folderToExclude) => fileRelativePath
|
this.excludedFoldersList.filter((folderToExclude) =>
|
||||||
.split('/')
|
fileRelativePath.split('/').some((pathElement) => {
|
||||||
.some((pathElement) => {
|
|
||||||
const minimatch = new Minimatch(folderToExclude, this.folderMatchingOptions);
|
const minimatch = new Minimatch(folderToExclude, this.folderMatchingOptions);
|
||||||
return minimatch.match(pathElement);
|
return minimatch.match(pathElement);
|
||||||
})).length === 0;
|
})
|
||||||
|
).length === 0;
|
||||||
}
|
}
|
||||||
return isAllowed;
|
return isAllowed;
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-3
@@ -31,7 +31,6 @@ import { AllowableOperationsEnum } from '../../../common/models/allowable-operat
|
|||||||
host: { class: 'adf-content-metadata-card' }
|
host: { class: 'adf-content-metadata-card' }
|
||||||
})
|
})
|
||||||
export class ContentMetadataCardComponent implements OnChanges {
|
export class ContentMetadataCardComponent implements OnChanges {
|
||||||
|
|
||||||
/** (required) The node entity to fetch metadata about */
|
/** (required) The node entity to fetch metadata about */
|
||||||
@Input()
|
@Input()
|
||||||
node: Node;
|
node: Node;
|
||||||
@@ -101,12 +100,16 @@ export class ContentMetadataCardComponent implements OnChanges {
|
|||||||
|
|
||||||
editAspectSupported = false;
|
editAspectSupported = false;
|
||||||
|
|
||||||
constructor(private contentService: ContentService, private nodeAspectService: NodeAspectService, private versionCompatibilityService: VersionCompatibilityService) {
|
constructor(
|
||||||
|
private contentService: ContentService,
|
||||||
|
private nodeAspectService: NodeAspectService,
|
||||||
|
private versionCompatibilityService: VersionCompatibilityService
|
||||||
|
) {
|
||||||
this.editAspectSupported = this.versionCompatibilityService.isVersionSupported('7');
|
this.editAspectSupported = this.versionCompatibilityService.isVersionSupported('7');
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges): void {
|
ngOnChanges(changes: SimpleChanges): void {
|
||||||
if (changes.displayAspect && changes.displayAspect.currentValue) {
|
if (changes.displayAspect?.currentValue) {
|
||||||
this.expanded = true;
|
this.expanded = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -407,7 +407,7 @@ export class ContentNodeSelectorPanelComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
private isExcludedSiteContent(row: ShareDataRow): boolean {
|
private isExcludedSiteContent(row: ShareDataRow): boolean {
|
||||||
const entry = row.node.entry;
|
const entry = row.node.entry;
|
||||||
if (this._excludeSiteContent && this._excludeSiteContent.length && entry && entry.properties && entry.properties['st:componentId']) {
|
if (this._excludeSiteContent?.length && entry && entry.properties?.['st:componentId']) {
|
||||||
const excludedItem = this._excludeSiteContent.find((id: string) => entry.properties['st:componentId'] === id);
|
const excludedItem = this._excludeSiteContent.find((id: string) => entry.properties['st:componentId'] === id);
|
||||||
return !!excludedItem;
|
return !!excludedItem;
|
||||||
}
|
}
|
||||||
@@ -489,7 +489,7 @@ export class ContentNodeSelectorPanelComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
if (this.customResourcesService.hasCorrespondingNodeIds(this.siteId)) {
|
if (this.customResourcesService.hasCorrespondingNodeIds(this.siteId)) {
|
||||||
this.customResourcesService.getCorrespondingNodeIds(this.siteId).subscribe((nodeIds) => {
|
this.customResourcesService.getCorrespondingNodeIds(this.siteId).subscribe((nodeIds) => {
|
||||||
if (nodeIds && nodeIds.length) {
|
if (nodeIds?.length) {
|
||||||
nodeIds
|
nodeIds
|
||||||
.filter((id) => id !== this.siteId)
|
.filter((id) => id !== this.siteId)
|
||||||
.forEach((extraId) => {
|
.forEach((extraId) => {
|
||||||
|
|||||||
@@ -15,14 +15,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import { Component, Inject, OnInit, ViewEncapsulation, ViewChild, OnDestroy } from '@angular/core';
|
||||||
Component,
|
|
||||||
Inject,
|
|
||||||
OnInit,
|
|
||||||
ViewEncapsulation,
|
|
||||||
ViewChild,
|
|
||||||
OnDestroy
|
|
||||||
} from '@angular/core';
|
|
||||||
import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog';
|
import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog';
|
||||||
import { MatSlideToggleChange } from '@angular/material/slide-toggle';
|
import { MatSlideToggleChange } from '@angular/material/slide-toggle';
|
||||||
import { UntypedFormGroup, UntypedFormControl, AbstractControl } from '@angular/forms';
|
import { UntypedFormGroup, UntypedFormControl, AbstractControl } from '@angular/forms';
|
||||||
@@ -43,11 +36,10 @@ type DatePickerType = 'date' | 'time' | 'month' | 'datetime';
|
|||||||
selector: 'adf-share-dialog',
|
selector: 'adf-share-dialog',
|
||||||
templateUrl: './content-node-share.dialog.html',
|
templateUrl: './content-node-share.dialog.html',
|
||||||
styleUrls: ['./content-node-share.dialog.scss'],
|
styleUrls: ['./content-node-share.dialog.scss'],
|
||||||
host: {class: 'adf-share-dialog'},
|
host: { class: 'adf-share-dialog' },
|
||||||
encapsulation: ViewEncapsulation.None
|
encapsulation: ViewEncapsulation.None
|
||||||
})
|
})
|
||||||
export class ShareDialogComponent implements OnInit, OnDestroy {
|
export class ShareDialogComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
minDate = add(new Date(), { days: 1 });
|
minDate = add(new Date(), { days: 1 });
|
||||||
sharedId: string;
|
sharedId: string;
|
||||||
fileName: string;
|
fileName: string;
|
||||||
@@ -57,16 +49,16 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
|||||||
isLinkWithExpiryDate = false;
|
isLinkWithExpiryDate = false;
|
||||||
form: UntypedFormGroup = new UntypedFormGroup({
|
form: UntypedFormGroup = new UntypedFormGroup({
|
||||||
sharedUrl: new UntypedFormControl(''),
|
sharedUrl: new UntypedFormControl(''),
|
||||||
time: new UntypedFormControl({value: '', disabled: true})
|
time: new UntypedFormControl({ value: '', disabled: true })
|
||||||
});
|
});
|
||||||
type: DatePickerType = 'date';
|
type: DatePickerType = 'date';
|
||||||
maxDebounceTime = 500;
|
maxDebounceTime = 500;
|
||||||
isExpiryDateToggleChecked: boolean;
|
isExpiryDateToggleChecked: boolean;
|
||||||
|
|
||||||
@ViewChild('slideToggleExpirationDate', {static: true})
|
@ViewChild('slideToggleExpirationDate', { static: true })
|
||||||
slideToggleExpirationDate;
|
slideToggleExpirationDate;
|
||||||
|
|
||||||
@ViewChild('datePickerInput', {static: true})
|
@ViewChild('datePickerInput', { static: true })
|
||||||
datePickerInput;
|
datePickerInput;
|
||||||
|
|
||||||
private onDestroy$ = new Subject<boolean>();
|
private onDestroy$ = new Subject<boolean>();
|
||||||
@@ -78,17 +70,16 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
|||||||
private contentService: ContentService,
|
private contentService: ContentService,
|
||||||
private renditionService: RenditionService,
|
private renditionService: RenditionService,
|
||||||
@Inject(MAT_DIALOG_DATA) public data: ContentNodeShareSettings
|
@Inject(MAT_DIALOG_DATA) public data: ContentNodeShareSettings
|
||||||
) {
|
) {}
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
if (this.data.node && this.data.node.entry) {
|
if (this.data.node?.entry) {
|
||||||
this.fileName = this.data.node.entry.name;
|
this.fileName = this.data.node.entry.name;
|
||||||
this.baseShareUrl = this.data.baseShareUrl;
|
this.baseShareUrl = this.data.baseShareUrl;
|
||||||
|
|
||||||
const properties = this.data.node.entry.properties;
|
const properties = this.data.node.entry.properties;
|
||||||
|
|
||||||
if (!properties || !properties['qshare:sharedId']) {
|
if (!properties?.['qshare:sharedId']) {
|
||||||
this.createSharedLinks(this.data.node.entry.id);
|
this.createSharedLinks(this.data.node.entry.id);
|
||||||
} else {
|
} else {
|
||||||
this.sharedId = properties['qshare:sharedId'];
|
this.sharedId = properties['qshare:sharedId'];
|
||||||
@@ -100,12 +91,7 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.time.valueChanges
|
this.time.valueChanges.pipe(debounceTime(this.maxDebounceTime), takeUntil(this.onDestroy$)).subscribe((value) => this.onTimeChanged(value));
|
||||||
.pipe(
|
|
||||||
debounceTime(this.maxDebounceTime),
|
|
||||||
takeUntil(this.onDestroy$)
|
|
||||||
)
|
|
||||||
.subscribe(value => this.onTimeChanged(value));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onTimeChanged(date: Date) {
|
onTimeChanged(date: Date) {
|
||||||
@@ -130,9 +116,9 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get canUpdate() {
|
get canUpdate() {
|
||||||
const {entry} = this.data.node;
|
const { entry } = this.data.node;
|
||||||
|
|
||||||
if (entry && entry.allowableOperations) {
|
if (entry?.allowableOperations) {
|
||||||
return this.contentService.hasAllowableOperations(entry, 'update');
|
return this.contentService.hasAllowableOperations(entry, 'update');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,9 +200,7 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
|||||||
deleteSharedLink(sharedId: string, dialogOpenFlag?: boolean) {
|
deleteSharedLink(sharedId: string, dialogOpenFlag?: boolean) {
|
||||||
this.isDisabled = true;
|
this.isDisabled = true;
|
||||||
|
|
||||||
this.sharedLinksApiService
|
this.sharedLinksApiService.deleteSharedLink(sharedId).subscribe((response: any) => {
|
||||||
.deleteSharedLink(sharedId)
|
|
||||||
.subscribe((response: any) => {
|
|
||||||
if (response instanceof Error) {
|
if (response instanceof Error) {
|
||||||
this.isDisabled = false;
|
this.isDisabled = false;
|
||||||
this.isFileShared = true;
|
this.isFileShared = true;
|
||||||
@@ -234,8 +218,7 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
|||||||
this.dialogRef.close(false);
|
this.dialogRef.close(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleError(error: Error) {
|
private handleError(error: Error) {
|
||||||
@@ -244,8 +227,7 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
statusCode = JSON.parse(error.message).error.statusCode;
|
statusCode = JSON.parse(error.message).error.statusCode;
|
||||||
} catch {
|
} catch {}
|
||||||
}
|
|
||||||
|
|
||||||
if (statusCode === 403) {
|
if (statusCode === 403) {
|
||||||
message = 'SHARE.UNSHARE_PERMISSION_ERROR';
|
message = 'SHARE.UNSHARE_PERMISSION_ERROR';
|
||||||
@@ -258,17 +240,20 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private updateForm(): Date {
|
private updateForm(): Date {
|
||||||
const {entry} = this.data.node;
|
const { entry } = this.data.node;
|
||||||
let expiryDate = null;
|
let expiryDate = null;
|
||||||
|
|
||||||
if (entry && entry.properties) {
|
if (entry?.properties) {
|
||||||
expiryDate = entry.properties['qshare:expiryDate'];
|
expiryDate = entry.properties['qshare:expiryDate'];
|
||||||
}
|
}
|
||||||
|
|
||||||
this.form.setValue({
|
this.form.setValue(
|
||||||
|
{
|
||||||
sharedUrl: `${this.baseShareUrl}${this.sharedId}`,
|
sharedUrl: `${this.baseShareUrl}${this.sharedId}`,
|
||||||
time: expiryDate ? new Date(expiryDate) : null
|
time: expiryDate ? new Date(expiryDate) : null
|
||||||
}, { emitEvent: false });
|
},
|
||||||
|
{ emitEvent: false }
|
||||||
|
);
|
||||||
|
|
||||||
return expiryDate;
|
return expiryDate;
|
||||||
}
|
}
|
||||||
@@ -279,7 +264,7 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
|||||||
if (this.type === 'date') {
|
if (this.type === 'date') {
|
||||||
expiryDate = format(endOfDay(new Date(date)), `yyyy-MM-dd'T'HH:mm:ss.SSSxx`);
|
expiryDate = format(endOfDay(new Date(date)), `yyyy-MM-dd'T'HH:mm:ss.SSSxx`);
|
||||||
} else {
|
} else {
|
||||||
expiryDate = format((new Date(date)), `yyyy-MM-dd'T'HH:mm:ss.SSSxx`);
|
expiryDate = format(new Date(date), `yyyy-MM-dd'T'HH:mm:ss.SSSxx`);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
expiryDate = null;
|
expiryDate = null;
|
||||||
@@ -311,12 +296,10 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private updateEntryExpiryDate(date: Date) {
|
private updateEntryExpiryDate(date: Date) {
|
||||||
const {properties} = this.data.node.entry;
|
const { properties } = this.data.node.entry;
|
||||||
|
|
||||||
if (properties) {
|
if (properties) {
|
||||||
properties['qshare:expiryDate'] = date
|
properties['qshare:expiryDate'] = date ? new Date(date) : null;
|
||||||
? new Date(date)
|
|
||||||
: null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ import { takeUntil } from 'rxjs/operators';
|
|||||||
exportAs: 'adfShare'
|
exportAs: 'adfShare'
|
||||||
})
|
})
|
||||||
export class NodeSharedDirective implements OnChanges, OnDestroy {
|
export class NodeSharedDirective implements OnChanges, OnDestroy {
|
||||||
|
|
||||||
isFile: boolean = false;
|
isFile: boolean = false;
|
||||||
isShared: boolean = false;
|
isShared: boolean = false;
|
||||||
|
|
||||||
@@ -50,11 +49,7 @@ export class NodeSharedDirective implements OnChanges, OnDestroy {
|
|||||||
return this._nodesApi;
|
return this._nodesApi;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(private dialog: MatDialog, private zone: NgZone, private alfrescoApiService: AlfrescoApiService) {}
|
||||||
private dialog: MatDialog,
|
|
||||||
private zone: NgZone,
|
|
||||||
private alfrescoApiService: AlfrescoApiService) {
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
this.onDestroy$.next(true);
|
this.onDestroy$.next(true);
|
||||||
@@ -62,7 +57,7 @@ export class NodeSharedDirective implements OnChanges, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
shareNode(nodeEntry: NodeEntry) {
|
shareNode(nodeEntry: NodeEntry) {
|
||||||
if (nodeEntry && nodeEntry.entry && nodeEntry.entry.isFile) {
|
if (nodeEntry?.entry?.isFile) {
|
||||||
// shared and favorite
|
// shared and favorite
|
||||||
const nodeId = nodeEntry.entry['nodeId'] || nodeEntry.entry['guid'];
|
const nodeId = nodeEntry.entry['nodeId'] || nodeEntry.entry['guid'];
|
||||||
|
|
||||||
@@ -96,10 +91,8 @@ export class NodeSharedDirective implements OnChanges, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnChanges() {
|
ngOnChanges() {
|
||||||
this.zone.onStable
|
this.zone.onStable.pipe(takeUntil(this.onDestroy$)).subscribe(() => {
|
||||||
.pipe(takeUntil(this.onDestroy$))
|
if (this.node?.entry) {
|
||||||
.subscribe(() => {
|
|
||||||
if (this.node && this.node.entry) {
|
|
||||||
this.isFile = this.node.entry.isFile;
|
this.isFile = this.node.entry.isFile;
|
||||||
this.isShared = this.node.entry.properties ? this.node.entry.properties['qshare:sharedId'] : false;
|
this.isShared = this.node.entry.properties ? this.node.entry.properties['qshare:sharedId'] : false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ export class DownloadZipDialogComponent implements OnInit {
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
if (this.data && this.data.nodeIds && this.data.nodeIds.length > 0) {
|
if (this.data?.nodeIds?.length > 0) {
|
||||||
if (!this.cancelled) {
|
if (!this.cancelled) {
|
||||||
this.downloadZip(this.data.nodeIds);
|
this.downloadZip(this.data.nodeIds);
|
||||||
} else {
|
} else {
|
||||||
@@ -64,7 +64,7 @@ export class DownloadZipDialogComponent implements OnInit {
|
|||||||
downloadZip(nodeIds: string[]) {
|
downloadZip(nodeIds: string[]) {
|
||||||
if (nodeIds && nodeIds.length > 0) {
|
if (nodeIds && nodeIds.length > 0) {
|
||||||
this.downloadZipService.createDownload({ nodeIds }).subscribe((data: DownloadEntry) => {
|
this.downloadZipService.createDownload({ nodeIds }).subscribe((data: DownloadEntry) => {
|
||||||
if (data && data.entry && data.entry.id) {
|
if (data?.entry?.id) {
|
||||||
const url = this.contentService.getContentUrl(data.entry.id, true);
|
const url = this.contentService.getContentUrl(data.entry.id, true);
|
||||||
|
|
||||||
this.nodeService.getNode(data.entry.id).subscribe((downloadNode) => {
|
this.nodeService.getNode(data.entry.id).subscribe((downloadNode) => {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Directive, HostListener, Input, OnChanges, Output, EventEmitter } from '@angular/core';
|
import { Directive, HostListener, Input, OnChanges, Output, EventEmitter, SimpleChanges } from '@angular/core';
|
||||||
import { FavoriteBodyCreate, FavoritesApi } from '@alfresco/js-api';
|
import { FavoriteBodyCreate, FavoritesApi } from '@alfresco/js-api';
|
||||||
import { AlfrescoApiService } from '@alfresco/adf-core';
|
import { AlfrescoApiService } from '@alfresco/adf-core';
|
||||||
import { LibraryEntity } from '../interfaces/library-entity.interface';
|
import { LibraryEntity } from '../interfaces/library-entity.interface';
|
||||||
@@ -59,7 +59,7 @@ export class LibraryFavoriteDirective implements OnChanges {
|
|||||||
|
|
||||||
constructor(private alfrescoApiService: AlfrescoApiService) {}
|
constructor(private alfrescoApiService: AlfrescoApiService) {}
|
||||||
|
|
||||||
ngOnChanges(changes) {
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
if (!changes.library.currentValue) {
|
if (!changes.library.currentValue) {
|
||||||
this.targetLibrary = null;
|
this.targetLibrary = null;
|
||||||
return;
|
return;
|
||||||
@@ -70,7 +70,7 @@ export class LibraryFavoriteDirective implements OnChanges {
|
|||||||
}
|
}
|
||||||
|
|
||||||
isFavorite(): boolean {
|
isFavorite(): boolean {
|
||||||
return this.targetLibrary && this.targetLibrary.isFavorite;
|
return this.targetLibrary?.isFavorite;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async markFavoriteLibrary(library: LibraryEntity) {
|
private async markFavoriteLibrary(library: LibraryEntity) {
|
||||||
|
|||||||
@@ -16,17 +16,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Directive, EventEmitter, HostListener, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
|
import { Directive, EventEmitter, HostListener, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
|
||||||
import {
|
import { SiteEntry, SiteMembershipRequestBodyCreate, SiteMembershipRequestEntry, SitesApi } from '@alfresco/js-api';
|
||||||
SiteEntry,
|
|
||||||
SiteMembershipRequestBodyCreate,
|
|
||||||
SiteMemberEntry,
|
|
||||||
SiteMembershipRequestEntry,
|
|
||||||
SitesApi
|
|
||||||
} from '@alfresco/js-api';
|
|
||||||
import { BehaviorSubject, from, Observable } from 'rxjs';
|
import { BehaviorSubject, from, Observable } from 'rxjs';
|
||||||
import { AlfrescoApiService } from '@alfresco/adf-core';
|
import { AlfrescoApiService } from '@alfresco/adf-core';
|
||||||
import { LibraryMembershipToggleEvent } from '../interfaces/library-membership-toggle-event.interface';
|
import { LibraryMembershipToggleEvent } from '../interfaces/library-membership-toggle-event.interface';
|
||||||
import { LibraryMembershipErrorEvent} from '../interfaces/library-membership-error-event.interface';
|
import { LibraryMembershipErrorEvent } from '../interfaces/library-membership-error-event.interface';
|
||||||
import { VersionCompatibilityService } from '../version-compatibility/version-compatibility.service';
|
import { VersionCompatibilityService } from '../version-compatibility/version-compatibility.service';
|
||||||
import { SitesService } from '../common/services/sites.service';
|
import { SitesService } from '../common/services/sites.service';
|
||||||
|
|
||||||
@@ -39,7 +33,7 @@ export class LibraryMembershipDirective implements OnChanges {
|
|||||||
|
|
||||||
isJoinRequested: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
isJoinRequested: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
||||||
|
|
||||||
_sitesApi: SitesApi;
|
private _sitesApi: SitesApi;
|
||||||
get sitesApi(): SitesApi {
|
get sitesApi(): SitesApi {
|
||||||
this._sitesApi = this._sitesApi ?? new SitesApi(this.alfrescoApiService.getInstance());
|
this._sitesApi = this._sitesApi ?? new SitesApi(this.alfrescoApiService.getInstance());
|
||||||
return this._sitesApi;
|
return this._sitesApi;
|
||||||
@@ -69,11 +63,10 @@ export class LibraryMembershipDirective implements OnChanges {
|
|||||||
private alfrescoApiService: AlfrescoApiService,
|
private alfrescoApiService: AlfrescoApiService,
|
||||||
private sitesService: SitesService,
|
private sitesService: SitesService,
|
||||||
private versionCompatibilityService: VersionCompatibilityService
|
private versionCompatibilityService: VersionCompatibilityService
|
||||||
) {
|
) {}
|
||||||
}
|
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges) {
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
if (!changes.selection.currentValue || !changes.selection.currentValue.entry) {
|
if (!changes.selection.currentValue?.entry) {
|
||||||
this.targetSite = null;
|
this.targetSite = null;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -115,7 +108,7 @@ export class LibraryMembershipDirective implements OnChanges {
|
|||||||
this.targetSite.joinRequested = true;
|
this.targetSite.joinRequested = true;
|
||||||
this.isJoinRequested.next(true);
|
this.isJoinRequested.next(true);
|
||||||
|
|
||||||
if (createdMembership.entry && createdMembership.entry.site && createdMembership.entry.site.role) {
|
if (createdMembership.entry?.site?.role) {
|
||||||
const info = {
|
const info = {
|
||||||
shouldReload: true,
|
shouldReload: true,
|
||||||
i18nKey: 'ADF_LIBRARY_MEMBERSHIP_MESSAGES.INFO.JOINED'
|
i18nKey: 'ADF_LIBRARY_MEMBERSHIP_MESSAGES.INFO.JOINED'
|
||||||
@@ -154,8 +147,8 @@ export class LibraryMembershipDirective implements OnChanges {
|
|||||||
|
|
||||||
if (this.isAdmin) {
|
if (this.isAdmin) {
|
||||||
this.joinLibrary().subscribe(
|
this.joinLibrary().subscribe(
|
||||||
(createdMembership: SiteMemberEntry) => {
|
(createdMembership) => {
|
||||||
if (createdMembership.entry && createdMembership.entry.role) {
|
if (createdMembership.entry?.role) {
|
||||||
const info = {
|
const info = {
|
||||||
shouldReload: true,
|
shouldReload: true,
|
||||||
i18nKey: 'ADF_LIBRARY_MEMBERSHIP_MESSAGES.INFO.JOINED'
|
i18nKey: 'ADF_LIBRARY_MEMBERSHIP_MESSAGES.INFO.JOINED'
|
||||||
@@ -223,7 +216,7 @@ export class LibraryMembershipDirective implements OnChanges {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private cancelJoinRequest() {
|
private cancelJoinRequest(): Observable<void> {
|
||||||
return from(this.sitesApi.deleteSiteMembershipRequestForPerson('-me-', this.targetSite.id));
|
return from(this.sitesApi.deleteSiteMembershipRequestForPerson('-me-', this.targetSite.id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -78,10 +78,7 @@ export class NodeDeleteDirective implements OnChanges {
|
|||||||
this.process(this.selection);
|
this.process(this.selection);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(private alfrescoApiService: AlfrescoApiService,
|
constructor(private alfrescoApiService: AlfrescoApiService, private translation: TranslationService, private elementRef: ElementRef) {}
|
||||||
private translation: TranslationService,
|
|
||||||
private elementRef: ElementRef) {
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnChanges() {
|
ngOnChanges() {
|
||||||
if (!this.selection || (this.selection && this.selection.length === 0)) {
|
if (!this.selection || (this.selection && this.selection.length === 0)) {
|
||||||
@@ -98,12 +95,10 @@ export class NodeDeleteDirective implements OnChanges {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private process(selection: NodeEntry[] | DeletedNodeEntry[]) {
|
private process(selection: NodeEntry[] | DeletedNodeEntry[]) {
|
||||||
if (selection && selection.length) {
|
if (selection?.length) {
|
||||||
|
|
||||||
const batch = this.getDeleteNodesBatch(selection);
|
const batch = this.getDeleteNodesBatch(selection);
|
||||||
|
|
||||||
forkJoin(...batch)
|
forkJoin(...batch).subscribe((data: ProcessedNodeData[]) => {
|
||||||
.subscribe((data: ProcessedNodeData[]) => {
|
|
||||||
const processedItems: ProcessStatus = this.processStatus(data);
|
const processedItems: ProcessStatus = this.processStatus(data);
|
||||||
const message = this.getMessage(processedItems);
|
const message = this.getMessage(processedItems);
|
||||||
|
|
||||||
@@ -114,7 +109,7 @@ export class NodeDeleteDirective implements OnChanges {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private getDeleteNodesBatch(selection: any): Observable<ProcessedNodeData>[] {
|
private getDeleteNodesBatch(selection: NodeEntry[] | DeletedNodeEntry[]): Observable<ProcessedNodeData>[] {
|
||||||
return selection.map((node) => this.deleteNode(node));
|
return selection.map((node) => this.deleteNode(node));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,10 +130,12 @@ export class NodeDeleteDirective implements OnChanges {
|
|||||||
entry: node.entry,
|
entry: node.entry,
|
||||||
status: 1
|
status: 1
|
||||||
})),
|
})),
|
||||||
catchError(() => of({
|
catchError(() =>
|
||||||
|
of({
|
||||||
entry: node.entry,
|
entry: node.entry,
|
||||||
status: 0
|
status: 0
|
||||||
}))
|
})
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,10 +144,10 @@ export class NodeDeleteDirective implements OnChanges {
|
|||||||
success: [],
|
success: [],
|
||||||
failed: [],
|
failed: [],
|
||||||
get someFailed() {
|
get someFailed() {
|
||||||
return !!(this.failed.length);
|
return !!this.failed.length;
|
||||||
},
|
},
|
||||||
get someSucceeded() {
|
get someSucceeded() {
|
||||||
return !!(this.success.length);
|
return !!this.success.length;
|
||||||
},
|
},
|
||||||
get oneFailed() {
|
get oneFailed() {
|
||||||
return this.failed.length === 1;
|
return this.failed.length === 1;
|
||||||
@@ -166,8 +163,7 @@ export class NodeDeleteDirective implements OnChanges {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return data.reduce(
|
return data.reduce((acc, next) => {
|
||||||
(acc, next) => {
|
|
||||||
if (next.status === 1) {
|
if (next.status === 1) {
|
||||||
acc.success.push(next);
|
acc.success.push(next);
|
||||||
} else {
|
} else {
|
||||||
@@ -175,9 +171,7 @@ export class NodeDeleteDirective implements OnChanges {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return acc;
|
return acc;
|
||||||
},
|
}, deleteStatus);
|
||||||
deleteStatus
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private getMessage(status: ProcessStatus): string | null {
|
private getMessage(status: ProcessStatus): string | null {
|
||||||
@@ -198,37 +192,25 @@ export class NodeDeleteDirective implements OnChanges {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (status.someFailed && status.someSucceeded && !status.oneSucceeded) {
|
if (status.someFailed && status.someSucceeded && !status.oneSucceeded) {
|
||||||
return this.translation.instant(
|
return this.translation.instant('CORE.DELETE_NODE.PARTIAL_PLURAL', {
|
||||||
'CORE.DELETE_NODE.PARTIAL_PLURAL',
|
|
||||||
{
|
|
||||||
success: status.success.length,
|
success: status.success.length,
|
||||||
failed: status.failed.length
|
failed: status.failed.length
|
||||||
}
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status.someFailed && status.oneSucceeded) {
|
if (status.someFailed && status.oneSucceeded) {
|
||||||
return this.translation.instant(
|
return this.translation.instant('CORE.DELETE_NODE.PARTIAL_SINGULAR', {
|
||||||
'CORE.DELETE_NODE.PARTIAL_SINGULAR',
|
|
||||||
{
|
|
||||||
success: status.success.length,
|
success: status.success.length,
|
||||||
failed: status.failed.length
|
failed: status.failed.length
|
||||||
}
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status.oneFailed && !status.someSucceeded) {
|
if (status.oneFailed && !status.someSucceeded) {
|
||||||
return this.translation.instant(
|
return this.translation.instant('CORE.DELETE_NODE.ERROR_SINGULAR', { name: status.failed[0].entry.name });
|
||||||
'CORE.DELETE_NODE.ERROR_SINGULAR',
|
|
||||||
{ name: status.failed[0].entry.name }
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status.oneSucceeded && !status.someFailed) {
|
if (status.oneSucceeded && !status.someFailed) {
|
||||||
return this.translation.instant(
|
return this.translation.instant('CORE.DELETE_NODE.SINGULAR', { name: status.success[0].entry.name });
|
||||||
'CORE.DELETE_NODE.SINGULAR',
|
|
||||||
{ name: status.success[0].entry.name }
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ import { ContentApi, NodeEntry, VersionEntry } from '@alfresco/js-api';
|
|||||||
selector: '[adfNodeDownload]'
|
selector: '[adfNodeDownload]'
|
||||||
})
|
})
|
||||||
export class NodeDownloadDirective {
|
export class NodeDownloadDirective {
|
||||||
|
|
||||||
_contentApi: ContentApi;
|
_contentApi: ContentApi;
|
||||||
get contentApi(): ContentApi {
|
get contentApi(): ContentApi {
|
||||||
this._contentApi = this._contentApi ?? new ContentApi(this.apiService.getInstance());
|
this._contentApi = this._contentApi ?? new ContentApi(this.apiService.getInstance());
|
||||||
@@ -49,11 +48,7 @@ export class NodeDownloadDirective {
|
|||||||
this.downloadNodes(this.nodes);
|
this.downloadNodes(this.nodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(private apiService: AlfrescoApiService, private downloadService: DownloadService, private dialog: MatDialog) {}
|
||||||
private apiService: AlfrescoApiService,
|
|
||||||
private downloadService: DownloadService,
|
|
||||||
private dialog: MatDialog) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Downloads multiple selected nodes.
|
* Downloads multiple selected nodes.
|
||||||
@@ -62,7 +57,6 @@ export class NodeDownloadDirective {
|
|||||||
* @param selection Multiple selected nodes to download
|
* @param selection Multiple selected nodes to download
|
||||||
*/
|
*/
|
||||||
downloadNodes(selection: NodeEntry | Array<NodeEntry>) {
|
downloadNodes(selection: NodeEntry | Array<NodeEntry>) {
|
||||||
|
|
||||||
if (!this.isSelectionValid(selection)) {
|
if (!this.isSelectionValid(selection)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -84,7 +78,7 @@ export class NodeDownloadDirective {
|
|||||||
* @param node Node to download
|
* @param node Node to download
|
||||||
*/
|
*/
|
||||||
downloadNode(node: NodeEntry) {
|
downloadNode(node: NodeEntry) {
|
||||||
if (node && node.entry) {
|
if (node?.entry) {
|
||||||
const entry = node.entry;
|
const entry = node.entry;
|
||||||
|
|
||||||
if (entry.isFile) {
|
if (entry.isFile) {
|
||||||
@@ -107,12 +101,12 @@ export class NodeDownloadDirective {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private downloadFile(node: NodeEntry) {
|
private downloadFile(node: NodeEntry) {
|
||||||
if (node && node.entry) {
|
if (node?.entry) {
|
||||||
// nodeId for Shared node
|
// nodeId for Shared node
|
||||||
const id = (node.entry as any).nodeId || node.entry.id;
|
const id = (node.entry as any).nodeId || node.entry.id;
|
||||||
|
|
||||||
let url;
|
let url: string;
|
||||||
let fileName;
|
let fileName: string;
|
||||||
if (this.version) {
|
if (this.version) {
|
||||||
url = this.contentApi.getVersionContentUrl(id, this.version.entry.id, true);
|
url = this.contentApi.getVersionContentUrl(id, this.version.entry.id, true);
|
||||||
fileName = this.version.entry.name;
|
fileName = this.version.entry.name;
|
||||||
@@ -128,7 +122,7 @@ export class NodeDownloadDirective {
|
|||||||
private downloadZip(selection: Array<NodeEntry>) {
|
private downloadZip(selection: Array<NodeEntry>) {
|
||||||
if (selection && selection.length > 0) {
|
if (selection && selection.length > 0) {
|
||||||
// nodeId for Shared node
|
// nodeId for Shared node
|
||||||
const nodeIds = selection.map((node: any) => (node.entry.nodeId || node.entry.id));
|
const nodeIds = selection.map((node: any) => node.entry.nodeId || node.entry.id);
|
||||||
|
|
||||||
this.dialog.open(DownloadZipDialogComponent, {
|
this.dialog.open(DownloadZipDialogComponent, {
|
||||||
width: '600px',
|
width: '600px',
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ export class NodeFavoriteDirective implements OnChanges {
|
|||||||
const node: Node | SharedLink = selected.entry;
|
const node: Node | SharedLink = selected.entry;
|
||||||
|
|
||||||
// ACS 6.x with 'isFavorite' include
|
// ACS 6.x with 'isFavorite' include
|
||||||
if (node && node.hasOwnProperty('isFavorite')) {
|
if (node?.hasOwnProperty('isFavorite')) {
|
||||||
return of(selected);
|
return of(selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,8 +19,20 @@
|
|||||||
/* eslint-disable @typescript-eslint/naming-convention */
|
/* eslint-disable @typescript-eslint/naming-convention */
|
||||||
|
|
||||||
import {
|
import {
|
||||||
AfterContentInit, Component, ContentChild, ElementRef, EventEmitter, HostListener, Input,
|
AfterContentInit,
|
||||||
OnChanges, OnDestroy, OnInit, Output, SimpleChanges, ViewChild, ViewEncapsulation
|
Component,
|
||||||
|
ContentChild,
|
||||||
|
ElementRef,
|
||||||
|
EventEmitter,
|
||||||
|
HostListener,
|
||||||
|
Input,
|
||||||
|
OnChanges,
|
||||||
|
OnDestroy,
|
||||||
|
OnInit,
|
||||||
|
Output,
|
||||||
|
SimpleChanges,
|
||||||
|
ViewChild,
|
||||||
|
ViewEncapsulation
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { ContentService } from '../../common/services/content.service';
|
import { ContentService } from '../../common/services/content.service';
|
||||||
|
|
||||||
@@ -75,15 +87,17 @@ const BYTES_TO_MB_CONVERSION_VALUE = 1048576;
|
|||||||
selector: 'adf-document-list',
|
selector: 'adf-document-list',
|
||||||
templateUrl: './document-list.component.html',
|
templateUrl: './document-list.component.html',
|
||||||
styleUrls: ['./document-list.component.scss'],
|
styleUrls: ['./document-list.component.scss'],
|
||||||
providers:[{
|
providers: [
|
||||||
|
{
|
||||||
provide: ADF_DOCUMENT_PARENT_COMPONENT,
|
provide: ADF_DOCUMENT_PARENT_COMPONENT,
|
||||||
useExisting: DocumentListComponent
|
useExisting: DocumentListComponent
|
||||||
}, DataTableService],
|
},
|
||||||
|
DataTableService
|
||||||
|
],
|
||||||
encapsulation: ViewEncapsulation.None,
|
encapsulation: ViewEncapsulation.None,
|
||||||
host: { class: 'adf-document-list' }
|
host: { class: 'adf-document-list' }
|
||||||
})
|
})
|
||||||
export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, AfterContentInit, PaginatedComponent, NavigableComponentInterface {
|
export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, AfterContentInit, PaginatedComponent, NavigableComponentInterface {
|
||||||
|
|
||||||
static SINGLE_CLICK_NAVIGATION: string = 'click';
|
static SINGLE_CLICK_NAVIGATION: string = 'click';
|
||||||
static DOUBLE_CLICK_NAVIGATION: string = 'dblclick';
|
static DOUBLE_CLICK_NAVIGATION: string = 'dblclick';
|
||||||
|
|
||||||
@@ -94,10 +108,7 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
|||||||
totalItems: 0
|
totalItems: 0
|
||||||
});
|
});
|
||||||
|
|
||||||
DEFAULT_SORTING: DataSorting[] = [
|
DEFAULT_SORTING: DataSorting[] = [new DataSorting('name', 'asc'), new DataSorting('isFolder', 'desc')];
|
||||||
new DataSorting('name', 'asc'),
|
|
||||||
new DataSorting('isFolder', 'desc')
|
|
||||||
];
|
|
||||||
|
|
||||||
@ContentChild(DataColumnListComponent)
|
@ContentChild(DataColumnListComponent)
|
||||||
columnList: DataColumnListComponent;
|
columnList: DataColumnListComponent;
|
||||||
@@ -362,7 +373,8 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
|||||||
return this._nodesApi;
|
return this._nodesApi;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(private documentListService: DocumentListService,
|
constructor(
|
||||||
|
private documentListService: DocumentListService,
|
||||||
private elementRef: ElementRef,
|
private elementRef: ElementRef,
|
||||||
private appConfig: AppConfigService,
|
private appConfig: AppConfigService,
|
||||||
private userPreferencesService: UserPreferencesService,
|
private userPreferencesService: UserPreferencesService,
|
||||||
@@ -372,24 +384,22 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
|||||||
private nodeService: NodesApiService,
|
private nodeService: NodesApiService,
|
||||||
private dataTableService: DataTableService,
|
private dataTableService: DataTableService,
|
||||||
private lockService: LockService,
|
private lockService: LockService,
|
||||||
private dialog: MatDialog) {
|
private dialog: MatDialog
|
||||||
|
) {
|
||||||
this.nodeService.nodeUpdated
|
this.nodeService.nodeUpdated.pipe(takeUntil(this.onDestroy$)).subscribe((node) => {
|
||||||
.pipe(takeUntil(this.onDestroy$))
|
this.dataTableService.rowUpdate.next({ id: node.id, obj: { entry: node } });
|
||||||
.subscribe((node) => {
|
|
||||||
this.dataTableService.rowUpdate.next({id: node.id, obj: {entry: node}});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.userPreferencesService
|
this.userPreferencesService
|
||||||
.select(UserPreferenceValues.PaginationSize)
|
.select(UserPreferenceValues.PaginationSize)
|
||||||
.pipe(takeUntil(this.onDestroy$))
|
.pipe(takeUntil(this.onDestroy$))
|
||||||
.subscribe(pagSize => {
|
.subscribe((pagSize) => {
|
||||||
this.maxItems = this._pagination.maxItems = pagSize;
|
this.maxItems = this._pagination.maxItems = pagSize;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getContextActions(node: NodeEntry) {
|
getContextActions(node: NodeEntry) {
|
||||||
if (node && node.entry) {
|
if (node?.entry) {
|
||||||
const actions = this.getNodeActions(node);
|
const actions = this.getNodeActions(node);
|
||||||
if (actions && actions.length > 0) {
|
if (actions && actions.length > 0) {
|
||||||
return actions.map((currentAction: ContentActionModel) => ({
|
return actions.map((currentAction: ContentActionModel) => ({
|
||||||
@@ -403,7 +413,7 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
|||||||
}
|
}
|
||||||
|
|
||||||
private get hasCustomLayout(): boolean {
|
private get hasCustomLayout(): boolean {
|
||||||
return this.columnList && this.columnList.columns && this.columnList.columns.length > 0;
|
return this.columnList?.columns?.length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getDefaultSorting(): DataSorting {
|
private getDefaultSorting(): DataSorting {
|
||||||
@@ -433,8 +443,14 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
|||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.rowMenuCache = {};
|
this.rowMenuCache = {};
|
||||||
this.loadLayoutPresets();
|
this.loadLayoutPresets();
|
||||||
this.data = new ShareDataTableAdapter(this.thumbnailService, this.contentService, null, this.getDefaultSorting(),
|
this.data = new ShareDataTableAdapter(
|
||||||
this.sortingMode, this.allowDropFiles);
|
this.thumbnailService,
|
||||||
|
this.contentService,
|
||||||
|
null,
|
||||||
|
this.getDefaultSorting(),
|
||||||
|
this.sortingMode,
|
||||||
|
this.allowDropFiles
|
||||||
|
);
|
||||||
this.data.thumbnails = this.thumbnails;
|
this.data.thumbnails = this.thumbnails;
|
||||||
this.data.permissionsStyle = this.permissionsStyle;
|
this.data.permissionsStyle = this.permissionsStyle;
|
||||||
|
|
||||||
@@ -446,9 +462,7 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
|||||||
this.data.setImageResolver(this.imageResolver);
|
this.data.setImageResolver(this.imageResolver);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.contextActionHandler
|
this.contextActionHandler.pipe(takeUntil(this.onDestroy$)).subscribe((val) => this.contextActionCallback(val));
|
||||||
.pipe(takeUntil(this.onDestroy$))
|
|
||||||
.subscribe(val => this.contextActionCallback(val));
|
|
||||||
|
|
||||||
this.enforceSingleClickNavigationForMobile();
|
this.enforceSingleClickNavigationForMobile();
|
||||||
if (this.filterValue && Object.keys(this.filterValue).length > 0) {
|
if (this.filterValue && Object.keys(this.filterValue).length > 0) {
|
||||||
@@ -458,9 +472,7 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
|||||||
|
|
||||||
ngAfterContentInit() {
|
ngAfterContentInit() {
|
||||||
if (this.columnList) {
|
if (this.columnList) {
|
||||||
this.columnList.columns.changes
|
this.columnList.columns.changes.pipe(takeUntil(this.onDestroy$)).subscribe(() => this.setTableSchema());
|
||||||
.pipe(takeUntil(this.onDestroy$))
|
|
||||||
.subscribe(() => this.setTableSchema());
|
|
||||||
}
|
}
|
||||||
this.setTableSchema();
|
this.setTableSchema();
|
||||||
}
|
}
|
||||||
@@ -517,7 +529,7 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.data) {
|
if (this.data) {
|
||||||
if (changes.node && changes.node.currentValue) {
|
if (changes.node?.currentValue) {
|
||||||
const merge = this._pagination ? this._pagination.merge : false;
|
const merge = this._pagination ? this._pagination.merge : false;
|
||||||
this.data.loadPage(changes.node.currentValue, merge, null);
|
this.data.loadPage(changes.node.currentValue, merge, null);
|
||||||
this.preserveExistingSelection();
|
this.preserveExistingSelection();
|
||||||
@@ -555,7 +567,7 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
|||||||
}
|
}
|
||||||
|
|
||||||
getNodeActions(node: NodeEntry | any): ContentActionModel[] {
|
getNodeActions(node: NodeEntry | any): ContentActionModel[] {
|
||||||
if (node && node.entry) {
|
if (node?.entry) {
|
||||||
let target = null;
|
let target = null;
|
||||||
|
|
||||||
if (node.entry.isFile) {
|
if (node.entry.isFile) {
|
||||||
@@ -575,9 +587,7 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
|||||||
|
|
||||||
const actionsByTarget = this.actions
|
const actionsByTarget = this.actions
|
||||||
.filter((entry) => {
|
.filter((entry) => {
|
||||||
const isVisible = (typeof entry.visible === 'function')
|
const isVisible = typeof entry.visible === 'function' ? entry.visible(node) : entry.visible;
|
||||||
? entry.visible(node)
|
|
||||||
: entry.visible;
|
|
||||||
|
|
||||||
return isVisible && entry.target.toLowerCase() === target;
|
return isVisible && entry.target.toLowerCase() === target;
|
||||||
})
|
})
|
||||||
@@ -613,10 +623,10 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
|||||||
return action.disabled(node);
|
return action.disabled(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((action.permission &&
|
if (
|
||||||
action.disableWithNoPermission &&
|
(action.permission && action.disableWithNoPermission && !this.contentService.hasAllowableOperations(node.entry, action.permission)) ||
|
||||||
!this.contentService.hasAllowableOperations(node.entry, action.permission)) ||
|
this.lockService.isLocked(node.entry)
|
||||||
this.lockService.isLocked(node.entry)) {
|
) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return action.disabled;
|
return action.disabled;
|
||||||
@@ -654,8 +664,7 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
|||||||
}
|
}
|
||||||
|
|
||||||
private isLinkFolder(node: Node) {
|
private isLinkFolder(node: Node) {
|
||||||
return node.nodeType === 'app:folderlink' && node.properties &&
|
return node.nodeType === 'app:folderlink' && node.properties && node.properties['cm:destination'];
|
||||||
node.properties['cm:destination'];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateCustomSourceData(nodeId: string): void {
|
private updateCustomSourceData(nodeId: string): void {
|
||||||
@@ -669,13 +678,11 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
|||||||
* @param action Action to be executed against the context.
|
* @param action Action to be executed against the context.
|
||||||
*/
|
*/
|
||||||
executeContentAction(node: NodeEntry, action: ContentActionModel) {
|
executeContentAction(node: NodeEntry, action: ContentActionModel) {
|
||||||
if (node && node.entry && action) {
|
if (node?.entry && action) {
|
||||||
const handlerSub = (typeof action.handler === 'function') ? action.handler(node, this, action.permission) : of(true);
|
const handlerSub = typeof action.handler === 'function' ? action.handler(node, this, action.permission) : of(true);
|
||||||
|
|
||||||
if (typeof action.execute === 'function' && handlerSub) {
|
if (typeof action.execute === 'function' && handlerSub) {
|
||||||
handlerSub
|
handlerSub.pipe(takeUntil(this.onDestroy$)).subscribe(() => action.execute(node));
|
||||||
.pipe(takeUntil(this.onDestroy$))
|
|
||||||
.subscribe(() => action.execute(node));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -710,16 +717,18 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
|||||||
this.updateCustomSourceData(this.currentFolderId);
|
this.updateCustomSourceData(this.currentFolderId);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.documentListService.loadFolderByNodeId(this.currentFolderId, this._pagination, this.includeFields, this.where, this.orderBy)
|
this.documentListService.loadFolderByNodeId(this.currentFolderId, this._pagination, this.includeFields, this.where, this.orderBy).subscribe(
|
||||||
.subscribe((documentNode: DocumentLoaderNode) => {
|
(documentNode: DocumentLoaderNode) => {
|
||||||
if (documentNode.currentNode) {
|
if (documentNode.currentNode) {
|
||||||
this.folderNode = documentNode.currentNode.entry;
|
this.folderNode = documentNode.currentNode.entry;
|
||||||
this.$folderNode.next(documentNode.currentNode.entry);
|
this.$folderNode.next(documentNode.currentNode.entry);
|
||||||
}
|
}
|
||||||
this.onPageLoaded(documentNode.children);
|
this.onPageLoaded(documentNode.children);
|
||||||
}, (err) => {
|
},
|
||||||
|
(err) => {
|
||||||
this.handleError(err);
|
this.handleError(err);
|
||||||
});
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
resetSelection() {
|
resetSelection() {
|
||||||
@@ -751,10 +760,7 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
|||||||
}
|
}
|
||||||
|
|
||||||
private buildOrderByArray(currentKey: string, currentDirection: string): string[] {
|
private buildOrderByArray(currentKey: string, currentDirection: string): string[] {
|
||||||
return [
|
return [`${this.additionalSorting.key} ${this.additionalSorting.direction}`, `${currentKey} ${currentDirection}`];
|
||||||
`${this.additionalSorting.key} ${this.additionalSorting.direction}`,
|
|
||||||
`${currentKey} ${currentDirection}`
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -801,7 +807,6 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
|||||||
this.executeActionClick(nodeEntry);
|
this.executeActionClick(nodeEntry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onNodeDblClick(nodeEntry: NodeEntry) {
|
onNodeDblClick(nodeEntry: NodeEntry) {
|
||||||
@@ -825,7 +830,7 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
|||||||
}
|
}
|
||||||
|
|
||||||
executeActionClick(nodeEntry: NodeEntry) {
|
executeActionClick(nodeEntry: NodeEntry) {
|
||||||
if (nodeEntry && nodeEntry.entry) {
|
if (nodeEntry?.entry) {
|
||||||
if (nodeEntry.entry.isFile) {
|
if (nodeEntry.entry.isFile) {
|
||||||
this.onPreviewFile(nodeEntry);
|
this.onPreviewFile(nodeEntry);
|
||||||
}
|
}
|
||||||
@@ -839,8 +844,7 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
|||||||
include: this.includeFields
|
include: this.includeFields
|
||||||
};
|
};
|
||||||
|
|
||||||
this.nodesApi.getNode(nodeEntry.entry['guid'], options)
|
this.nodesApi.getNode(nodeEntry.entry['guid'], options).then((node: NodeEntry) => {
|
||||||
.then((node: NodeEntry) => {
|
|
||||||
this.navigateTo(node.entry);
|
this.navigateTo(node.entry);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -911,7 +915,7 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
|||||||
canNavigateFolder(node: Node): boolean {
|
canNavigateFolder(node: Node): boolean {
|
||||||
let canNavigateFolder: boolean = false;
|
let canNavigateFolder: boolean = false;
|
||||||
|
|
||||||
if (node && node.isFolder) {
|
if (node?.isFolder) {
|
||||||
canNavigateFolder = true;
|
canNavigateFolder = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -960,8 +964,7 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
|||||||
if (JSON.parse(err.message).error.statusCode === 403) {
|
if (JSON.parse(err.message).error.statusCode === 403) {
|
||||||
this.noPermission = true;
|
this.noPermission = true;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
this.setLoadingState(false);
|
this.setLoadingState(false);
|
||||||
this.error.emit(err);
|
this.error.emit(err);
|
||||||
@@ -976,7 +979,11 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
|||||||
}
|
}
|
||||||
|
|
||||||
getSelectionBasedOnSelectionMode(): DataRow[] {
|
getSelectionBasedOnSelectionMode(): DataRow[] {
|
||||||
return this.hasPreselectedRows() ? (this.isSingleSelectionMode() ? [this.preselectedRows[0]] : this.data.getSelectedRows()) : this.data.getSelectedRows();
|
return this.hasPreselectedRows()
|
||||||
|
? this.isSingleSelectionMode()
|
||||||
|
? [this.preselectedRows[0]]
|
||||||
|
: this.data.getSelectedRows()
|
||||||
|
: this.data.getSelectedRows();
|
||||||
}
|
}
|
||||||
|
|
||||||
onPreselectNodes() {
|
onPreselectNodes() {
|
||||||
|
|||||||
+1
-1
@@ -63,7 +63,7 @@ export class FilterHeaderComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges) {
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
if (changes['currentFolderId'] && changes['currentFolderId'].currentValue) {
|
if (changes['currentFolderId']?.currentValue) {
|
||||||
this.resetFilterHeader();
|
this.resetFilterHeader();
|
||||||
this.configureSearchParent(changes['currentFolderId'].currentValue);
|
this.configureSearchParent(changes['currentFolderId'].currentValue);
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-24
@@ -15,15 +15,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import { Component, ChangeDetectionStrategy, ViewEncapsulation, OnInit, Input, ElementRef, OnDestroy } from '@angular/core';
|
||||||
Component,
|
|
||||||
ChangeDetectionStrategy,
|
|
||||||
ViewEncapsulation,
|
|
||||||
OnInit,
|
|
||||||
Input,
|
|
||||||
ElementRef,
|
|
||||||
OnDestroy
|
|
||||||
} from '@angular/core';
|
|
||||||
import { NodeEntry, Site } from '@alfresco/js-api';
|
import { NodeEntry, Site } from '@alfresco/js-api';
|
||||||
import { ShareDataRow } from '../../data/share-data-row.model';
|
import { ShareDataRow } from '../../data/share-data-row.model';
|
||||||
import { NodesApiService } from '../../../common/services/nodes-api.service';
|
import { NodesApiService } from '../../../common/services/nodes-api.service';
|
||||||
@@ -36,13 +28,17 @@ import { takeUntil } from 'rxjs/operators';
|
|||||||
template: `
|
template: `
|
||||||
<span
|
<span
|
||||||
role="link"
|
role="link"
|
||||||
[attr.aria-label]="'NAME_COLUMN_LINK.ACCESSIBILITY.ARIA_LABEL' | translate:{
|
[attr.aria-label]="
|
||||||
|
'NAME_COLUMN_LINK.ACCESSIBILITY.ARIA_LABEL'
|
||||||
|
| translate
|
||||||
|
: {
|
||||||
name: displayText$ | async
|
name: displayText$ | async
|
||||||
}"
|
}
|
||||||
|
"
|
||||||
class="adf-datatable-cell-value"
|
class="adf-datatable-cell-value"
|
||||||
title="{{ displayTooltip$ | async }}"
|
title="{{ displayTooltip$ | async }}"
|
||||||
(click)="onClick()">
|
(click)="onClick()"
|
||||||
|
>
|
||||||
{{ displayText$ | async }}
|
{{ displayText$ | async }}
|
||||||
</span>
|
</span>
|
||||||
`,
|
`,
|
||||||
@@ -62,17 +58,12 @@ export class LibraryNameColumnComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
private onDestroy$ = new Subject<boolean>();
|
private onDestroy$ = new Subject<boolean>();
|
||||||
|
|
||||||
constructor(
|
constructor(private element: ElementRef, private nodesApiService: NodesApiService) {}
|
||||||
private element: ElementRef,
|
|
||||||
private nodesApiService: NodesApiService
|
|
||||||
) {}
|
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.updateValue();
|
this.updateValue();
|
||||||
|
|
||||||
this.nodesApiService.nodeUpdated
|
this.nodesApiService.nodeUpdated.pipe(takeUntil(this.onDestroy$)).subscribe((node) => {
|
||||||
.pipe(takeUntil(this.onDestroy$))
|
|
||||||
.subscribe(node => {
|
|
||||||
const row: ShareDataRow = this.context.row;
|
const row: ShareDataRow = this.context.row;
|
||||||
if (row) {
|
if (row) {
|
||||||
const { entry } = row.node;
|
const { entry } = row.node;
|
||||||
@@ -88,10 +79,8 @@ export class LibraryNameColumnComponent implements OnInit, OnDestroy {
|
|||||||
protected updateValue() {
|
protected updateValue() {
|
||||||
this.node = this.context.row.node;
|
this.node = this.context.row.node;
|
||||||
const rows: Array<ShareDataRow> = this.context.data.rows || [];
|
const rows: Array<ShareDataRow> = this.context.data.rows || [];
|
||||||
if (this.node && this.node.entry) {
|
if (this.node?.entry) {
|
||||||
this.displayText$.next(
|
this.displayText$.next(this.makeLibraryTitle(this.node.entry as any, rows));
|
||||||
this.makeLibraryTitle(this.node.entry as any, rows)
|
|
||||||
);
|
|
||||||
this.displayTooltip$.next(this.makeLibraryTooltip(this.node.entry));
|
this.displayTooltip$.next(this.makeLibraryTooltip(this.node.entry));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-14
@@ -15,14 +15,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import { Component, OnInit, Input, ChangeDetectionStrategy, ViewEncapsulation, OnDestroy } from '@angular/core';
|
||||||
Component,
|
|
||||||
OnInit,
|
|
||||||
Input,
|
|
||||||
ChangeDetectionStrategy,
|
|
||||||
ViewEncapsulation,
|
|
||||||
OnDestroy
|
|
||||||
} from '@angular/core';
|
|
||||||
import { BehaviorSubject, Subject } from 'rxjs';
|
import { BehaviorSubject, Subject } from 'rxjs';
|
||||||
import { SiteEntry, Site } from '@alfresco/js-api';
|
import { SiteEntry, Site } from '@alfresco/js-api';
|
||||||
import { ShareDataRow } from '../../data/share-data-row.model';
|
import { ShareDataRow } from '../../data/share-data-row.model';
|
||||||
@@ -32,8 +25,8 @@ import { NodesApiService } from '../../../common/services/nodes-api.service';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'adf-library-role-column',
|
selector: 'adf-library-role-column',
|
||||||
template: `
|
template: `
|
||||||
<span class="adf-datatable-cell-value" title="{{ (displayText$ | async) | translate }}">
|
<span class="adf-datatable-cell-value" title="{{ displayText$ | async | translate }}">
|
||||||
{{ (displayText$ | async) | translate }}
|
{{ displayText$ | async | translate }}
|
||||||
</span>
|
</span>
|
||||||
`,
|
`,
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
@@ -53,9 +46,7 @@ export class LibraryRoleColumnComponent implements OnInit, OnDestroy {
|
|||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.updateValue();
|
this.updateValue();
|
||||||
|
|
||||||
this.nodesApiService.nodeUpdated
|
this.nodesApiService.nodeUpdated.pipe(takeUntil(this.onDestroy$)).subscribe((node) => {
|
||||||
.pipe(takeUntil(this.onDestroy$))
|
|
||||||
.subscribe(node => {
|
|
||||||
const row: ShareDataRow = this.context.row;
|
const row: ShareDataRow = this.context.row;
|
||||||
if (row) {
|
if (row) {
|
||||||
const { entry } = row.node;
|
const { entry } = row.node;
|
||||||
@@ -70,7 +61,7 @@ export class LibraryRoleColumnComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
protected updateValue() {
|
protected updateValue() {
|
||||||
const node: SiteEntry = this.context.row.node;
|
const node: SiteEntry = this.context.row.node;
|
||||||
if (node && node.entry) {
|
if (node?.entry) {
|
||||||
const role: string = node.entry.role;
|
const role: string = node.entry.role;
|
||||||
switch (role) {
|
switch (role) {
|
||||||
case Site.RoleEnum.SiteManager:
|
case Site.RoleEnum.SiteManager:
|
||||||
|
|||||||
+4
-6
@@ -25,8 +25,8 @@ import { takeUntil } from 'rxjs/operators';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'adf-library-status-column',
|
selector: 'adf-library-status-column',
|
||||||
template: `
|
template: `
|
||||||
<span class="adf-datatable-cell-value" title="{{ (displayText$ | async) | translate }}">
|
<span class="adf-datatable-cell-value" title="{{ displayText$ | async | translate }}">
|
||||||
{{ (displayText$ | async) | translate }}
|
{{ displayText$ | async | translate }}
|
||||||
</span>
|
</span>
|
||||||
`,
|
`,
|
||||||
host: { class: 'adf-library-status-column adf-datatable-content-cell' }
|
host: { class: 'adf-library-status-column adf-datatable-content-cell' }
|
||||||
@@ -44,9 +44,7 @@ export class LibraryStatusColumnComponent implements OnInit, OnDestroy {
|
|||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.updateValue();
|
this.updateValue();
|
||||||
|
|
||||||
this.nodesApiService.nodeUpdated
|
this.nodesApiService.nodeUpdated.pipe(takeUntil(this.onDestroy$)).subscribe((node) => {
|
||||||
.pipe(takeUntil(this.onDestroy$))
|
|
||||||
.subscribe(node => {
|
|
||||||
const row: ShareDataRow = this.context.row;
|
const row: ShareDataRow = this.context.row;
|
||||||
if (row) {
|
if (row) {
|
||||||
const { entry } = row.node;
|
const { entry } = row.node;
|
||||||
@@ -61,7 +59,7 @@ export class LibraryStatusColumnComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
protected updateValue() {
|
protected updateValue() {
|
||||||
const node: SiteEntry = this.context.row.node;
|
const node: SiteEntry = this.context.row.node;
|
||||||
if (node && node.entry) {
|
if (node?.entry) {
|
||||||
const visibility: string = node.entry.visibility;
|
const visibility: string = node.entry.visibility;
|
||||||
|
|
||||||
switch (visibility) {
|
switch (visibility) {
|
||||||
|
|||||||
+11
-17
@@ -15,15 +15,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import { Component, Input, OnInit, ChangeDetectionStrategy, ViewEncapsulation, ElementRef, OnDestroy } from '@angular/core';
|
||||||
Component,
|
|
||||||
Input,
|
|
||||||
OnInit,
|
|
||||||
ChangeDetectionStrategy,
|
|
||||||
ViewEncapsulation,
|
|
||||||
ElementRef,
|
|
||||||
OnDestroy
|
|
||||||
} from '@angular/core';
|
|
||||||
import { NodeEntry } from '@alfresco/js-api';
|
import { NodeEntry } from '@alfresco/js-api';
|
||||||
import { BehaviorSubject, Subject } from 'rxjs';
|
import { BehaviorSubject, Subject } from 'rxjs';
|
||||||
import { NodesApiService } from '../../../common/services/nodes-api.service';
|
import { NodesApiService } from '../../../common/services/nodes-api.service';
|
||||||
@@ -35,13 +27,17 @@ import { takeUntil } from 'rxjs/operators';
|
|||||||
template: `
|
template: `
|
||||||
<span
|
<span
|
||||||
role="link"
|
role="link"
|
||||||
[attr.aria-label]="'NAME_COLUMN_LINK.ACCESSIBILITY.ARIA_LABEL' | translate:{
|
[attr.aria-label]="
|
||||||
|
'NAME_COLUMN_LINK.ACCESSIBILITY.ARIA_LABEL'
|
||||||
|
| translate
|
||||||
|
: {
|
||||||
name: displayText$ | async
|
name: displayText$ | async
|
||||||
}"
|
}
|
||||||
|
"
|
||||||
class="adf-datatable-cell-value"
|
class="adf-datatable-cell-value"
|
||||||
title="{{ node | adfNodeNameTooltip }}"
|
title="{{ node | adfNodeNameTooltip }}"
|
||||||
(click)="onClick()">
|
(click)="onClick()"
|
||||||
|
>
|
||||||
{{ displayText$ | async }}
|
{{ displayText$ | async }}
|
||||||
</span>
|
</span>
|
||||||
`,
|
`,
|
||||||
@@ -66,9 +62,7 @@ export class NameColumnComponent implements OnInit, OnDestroy {
|
|||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.updateValue();
|
this.updateValue();
|
||||||
|
|
||||||
this.nodesApiService.nodeUpdated
|
this.nodesApiService.nodeUpdated.pipe(takeUntil(this.onDestroy$)).subscribe((node) => {
|
||||||
.pipe(takeUntil(this.onDestroy$))
|
|
||||||
.subscribe(node => {
|
|
||||||
const row: ShareDataRow = this.context.row;
|
const row: ShareDataRow = this.context.row;
|
||||||
if (row) {
|
if (row) {
|
||||||
const { entry } = row.node;
|
const { entry } = row.node;
|
||||||
@@ -84,7 +78,7 @@ export class NameColumnComponent implements OnInit, OnDestroy {
|
|||||||
protected updateValue() {
|
protected updateValue() {
|
||||||
this.node = this.context.row.node;
|
this.node = this.context.row.node;
|
||||||
|
|
||||||
if (this.node && this.node.entry) {
|
if (this.node?.entry) {
|
||||||
const displayText = this.context.row.getValue(this.key);
|
const displayText = this.context.row.getValue(this.key);
|
||||||
this.displayText$.next(displayText || this.node.entry.id);
|
this.displayText$.next(displayText || this.node.entry.id);
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-13
@@ -15,13 +15,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import { Component, ChangeDetectionStrategy, ViewEncapsulation, OnInit, Input } from '@angular/core';
|
||||||
Component,
|
|
||||||
ChangeDetectionStrategy,
|
|
||||||
ViewEncapsulation,
|
|
||||||
OnInit,
|
|
||||||
Input
|
|
||||||
} from '@angular/core';
|
|
||||||
import { NodeEntry } from '@alfresco/js-api';
|
import { NodeEntry } from '@alfresco/js-api';
|
||||||
import { ShareDataRow } from '../../data/share-data-row.model';
|
import { ShareDataRow } from '../../data/share-data-row.model';
|
||||||
|
|
||||||
@@ -52,15 +46,14 @@ export class TrashcanNameColumnComponent implements OnInit {
|
|||||||
this.node = this.context.row.node;
|
this.node = this.context.row.node;
|
||||||
const rows: Array<ShareDataRow> = this.context.data.rows || [];
|
const rows: Array<ShareDataRow> = this.context.data.rows || [];
|
||||||
|
|
||||||
if (this.node && this.node.entry) {
|
if (this.node?.entry) {
|
||||||
this.isLibrary = this.node.entry.nodeType === 'st:site';
|
this.isLibrary = this.node.entry.nodeType === 'st:site';
|
||||||
|
|
||||||
if (this.isLibrary) {
|
if (this.isLibrary) {
|
||||||
const { properties } = this.node.entry;
|
const { properties } = this.node.entry;
|
||||||
|
|
||||||
this.displayText = this.makeLibraryTitle(this.node.entry, rows);
|
this.displayText = this.makeLibraryTitle(this.node.entry, rows);
|
||||||
this.displayTooltip =
|
this.displayTooltip = properties['cm:description'] || properties['cm:title'];
|
||||||
properties['cm:description'] || properties['cm:title'];
|
|
||||||
} else {
|
} else {
|
||||||
this.displayText = this.node.entry.name || this.node.entry.id;
|
this.displayText = this.node.entry.name || this.node.entry.id;
|
||||||
}
|
}
|
||||||
@@ -78,8 +71,6 @@ export class TrashcanNameColumnComponent implements OnInit {
|
|||||||
isDuplicate = entries.some((entry: any) => entry.id !== id && entry.properties['cm:title'] === title);
|
isDuplicate = entries.some((entry: any) => entry.id !== id && entry.properties['cm:title'] === title);
|
||||||
}
|
}
|
||||||
|
|
||||||
return isDuplicate
|
return isDuplicate ? `${library.properties['cm:title']} (${library.name})` : `${library.properties['cm:title']}`;
|
||||||
? `${library.properties['cm:title']} (${library.name})`
|
|
||||||
: `${library.properties['cm:title']}`;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,11 +95,11 @@ export class ShareDataRow implements DataRow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
isFile(nodeEntry: NodeEntry): boolean {
|
isFile(nodeEntry: NodeEntry): boolean {
|
||||||
return nodeEntry.entry && nodeEntry.entry.isFile;
|
return nodeEntry.entry?.isFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
isFolder(nodeEntry: NodeEntry): boolean {
|
isFolder(nodeEntry: NodeEntry): boolean {
|
||||||
return nodeEntry.entry && nodeEntry.entry.isFolder;
|
return nodeEntry.entry?.isFolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
cacheValue(key: string, value: any): any {
|
cacheValue(key: string, value: any): any {
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ export class DocumentListService implements DocumentListLoader {
|
|||||||
*/
|
*/
|
||||||
getFolder(folder: string, opts?: any, includeFields: string[] = []): Observable<NodePaging> {
|
getFolder(folder: string, opts?: any, includeFields: string[] = []): Observable<NodePaging> {
|
||||||
let rootNodeId = ROOT_ID;
|
let rootNodeId = ROOT_ID;
|
||||||
if (opts && opts.rootFolderId) {
|
if (opts?.rootFolderId) {
|
||||||
rootNodeId = opts.rootFolderId;
|
rootNodeId = opts.rootFolderId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -51,7 +51,7 @@ export class SearchPermissionConfigurationService implements SearchConfiguration
|
|||||||
|
|
||||||
private getQuery(searchTerm: string) {
|
private getQuery(searchTerm: string) {
|
||||||
let query: string;
|
let query: string;
|
||||||
if (this.queryProvider && this.queryProvider.query) {
|
if (this.queryProvider?.query) {
|
||||||
query = this.queryProvider.query.replace(new RegExp(/\${([^}]+)}/g), searchTerm);
|
query = this.queryProvider.query.replace(new RegExp(/\${([^}]+)}/g), searchTerm);
|
||||||
} else {
|
} else {
|
||||||
query = `(email:*${searchTerm}* OR firstName:*${searchTerm}* OR lastName:*${searchTerm}* OR displayName:*${searchTerm}* OR authorityName:*${searchTerm}* OR authorityDisplayName:*${searchTerm}*) AND ANAME:(\"0/APP.DEFAULT\")`;
|
query = `(email:*${searchTerm}* OR firstName:*${searchTerm}* OR lastName:*${searchTerm}* OR displayName:*${searchTerm}* OR authorityName:*${searchTerm}* OR authorityDisplayName:*${searchTerm}*) AND ANAME:(\"0/APP.DEFAULT\")`;
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import { NodeEntry } from '@alfresco/js-api';
|
|||||||
name: 'adfNodeNameTooltip'
|
name: 'adfNodeNameTooltip'
|
||||||
})
|
})
|
||||||
export class NodeNameTooltipPipe implements PipeTransform {
|
export class NodeNameTooltipPipe implements PipeTransform {
|
||||||
|
|
||||||
transform(node: NodeEntry): string {
|
transform(node: NodeEntry): string {
|
||||||
if (node) {
|
if (node) {
|
||||||
return this.getNodeTooltip(node);
|
return this.getNodeTooltip(node);
|
||||||
@@ -46,18 +45,17 @@ export class NodeNameTooltipPipe implements PipeTransform {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getNodeTooltip(node: NodeEntry): string {
|
private getNodeTooltip(node: NodeEntry): string {
|
||||||
if (!node || !node.entry) {
|
if (!node?.entry) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { entry: { properties, name } } = node;
|
const {
|
||||||
const lines = [ name ];
|
entry: { properties, name }
|
||||||
|
} = node;
|
||||||
|
const lines = [name];
|
||||||
|
|
||||||
if (properties) {
|
if (properties) {
|
||||||
const {
|
const { 'cm:title': title, 'cm:description': description } = properties;
|
||||||
'cm:title': title,
|
|
||||||
'cm:description': description
|
|
||||||
} = properties;
|
|
||||||
|
|
||||||
if (title && description) {
|
if (title && description) {
|
||||||
lines[0] = title;
|
lines[0] = title;
|
||||||
|
|||||||
@@ -16,8 +16,19 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { AuthenticationService, ThumbnailService, SearchTextInputComponent } from '@alfresco/adf-core';
|
import { AuthenticationService, ThumbnailService, SearchTextInputComponent } from '@alfresco/adf-core';
|
||||||
import { Component, EventEmitter, Input, OnDestroy, Output,
|
import {
|
||||||
QueryList, ViewEncapsulation, ViewChild, ViewChildren, TemplateRef, ContentChild } from '@angular/core';
|
Component,
|
||||||
|
EventEmitter,
|
||||||
|
Input,
|
||||||
|
OnDestroy,
|
||||||
|
Output,
|
||||||
|
QueryList,
|
||||||
|
ViewEncapsulation,
|
||||||
|
ViewChild,
|
||||||
|
ViewChildren,
|
||||||
|
TemplateRef,
|
||||||
|
ContentChild
|
||||||
|
} from '@angular/core';
|
||||||
import { NodeEntry } from '@alfresco/js-api';
|
import { NodeEntry } from '@alfresco/js-api';
|
||||||
import { Subject } from 'rxjs';
|
import { Subject } from 'rxjs';
|
||||||
import { SearchComponent } from './search.component';
|
import { SearchComponent } from './search.component';
|
||||||
@@ -32,7 +43,6 @@ import { EmptySearchResultComponent } from './empty-search-result.component';
|
|||||||
host: { class: 'adf-search-control' }
|
host: { class: 'adf-search-control' }
|
||||||
})
|
})
|
||||||
export class SearchControlComponent implements OnDestroy {
|
export class SearchControlComponent implements OnDestroy {
|
||||||
|
|
||||||
/** Toggles highlighting of the search term in the results. */
|
/** Toggles highlighting of the search term in the results. */
|
||||||
@Input()
|
@Input()
|
||||||
highlight: boolean = false;
|
highlight: boolean = false;
|
||||||
@@ -90,15 +100,12 @@ export class SearchControlComponent implements OnDestroy {
|
|||||||
emptySearchTemplate: EmptySearchResultComponent;
|
emptySearchTemplate: EmptySearchResultComponent;
|
||||||
|
|
||||||
focusSubject = new Subject<FocusEvent>();
|
focusSubject = new Subject<FocusEvent>();
|
||||||
noSearchResultTemplate: TemplateRef <any> = null;
|
noSearchResultTemplate: TemplateRef<any> = null;
|
||||||
searchTerm: string = '';
|
searchTerm: string = '';
|
||||||
|
|
||||||
private onDestroy$ = new Subject<boolean>();
|
private onDestroy$ = new Subject<boolean>();
|
||||||
|
|
||||||
constructor(
|
constructor(public authService: AuthenticationService, private thumbnailService: ThumbnailService) {}
|
||||||
public authService: AuthenticationService,
|
|
||||||
private thumbnailService: ThumbnailService
|
|
||||||
) {}
|
|
||||||
|
|
||||||
isNoSearchTemplatePresent(): boolean {
|
isNoSearchTemplatePresent(): boolean {
|
||||||
return !!this.emptySearchTemplate;
|
return !!this.emptySearchTemplate;
|
||||||
@@ -126,7 +133,7 @@ export class SearchControlComponent implements OnDestroy {
|
|||||||
getMimeType(node: NodeEntry): string {
|
getMimeType(node: NodeEntry): string {
|
||||||
let mimeType: string;
|
let mimeType: string;
|
||||||
|
|
||||||
if (node.entry.content && node.entry.content.mimeType) {
|
if (node.entry.content?.mimeType) {
|
||||||
mimeType = node.entry.content.mimeType;
|
mimeType = node.entry.content.mimeType;
|
||||||
}
|
}
|
||||||
if (node.entry.isFolder) {
|
if (node.entry.isFolder) {
|
||||||
@@ -154,7 +161,7 @@ export class SearchControlComponent implements OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onSelectFirstResult() {
|
onSelectFirstResult() {
|
||||||
if ( this.listResultElement && this.listResultElement.length > 0) {
|
if (this.listResultElement && this.listResultElement.length > 0) {
|
||||||
const firstElement = this.listResultElement.first as MatListItem;
|
const firstElement = this.listResultElement.first as MatListItem;
|
||||||
// eslint-disable-next-line no-underscore-dangle
|
// eslint-disable-next-line no-underscore-dangle
|
||||||
firstElement._getHostElement().focus();
|
firstElement._getHostElement().focus();
|
||||||
@@ -184,7 +191,7 @@ export class SearchControlComponent implements OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private isListElement(event: any): boolean {
|
private isListElement(event: any): boolean {
|
||||||
return event.relatedTarget && event.relatedTarget.children[0] && event.relatedTarget.children[0].className === 'mat-list-item-content';
|
return event.relatedTarget?.children[0] && event.relatedTarget.children[0].className === 'mat-list-item-content';
|
||||||
}
|
}
|
||||||
|
|
||||||
private getNextElementSibling(node: Element): Element {
|
private getNextElementSibling(node: Element): Element {
|
||||||
|
|||||||
+29
-28
@@ -18,12 +18,7 @@
|
|||||||
import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
|
import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
|
||||||
import { UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms';
|
import { UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms';
|
||||||
import { DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE } from '@angular/material/core';
|
import { DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE } from '@angular/material/core';
|
||||||
import {
|
import { MOMENT_DATE_FORMATS, MomentDateAdapter, UserPreferencesService, UserPreferenceValues } from '@alfresco/adf-core';
|
||||||
MOMENT_DATE_FORMATS,
|
|
||||||
MomentDateAdapter,
|
|
||||||
UserPreferencesService,
|
|
||||||
UserPreferenceValues
|
|
||||||
} from '@alfresco/adf-core';
|
|
||||||
|
|
||||||
import { SearchWidget } from '../../models/search-widget.interface';
|
import { SearchWidget } from '../../models/search-widget.interface';
|
||||||
import { SearchWidgetSettings } from '../../models/search-widget-settings.interface';
|
import { SearchWidgetSettings } from '../../models/search-widget-settings.interface';
|
||||||
@@ -54,7 +49,6 @@ const DEFAULT_FORMAT_DATE: string = 'DD/MM/YYYY';
|
|||||||
host: { class: 'adf-search-date-range' }
|
host: { class: 'adf-search-date-range' }
|
||||||
})
|
})
|
||||||
export class SearchDateRangeComponent implements SearchWidget, OnInit, OnDestroy {
|
export class SearchDateRangeComponent implements SearchWidget, OnInit, OnDestroy {
|
||||||
|
|
||||||
from: UntypedFormControl;
|
from: UntypedFormControl;
|
||||||
to: UntypedFormControl;
|
to: UntypedFormControl;
|
||||||
|
|
||||||
@@ -74,23 +68,28 @@ export class SearchDateRangeComponent implements SearchWidget, OnInit, OnDestroy
|
|||||||
|
|
||||||
private onDestroy$ = new Subject<boolean>();
|
private onDestroy$ = new Subject<boolean>();
|
||||||
|
|
||||||
constructor(private dateAdapter: DateAdapter<Moment>,
|
constructor(private dateAdapter: DateAdapter<Moment>, private userPreferencesService: UserPreferencesService) {}
|
||||||
private userPreferencesService: UserPreferencesService) {
|
|
||||||
}
|
|
||||||
|
|
||||||
getFromValidationMessage(): string {
|
getFromValidationMessage(): string {
|
||||||
return this.from.hasError('invalidOnChange') || this.hasParseError(this.from) ? 'SEARCH.FILTER.VALIDATION.INVALID-DATE' :
|
return this.from.hasError('invalidOnChange') || this.hasParseError(this.from)
|
||||||
this.from.hasError('matDatepickerMax') ? 'SEARCH.FILTER.VALIDATION.BEYOND-MAX-DATE' :
|
? 'SEARCH.FILTER.VALIDATION.INVALID-DATE'
|
||||||
this.from.hasError('required') ? 'SEARCH.FILTER.VALIDATION.REQUIRED-VALUE' :
|
: this.from.hasError('matDatepickerMax')
|
||||||
'';
|
? 'SEARCH.FILTER.VALIDATION.BEYOND-MAX-DATE'
|
||||||
|
: this.from.hasError('required')
|
||||||
|
? 'SEARCH.FILTER.VALIDATION.REQUIRED-VALUE'
|
||||||
|
: '';
|
||||||
}
|
}
|
||||||
|
|
||||||
getToValidationMessage(): string {
|
getToValidationMessage(): string {
|
||||||
return this.to.hasError('invalidOnChange') || this.hasParseError(this.to) ? 'SEARCH.FILTER.VALIDATION.INVALID-DATE' :
|
return this.to.hasError('invalidOnChange') || this.hasParseError(this.to)
|
||||||
this.to.hasError('matDatepickerMin') ? 'SEARCH.FILTER.VALIDATION.NO-DAYS' :
|
? 'SEARCH.FILTER.VALIDATION.INVALID-DATE'
|
||||||
this.to.hasError('matDatepickerMax') ? 'SEARCH.FILTER.VALIDATION.BEYOND-MAX-DATE' :
|
: this.to.hasError('matDatepickerMin')
|
||||||
this.to.hasError('required') ? 'SEARCH.FILTER.VALIDATION.REQUIRED-VALUE' :
|
? 'SEARCH.FILTER.VALIDATION.NO-DAYS'
|
||||||
'';
|
: this.to.hasError('matDatepickerMax')
|
||||||
|
? 'SEARCH.FILTER.VALIDATION.BEYOND-MAX-DATE'
|
||||||
|
: this.to.hasError('required')
|
||||||
|
? 'SEARCH.FILTER.VALIDATION.REQUIRED-VALUE'
|
||||||
|
: '';
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
@@ -102,13 +101,11 @@ export class SearchDateRangeComponent implements SearchWidget, OnInit, OnDestroy
|
|||||||
this.userPreferencesService
|
this.userPreferencesService
|
||||||
.select(UserPreferenceValues.Locale)
|
.select(UserPreferenceValues.Locale)
|
||||||
.pipe(takeUntil(this.onDestroy$))
|
.pipe(takeUntil(this.onDestroy$))
|
||||||
.subscribe(locale => this.setLocale(locale));
|
.subscribe((locale) => this.setLocale(locale));
|
||||||
|
|
||||||
const validators = Validators.compose([
|
const validators = Validators.compose([Validators.required]);
|
||||||
Validators.required
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (this.settings && this.settings.maxDate) {
|
if (this.settings?.maxDate) {
|
||||||
if (this.settings.maxDate === 'today') {
|
if (this.settings.maxDate === 'today') {
|
||||||
this.maxDate = this.dateAdapter.today().endOf('day');
|
this.maxDate = this.dateAdapter.today().endOf('day');
|
||||||
} else {
|
} else {
|
||||||
@@ -174,7 +171,12 @@ export class SearchDateRangeComponent implements SearchWidget, OnInit, OnDestroy
|
|||||||
if (this.form.invalid || this.form.pristine) {
|
if (this.form.invalid || this.form.pristine) {
|
||||||
this.displayValue$.next('');
|
this.displayValue$.next('');
|
||||||
} else {
|
} else {
|
||||||
this.displayValue$.next(`${this.dateAdapter.format(this.form.value.from, this.datePickerFormat)} - ${this.dateAdapter.format(this.form.value.to, this.datePickerFormat)}`);
|
this.displayValue$.next(
|
||||||
|
`${this.dateAdapter.format(this.form.value.from, this.datePickerFormat)} - ${this.dateAdapter.format(
|
||||||
|
this.form.value.to,
|
||||||
|
this.datePickerFormat
|
||||||
|
)}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,10 +221,9 @@ export class SearchDateRangeComponent implements SearchWidget, OnInit, OnDestroy
|
|||||||
}
|
}
|
||||||
|
|
||||||
onChangedHandler(event: any, formControl: UntypedFormControl) {
|
onChangedHandler(event: any, formControl: UntypedFormControl) {
|
||||||
|
|
||||||
const inputValue = event.value;
|
const inputValue = event.value;
|
||||||
const formatDate = this.dateAdapter.parse(inputValue, this.datePickerFormat);
|
const formatDate = this.dateAdapter.parse(inputValue, this.datePickerFormat);
|
||||||
if (formatDate && formatDate.isValid()) {
|
if (formatDate?.isValid()) {
|
||||||
formControl.setValue(formatDate);
|
formControl.setValue(formatDate);
|
||||||
} else if (formatDate) {
|
} else if (formatDate) {
|
||||||
formControl.setErrors({
|
formControl.setErrors({
|
||||||
@@ -247,6 +248,6 @@ export class SearchDateRangeComponent implements SearchWidget, OnInit, OnDestroy
|
|||||||
}
|
}
|
||||||
|
|
||||||
setFromMaxDate() {
|
setFromMaxDate() {
|
||||||
this.fromMaxDate = (!this.to.value || this.maxDate && (moment(this.maxDate).isBefore(this.to.value))) ? this.maxDate : moment(this.to.value);
|
this.fromMaxDate = !this.to.value || (this.maxDate && moment(this.maxDate).isBefore(this.to.value)) ? this.maxDate : moment(this.to.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+30
-25
@@ -42,14 +42,11 @@ const DEFAULT_DATETIME_FORMAT: string = 'DD/MM/YYYY HH:mm';
|
|||||||
selector: 'adf-search-datetime-range',
|
selector: 'adf-search-datetime-range',
|
||||||
templateUrl: './search-datetime-range.component.html',
|
templateUrl: './search-datetime-range.component.html',
|
||||||
styleUrls: ['./search-datetime-range.component.scss'],
|
styleUrls: ['./search-datetime-range.component.scss'],
|
||||||
providers: [
|
providers: [{ provide: MAT_DATETIME_FORMATS, useValue: MAT_MOMENT_DATETIME_FORMATS }],
|
||||||
{ provide: MAT_DATETIME_FORMATS, useValue: MAT_MOMENT_DATETIME_FORMATS }
|
|
||||||
],
|
|
||||||
encapsulation: ViewEncapsulation.None,
|
encapsulation: ViewEncapsulation.None,
|
||||||
host: { class: 'adf-search-date-range' }
|
host: { class: 'adf-search-date-range' }
|
||||||
})
|
})
|
||||||
export class SearchDatetimeRangeComponent implements SearchWidget, OnInit, OnDestroy {
|
export class SearchDatetimeRangeComponent implements SearchWidget, OnInit, OnDestroy {
|
||||||
|
|
||||||
from: UntypedFormControl;
|
from: UntypedFormControl;
|
||||||
to: UntypedFormControl;
|
to: UntypedFormControl;
|
||||||
|
|
||||||
@@ -69,23 +66,28 @@ export class SearchDatetimeRangeComponent implements SearchWidget, OnInit, OnDes
|
|||||||
|
|
||||||
private onDestroy$ = new Subject<boolean>();
|
private onDestroy$ = new Subject<boolean>();
|
||||||
|
|
||||||
constructor(private dateAdapter: DatetimeAdapter<Moment>,
|
constructor(private dateAdapter: DatetimeAdapter<Moment>, private userPreferencesService: UserPreferencesService) {}
|
||||||
private userPreferencesService: UserPreferencesService) {
|
|
||||||
}
|
|
||||||
|
|
||||||
getFromValidationMessage(): string {
|
getFromValidationMessage(): string {
|
||||||
return this.from.hasError('invalidOnChange') || this.hasParseError(this.from) ? 'SEARCH.FILTER.VALIDATION.INVALID-DATETIME' :
|
return this.from.hasError('invalidOnChange') || this.hasParseError(this.from)
|
||||||
this.from.hasError('matDatepickerMax') ? 'SEARCH.FILTER.VALIDATION.BEYOND-MAX-DATETIME' :
|
? 'SEARCH.FILTER.VALIDATION.INVALID-DATETIME'
|
||||||
this.from.hasError('required') ? 'SEARCH.FILTER.VALIDATION.REQUIRED-VALUE' :
|
: this.from.hasError('matDatepickerMax')
|
||||||
'';
|
? 'SEARCH.FILTER.VALIDATION.BEYOND-MAX-DATETIME'
|
||||||
|
: this.from.hasError('required')
|
||||||
|
? 'SEARCH.FILTER.VALIDATION.REQUIRED-VALUE'
|
||||||
|
: '';
|
||||||
}
|
}
|
||||||
|
|
||||||
getToValidationMessage(): string {
|
getToValidationMessage(): string {
|
||||||
return this.to.hasError('invalidOnChange') || this.hasParseError(this.to) ? 'SEARCH.FILTER.VALIDATION.INVALID-DATETIME' :
|
return this.to.hasError('invalidOnChange') || this.hasParseError(this.to)
|
||||||
this.to.hasError('matDatepickerMin') ? 'SEARCH.FILTER.VALIDATION.NO-DAYS' :
|
? 'SEARCH.FILTER.VALIDATION.INVALID-DATETIME'
|
||||||
this.to.hasError('matDatepickerMax') ? 'SEARCH.FILTER.VALIDATION.BEYOND-MAX-DATETIME' :
|
: this.to.hasError('matDatepickerMin')
|
||||||
this.to.hasError('required') ? 'SEARCH.FILTER.VALIDATION.REQUIRED-VALUE' :
|
? 'SEARCH.FILTER.VALIDATION.NO-DAYS'
|
||||||
'';
|
: this.to.hasError('matDatepickerMax')
|
||||||
|
? 'SEARCH.FILTER.VALIDATION.BEYOND-MAX-DATETIME'
|
||||||
|
: this.to.hasError('required')
|
||||||
|
? 'SEARCH.FILTER.VALIDATION.REQUIRED-VALUE'
|
||||||
|
: '';
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
@@ -94,13 +96,11 @@ export class SearchDatetimeRangeComponent implements SearchWidget, OnInit, OnDes
|
|||||||
this.userPreferencesService
|
this.userPreferencesService
|
||||||
.select(UserPreferenceValues.Locale)
|
.select(UserPreferenceValues.Locale)
|
||||||
.pipe(takeUntil(this.onDestroy$))
|
.pipe(takeUntil(this.onDestroy$))
|
||||||
.subscribe(locale => this.setLocale(locale));
|
.subscribe((locale) => this.setLocale(locale));
|
||||||
|
|
||||||
const validators = Validators.compose([
|
const validators = Validators.compose([Validators.required]);
|
||||||
Validators.required
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (this.settings && this.settings.maxDatetime) {
|
if (this.settings?.maxDatetime) {
|
||||||
this.maxDatetime = moment(this.settings.maxDatetime);
|
this.maxDatetime = moment(this.settings.maxDatetime);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,7 +161,12 @@ export class SearchDatetimeRangeComponent implements SearchWidget, OnInit, OnDes
|
|||||||
if (this.form.invalid || this.form.pristine) {
|
if (this.form.invalid || this.form.pristine) {
|
||||||
this.displayValue$.next('');
|
this.displayValue$.next('');
|
||||||
} else {
|
} else {
|
||||||
this.displayValue$.next(`${this.dateAdapter.format(this.form.value.from, this.datetimePickerFormat)} - ${this.dateAdapter.format(this.form.value.to, this.datetimePickerFormat)}`);
|
this.displayValue$.next(
|
||||||
|
`${this.dateAdapter.format(this.form.value.from, this.datetimePickerFormat)} - ${this.dateAdapter.format(
|
||||||
|
this.form.value.to,
|
||||||
|
this.datetimePickerFormat
|
||||||
|
)}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,10 +212,9 @@ export class SearchDatetimeRangeComponent implements SearchWidget, OnInit, OnDes
|
|||||||
}
|
}
|
||||||
|
|
||||||
onChangedHandler(event: any, formControl: UntypedFormControl) {
|
onChangedHandler(event: any, formControl: UntypedFormControl) {
|
||||||
|
|
||||||
const inputValue = event.value;
|
const inputValue = event.value;
|
||||||
const formatDate = this.dateAdapter.parse(inputValue, this.datetimePickerFormat);
|
const formatDate = this.dateAdapter.parse(inputValue, this.datetimePickerFormat);
|
||||||
if (formatDate && formatDate.isValid()) {
|
if (formatDate?.isValid()) {
|
||||||
formControl.setValue(formatDate);
|
formControl.setValue(formatDate);
|
||||||
} else if (formatDate) {
|
} else if (formatDate) {
|
||||||
formControl.setErrors({
|
formControl.setErrors({
|
||||||
@@ -235,6 +239,7 @@ export class SearchDatetimeRangeComponent implements SearchWidget, OnInit, OnDes
|
|||||||
}
|
}
|
||||||
|
|
||||||
setFromMaxDatetime() {
|
setFromMaxDatetime() {
|
||||||
this.fromMaxDatetime = (!this.to.value || this.maxDatetime && (moment(this.maxDatetime).isBefore(this.to.value))) ? this.maxDatetime : moment(this.to.value);
|
this.fromMaxDatetime =
|
||||||
|
!this.to.value || (this.maxDatetime && moment(this.maxDatetime).isBefore(this.to.value)) ? this.maxDatetime : moment(this.to.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-7
@@ -33,16 +33,16 @@ import { Subject } from 'rxjs';
|
|||||||
encapsulation: ViewEncapsulation.None
|
encapsulation: ViewEncapsulation.None
|
||||||
})
|
})
|
||||||
export class SearchFacetFieldComponent implements FacetWidget {
|
export class SearchFacetFieldComponent implements FacetWidget {
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
field!: FacetField;
|
field!: FacetField;
|
||||||
|
|
||||||
displayValue$: Subject<string> = new Subject<string>();
|
displayValue$: Subject<string> = new Subject<string>();
|
||||||
|
|
||||||
constructor(@Inject(SEARCH_QUERY_SERVICE_TOKEN) public queryBuilder: SearchQueryBuilderService,
|
constructor(
|
||||||
|
@Inject(SEARCH_QUERY_SERVICE_TOKEN) public queryBuilder: SearchQueryBuilderService,
|
||||||
private searchFacetFiltersService: SearchFacetFiltersService,
|
private searchFacetFiltersService: SearchFacetFiltersService,
|
||||||
private translationService: TranslationService) {
|
private translationService: TranslationService
|
||||||
}
|
) {}
|
||||||
|
|
||||||
get canUpdateOnChange() {
|
get canUpdateOnChange() {
|
||||||
return this.field.settings?.allowUpdateOnChange ?? true;
|
return this.field.settings?.allowUpdateOnChange ?? true;
|
||||||
@@ -83,14 +83,14 @@ export class SearchFacetFieldComponent implements FacetWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
canResetSelectedBuckets(field: FacetField): boolean {
|
canResetSelectedBuckets(field: FacetField): boolean {
|
||||||
if (field && field.buckets) {
|
if (field?.buckets) {
|
||||||
return field.buckets.items.some((bucket) => bucket.checked);
|
return field.buckets.items.some((bucket) => bucket.checked);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
resetSelectedBuckets(field: FacetField) {
|
resetSelectedBuckets(field: FacetField) {
|
||||||
if (field && field.buckets) {
|
if (field?.buckets) {
|
||||||
for (const bucket of field.buckets.items) {
|
for (const bucket of field.buckets.items) {
|
||||||
bucket.checked = false;
|
bucket.checked = false;
|
||||||
this.queryBuilder.removeUserFacetBucket(field.field, bucket);
|
this.queryBuilder.removeUserFacetBucket(field.field, bucket);
|
||||||
@@ -110,7 +110,8 @@ export class SearchFacetFieldComponent implements FacetWidget {
|
|||||||
if (!this.field.buckets?.items) {
|
if (!this.field.buckets?.items) {
|
||||||
this.displayValue$.next('');
|
this.displayValue$.next('');
|
||||||
} else {
|
} else {
|
||||||
const displayValue = this.field.buckets?.items?.filter((item) => item.checked)
|
const displayValue = this.field.buckets?.items
|
||||||
|
?.filter((item) => item.checked)
|
||||||
.map((item) => this.translationService.instant(item.display || item.label))
|
.map((item) => this.translationService.instant(item.display || item.label))
|
||||||
.join(', ');
|
.join(', ');
|
||||||
this.displayValue$.next(displayValue);
|
this.displayValue$.next(displayValue);
|
||||||
|
|||||||
+7
-5
@@ -15,7 +15,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Component, Inject, Input, ViewEncapsulation } from '@angular/core';
|
import { Component, Inject, Input, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
|
||||||
import { SearchFacetFiltersService } from '../../services/search-facet-filters.service';
|
import { SearchFacetFiltersService } from '../../services/search-facet-filters.service';
|
||||||
import { SEARCH_QUERY_SERVICE_TOKEN } from '../../search-query-service.token';
|
import { SEARCH_QUERY_SERVICE_TOKEN } from '../../search-query-service.token';
|
||||||
import { SearchQueryBuilderService } from '../../services/search-query-builder.service';
|
import { SearchQueryBuilderService } from '../../services/search-query-builder.service';
|
||||||
@@ -28,7 +28,7 @@ import { takeUntil } from 'rxjs/operators';
|
|||||||
styleUrls: ['./search-filter-chips.component.scss'],
|
styleUrls: ['./search-filter-chips.component.scss'],
|
||||||
encapsulation: ViewEncapsulation.None
|
encapsulation: ViewEncapsulation.None
|
||||||
})
|
})
|
||||||
export class SearchFilterChipsComponent {
|
export class SearchFilterChipsComponent implements OnInit, OnDestroy {
|
||||||
private onDestroy$ = new Subject<void>();
|
private onDestroy$ = new Subject<void>();
|
||||||
|
|
||||||
/** Toggles whether to show or not the context facet filters. */
|
/** Toggles whether to show or not the context facet filters. */
|
||||||
@@ -40,12 +40,14 @@ export class SearchFilterChipsComponent {
|
|||||||
constructor(
|
constructor(
|
||||||
@Inject(SEARCH_QUERY_SERVICE_TOKEN)
|
@Inject(SEARCH_QUERY_SERVICE_TOKEN)
|
||||||
public queryBuilder: SearchQueryBuilderService,
|
public queryBuilder: SearchQueryBuilderService,
|
||||||
public facetFiltersService: SearchFacetFiltersService) {}
|
public facetFiltersService: SearchFacetFiltersService
|
||||||
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.queryBuilder.executed.asObservable()
|
this.queryBuilder.executed
|
||||||
|
.asObservable()
|
||||||
.pipe(takeUntil(this.onDestroy$))
|
.pipe(takeUntil(this.onDestroy$))
|
||||||
.subscribe(() => this.facetChipTabbedId = 'search-fact-chip-tabbed-' + this.facetFiltersService.tabbedFacet?.fields.join('-'));
|
.subscribe(() => (this.facetChipTabbedId = 'search-fact-chip-tabbed-' + this.facetFiltersService.tabbedFacet?.fields.join('-')));
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
|
|||||||
+6
-17
@@ -15,18 +15,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import { Component, Input, Output, OnInit, EventEmitter, ViewEncapsulation, ViewChild, Inject, OnDestroy, ElementRef } from '@angular/core';
|
||||||
Component,
|
|
||||||
Input,
|
|
||||||
Output,
|
|
||||||
OnInit,
|
|
||||||
EventEmitter,
|
|
||||||
ViewEncapsulation,
|
|
||||||
ViewChild,
|
|
||||||
Inject,
|
|
||||||
OnDestroy,
|
|
||||||
ElementRef
|
|
||||||
} from '@angular/core';
|
|
||||||
import { ConfigurableFocusTrapFactory, ConfigurableFocusTrap } from '@angular/cdk/a11y';
|
import { ConfigurableFocusTrapFactory, ConfigurableFocusTrap } from '@angular/cdk/a11y';
|
||||||
import { DataColumn, TranslationService } from '@alfresco/adf-core';
|
import { DataColumn, TranslationService } from '@alfresco/adf-core';
|
||||||
import { SearchWidgetContainerComponent } from '../search-widget-container/search-widget-container.component';
|
import { SearchWidgetContainerComponent } from '../search-widget-container/search-widget-container.component';
|
||||||
@@ -44,7 +33,6 @@ import { FilterSearch } from '../../models/filter-search.interface';
|
|||||||
encapsulation: ViewEncapsulation.None
|
encapsulation: ViewEncapsulation.None
|
||||||
})
|
})
|
||||||
export class SearchFilterContainerComponent implements OnInit, OnDestroy {
|
export class SearchFilterContainerComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
/** The column the filter will be applied on. */
|
/** The column the filter will be applied on. */
|
||||||
@Input()
|
@Input()
|
||||||
col: DataColumn;
|
col: DataColumn;
|
||||||
@@ -69,14 +57,15 @@ export class SearchFilterContainerComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
private onDestroy$ = new Subject<boolean>();
|
private onDestroy$ = new Subject<boolean>();
|
||||||
|
|
||||||
constructor(@Inject(SEARCH_QUERY_SERVICE_TOKEN) private searchFilterQueryBuilder: SearchHeaderQueryBuilderService,
|
constructor(
|
||||||
|
@Inject(SEARCH_QUERY_SERVICE_TOKEN) private searchFilterQueryBuilder: SearchHeaderQueryBuilderService,
|
||||||
private translationService: TranslationService,
|
private translationService: TranslationService,
|
||||||
private focusTrapFactory: ConfigurableFocusTrapFactory) {
|
private focusTrapFactory: ConfigurableFocusTrapFactory
|
||||||
}
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.category = this.searchFilterQueryBuilder.getCategoryForColumn(this.col.key);
|
this.category = this.searchFilterQueryBuilder.getCategoryForColumn(this.col.key);
|
||||||
this.initialValue = this.value && this.value[this.col.key] ? this.value[this.col.key] : undefined;
|
this.initialValue = this.value?.[this.col.key] ? this.value[this.col.key] : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
|
|||||||
+7
-6
@@ -30,7 +30,6 @@ import { SearchFacetFiltersService } from '../../services/search-facet-filters.s
|
|||||||
host: { class: 'adf-search-filter' }
|
host: { class: 'adf-search-filter' }
|
||||||
})
|
})
|
||||||
export class SearchFilterComponent {
|
export class SearchFilterComponent {
|
||||||
|
|
||||||
/** Toggles whether to show or not the context facet filters. */
|
/** Toggles whether to show or not the context facet filters. */
|
||||||
@Input()
|
@Input()
|
||||||
showContextFacets: boolean = true;
|
showContextFacets: boolean = true;
|
||||||
@@ -41,16 +40,18 @@ export class SearchFilterComponent {
|
|||||||
};
|
};
|
||||||
displayResetButton: boolean;
|
displayResetButton: boolean;
|
||||||
|
|
||||||
constructor(@Inject(SEARCH_QUERY_SERVICE_TOKEN) public queryBuilder: SearchQueryBuilderService,
|
constructor(
|
||||||
public facetFiltersService: SearchFacetFiltersService) {
|
@Inject(SEARCH_QUERY_SERVICE_TOKEN) public queryBuilder: SearchQueryBuilderService,
|
||||||
if (queryBuilder.config && queryBuilder.config.facetQueries) {
|
public facetFiltersService: SearchFacetFiltersService
|
||||||
|
) {
|
||||||
|
if (queryBuilder.config?.facetQueries) {
|
||||||
this.facetQueriesLabel = queryBuilder.config.facetQueries.label || 'Facet Queries';
|
this.facetQueriesLabel = queryBuilder.config.facetQueries.label || 'Facet Queries';
|
||||||
this.facetExpanded['query'] = queryBuilder.config.facetQueries.expanded;
|
this.facetExpanded['query'] = queryBuilder.config.facetQueries.expanded;
|
||||||
}
|
}
|
||||||
if (queryBuilder.config && queryBuilder.config.facetFields) {
|
if (queryBuilder.config?.facetFields) {
|
||||||
this.facetExpanded['field'] = queryBuilder.config.facetFields.expanded;
|
this.facetExpanded['field'] = queryBuilder.config.facetFields.expanded;
|
||||||
}
|
}
|
||||||
if (queryBuilder.config && queryBuilder.config.facetIntervals) {
|
if (queryBuilder.config?.facetIntervals) {
|
||||||
this.facetExpanded['interval'] = queryBuilder.config.facetIntervals.expanded;
|
this.facetExpanded['interval'] = queryBuilder.config.facetIntervals.expanded;
|
||||||
}
|
}
|
||||||
this.displayResetButton = this.queryBuilder.config && !!this.queryBuilder.config.resetButton;
|
this.displayResetButton = this.queryBuilder.config && !!this.queryBuilder.config.resetButton;
|
||||||
|
|||||||
+5
-6
@@ -38,7 +38,6 @@ import { Observable } from 'rxjs';
|
|||||||
template: '<div #content></div>'
|
template: '<div #content></div>'
|
||||||
})
|
})
|
||||||
export class SearchWidgetContainerComponent implements OnInit, OnDestroy, OnChanges {
|
export class SearchWidgetContainerComponent implements OnInit, OnDestroy, OnChanges {
|
||||||
|
|
||||||
@ViewChild('content', { read: ViewContainerRef, static: true })
|
@ViewChild('content', { read: ViewContainerRef, static: true })
|
||||||
content: ViewContainerRef;
|
content: ViewContainerRef;
|
||||||
|
|
||||||
@@ -62,8 +61,8 @@ export class SearchWidgetContainerComponent implements OnInit, OnDestroy, OnChan
|
|||||||
constructor(
|
constructor(
|
||||||
private searchFilterService: SearchFilterService,
|
private searchFilterService: SearchFilterService,
|
||||||
@Inject(SEARCH_QUERY_SERVICE_TOKEN) private queryBuilder: BaseQueryBuilderService,
|
@Inject(SEARCH_QUERY_SERVICE_TOKEN) private queryBuilder: BaseQueryBuilderService,
|
||||||
private componentFactoryResolver: ComponentFactoryResolver) {
|
private componentFactoryResolver: ComponentFactoryResolver
|
||||||
}
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
const componentType = this.searchFilterService.widgets[this.selector];
|
const componentType = this.searchFilterService.widgets[this.selector];
|
||||||
@@ -85,9 +84,9 @@ export class SearchWidgetContainerComponent implements OnInit, OnDestroy, OnChan
|
|||||||
}
|
}
|
||||||
|
|
||||||
private setupWidget(ref: ComponentRef<any>) {
|
private setupWidget(ref: ComponentRef<any>) {
|
||||||
if (ref && ref.instance) {
|
if (ref?.instance) {
|
||||||
ref.instance.id = this.id;
|
ref.instance.id = this.id;
|
||||||
ref.instance.settings = {...this.settings};
|
ref.instance.settings = { ...this.settings };
|
||||||
ref.instance.context = this.queryBuilder;
|
ref.instance.context = this.queryBuilder;
|
||||||
if (this.value) {
|
if (this.value) {
|
||||||
ref.instance.isActive = true;
|
ref.instance.isActive = true;
|
||||||
@@ -128,7 +127,7 @@ export class SearchWidgetContainerComponent implements OnInit, OnDestroy, OnChan
|
|||||||
}
|
}
|
||||||
|
|
||||||
resetInnerWidget() {
|
resetInnerWidget() {
|
||||||
if (this.componentRef && this.componentRef.instance) {
|
if (this.componentRef?.instance) {
|
||||||
this.componentRef.instance.reset();
|
this.componentRef.instance.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,8 @@ import {
|
|||||||
TemplateRef,
|
TemplateRef,
|
||||||
ViewChild,
|
ViewChild,
|
||||||
ViewEncapsulation,
|
ViewEncapsulation,
|
||||||
OnDestroy
|
OnDestroy,
|
||||||
|
SimpleChanges
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { NodePaging, ResultSetPaging } from '@alfresco/js-api';
|
import { NodePaging, ResultSetPaging } from '@alfresco/js-api';
|
||||||
import { Subject } from 'rxjs';
|
import { Subject } from 'rxjs';
|
||||||
@@ -45,7 +46,6 @@ import { SearchComponentInterface } from '@alfresco/adf-core';
|
|||||||
host: { class: 'adf-search' }
|
host: { class: 'adf-search' }
|
||||||
})
|
})
|
||||||
export class SearchComponent implements SearchComponentInterface, AfterContentInit, OnChanges, OnDestroy {
|
export class SearchComponent implements SearchComponentInterface, AfterContentInit, OnChanges, OnDestroy {
|
||||||
|
|
||||||
@ViewChild('panel', { static: true })
|
@ViewChild('panel', { static: true })
|
||||||
panel: ElementRef;
|
panel: ElementRef;
|
||||||
|
|
||||||
@@ -74,8 +74,8 @@ export class SearchComponent implements SearchComponentInterface, AfterContentIn
|
|||||||
// eslint-disable-next-line @angular-eslint/no-input-rename
|
// eslint-disable-next-line @angular-eslint/no-input-rename
|
||||||
@Input('class')
|
@Input('class')
|
||||||
set classList(classList: string) {
|
set classList(classList: string) {
|
||||||
if (classList && classList.length) {
|
if (classList?.length) {
|
||||||
classList.split(' ').forEach((className) => this._classList[className.trim()] = true);
|
classList.split(' ').forEach((className) => (this._classList[className.trim()] = true));
|
||||||
this._elementRef.nativeElement.className = '';
|
this._elementRef.nativeElement.className = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -104,22 +104,14 @@ export class SearchComponent implements SearchComponentInterface, AfterContentIn
|
|||||||
_classList: { [key: string]: boolean } = {};
|
_classList: { [key: string]: boolean } = {};
|
||||||
private onDestroy$ = new Subject<boolean>();
|
private onDestroy$ = new Subject<boolean>();
|
||||||
|
|
||||||
constructor(private searchService: SearchService,
|
constructor(private searchService: SearchService, private _elementRef: ElementRef) {
|
||||||
private _elementRef: ElementRef) {
|
this.keyPressedStream.pipe(debounceTime(200), takeUntil(this.onDestroy$)).subscribe((searchedWord) => {
|
||||||
this.keyPressedStream
|
|
||||||
.pipe(
|
|
||||||
debounceTime(200),
|
|
||||||
takeUntil(this.onDestroy$)
|
|
||||||
)
|
|
||||||
.subscribe(searchedWord => {
|
|
||||||
this.loadSearchResults(searchedWord);
|
this.loadSearchResults(searchedWord);
|
||||||
});
|
});
|
||||||
|
|
||||||
searchService.dataLoaded
|
searchService.dataLoaded.pipe(takeUntil(this.onDestroy$)).subscribe(
|
||||||
.pipe(takeUntil(this.onDestroy$))
|
(nodePaging) => this.onSearchDataLoaded(nodePaging),
|
||||||
.subscribe(
|
(error) => this.onSearchDataError(error)
|
||||||
nodePaging => this.onSearchDataLoaded(nodePaging),
|
|
||||||
error => this.onSearchDataError(error)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,8 +119,8 @@ export class SearchComponent implements SearchComponentInterface, AfterContentIn
|
|||||||
this.setVisibility();
|
this.setVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnChanges(changes) {
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
if (changes.searchTerm && changes.searchTerm.currentValue) {
|
if (changes.searchTerm?.currentValue) {
|
||||||
this.loadSearchResults(changes.searchTerm.currentValue);
|
this.loadSearchResults(changes.searchTerm.currentValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -174,8 +166,8 @@ export class SearchComponent implements SearchComponentInterface, AfterContentIn
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onSearchDataError(error) {
|
onSearchDataError(error: { status: number }) {
|
||||||
if (error && error.status !== 400) {
|
if (error?.status !== 400) {
|
||||||
this.results = null;
|
this.results = null;
|
||||||
this.error.emit(error);
|
this.error.emit(error);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,10 +19,8 @@ import { ErrorStateMatcher } from '@angular/material/core';
|
|||||||
import { UntypedFormControl, FormGroupDirective, NgForm } from '@angular/forms';
|
import { UntypedFormControl, FormGroupDirective, NgForm } from '@angular/forms';
|
||||||
|
|
||||||
export class LiveErrorStateMatcher implements ErrorStateMatcher {
|
export class LiveErrorStateMatcher implements ErrorStateMatcher {
|
||||||
|
|
||||||
isErrorState(control: UntypedFormControl | null, form: FormGroupDirective | NgForm | null): boolean {
|
isErrorState(control: UntypedFormControl | null, form: FormGroupDirective | NgForm | null): boolean {
|
||||||
const isSubmitted = form && form.submitted;
|
const isSubmitted = form?.submitted;
|
||||||
return !!(control && control.invalid && (control.dirty || control.touched || (!control.pristine && isSubmitted)));
|
return !!(control?.invalid && (control.dirty || control.touched || (!control.pristine && isSubmitted)));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ export abstract class BaseQueryBuilderService {
|
|||||||
// TODO: to be supported in future iterations
|
// TODO: to be supported in future iterations
|
||||||
ranges: { [id: string]: SearchRange } = {};
|
ranges: { [id: string]: SearchRange } = {};
|
||||||
|
|
||||||
constructor(protected appConfig: AppConfigService, protected alfrescoApiService: AlfrescoApiService) {
|
protected constructor(protected appConfig: AppConfigService, protected alfrescoApiService: AlfrescoApiService) {
|
||||||
this.resetToDefaults();
|
this.resetToDefaults();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -374,7 +374,7 @@ export abstract class BaseQueryBuilderService {
|
|||||||
* @returns The primary sorting definition
|
* @returns The primary sorting definition
|
||||||
*/
|
*/
|
||||||
getPrimarySorting(): SearchSortingDefinition {
|
getPrimarySorting(): SearchSortingDefinition {
|
||||||
if (this.sorting && this.sorting.length > 0) {
|
if (this.sorting?.length > 0) {
|
||||||
return this.sorting[0];
|
return this.sorting[0];
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@@ -386,10 +386,7 @@ export abstract class BaseQueryBuilderService {
|
|||||||
* @returns Pre-configured sorting options
|
* @returns Pre-configured sorting options
|
||||||
*/
|
*/
|
||||||
getSortingOptions(): SearchSortingDefinition[] {
|
getSortingOptions(): SearchSortingDefinition[] {
|
||||||
if (this.config && this.config.sorting) {
|
return this.config?.sorting?.options || [];
|
||||||
return this.config.sorting.options || [];
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -398,7 +395,7 @@ export abstract class BaseQueryBuilderService {
|
|||||||
* @param query Target query
|
* @param query Target query
|
||||||
* @returns Query group
|
* @returns Query group
|
||||||
*/
|
*/
|
||||||
getQueryGroup(query) {
|
getQueryGroup(query: FacetQuery): string {
|
||||||
return query.group || this.config.facetQueries.label || 'Facet Queries';
|
return query.group || this.config.facetQueries.label || 'Facet Queries';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -408,10 +405,7 @@ export abstract class BaseQueryBuilderService {
|
|||||||
* @returns True if defined, false otherwise
|
* @returns True if defined, false otherwise
|
||||||
*/
|
*/
|
||||||
get hasFacetQueries(): boolean {
|
get hasFacetQueries(): boolean {
|
||||||
if (this.config && this.config.facetQueries && this.config.facetQueries.queries && this.config.facetQueries.queries.length > 0) {
|
return this.config?.facetQueries?.queries?.length > 0;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -420,11 +414,11 @@ export abstract class BaseQueryBuilderService {
|
|||||||
* @returns True if defined, false otherwise
|
* @returns True if defined, false otherwise
|
||||||
*/
|
*/
|
||||||
get hasFacetIntervals(): boolean {
|
get hasFacetIntervals(): boolean {
|
||||||
return this.config && this.config.facetIntervals && this.config.facetIntervals.intervals && this.config.facetIntervals.intervals.length > 0;
|
return this.config?.facetIntervals?.intervals?.length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
get hasFacetHighlight(): boolean {
|
get hasFacetHighlight(): boolean {
|
||||||
return !!(this.config && this.config.highlight);
|
return !!this.config?.highlight;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected get sort(): RequestSortDefinitionInner[] {
|
protected get sort(): RequestSortDefinitionInner[] {
|
||||||
@@ -515,9 +509,9 @@ export abstract class BaseQueryBuilderService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected get facetFields(): RequestFacetFields {
|
protected get facetFields(): RequestFacetFields {
|
||||||
const facetFields = this.config.facetFields && this.config.facetFields.fields;
|
const facetFields = this.config.facetFields?.fields;
|
||||||
|
|
||||||
if (facetFields && facetFields.length > 0) {
|
if (facetFields?.length > 0) {
|
||||||
return {
|
return {
|
||||||
facets: facetFields.map(
|
facets: facetFields.map(
|
||||||
(facet) =>
|
(facet) =>
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ const DEFAULT_PAGE_SIZE: number = 5;
|
|||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class SearchFacetFiltersService implements OnDestroy {
|
export class SearchFacetFiltersService implements OnDestroy {
|
||||||
|
|
||||||
/** All facet field items to be displayed in the component. These are updated according to the response.
|
/** All facet field items to be displayed in the component. These are updated according to the response.
|
||||||
* When a new search is performed, the already existing items are updated with the new bucket count values and
|
* When a new search is performed, the already existing items are updated with the new bucket count values and
|
||||||
* the newly received items are added to the responseFacets.
|
* the newly received items are added to the responseFacets.
|
||||||
@@ -55,29 +54,24 @@ export class SearchFacetFiltersService implements OnDestroy {
|
|||||||
private readonly facetQueriesPageSize = DEFAULT_PAGE_SIZE;
|
private readonly facetQueriesPageSize = DEFAULT_PAGE_SIZE;
|
||||||
private readonly onDestroy$ = new Subject<boolean>();
|
private readonly onDestroy$ = new Subject<boolean>();
|
||||||
|
|
||||||
constructor(@Inject(SEARCH_QUERY_SERVICE_TOKEN) public queryBuilder: SearchQueryBuilderService,
|
constructor(
|
||||||
|
@Inject(SEARCH_QUERY_SERVICE_TOKEN) public queryBuilder: SearchQueryBuilderService,
|
||||||
private searchService: SearchService,
|
private searchService: SearchService,
|
||||||
private translationService: TranslationService,
|
private translationService: TranslationService,
|
||||||
private categoryService: CategoryService
|
private categoryService: CategoryService
|
||||||
) {
|
) {
|
||||||
if (queryBuilder.config && queryBuilder.config.facetQueries) {
|
if (queryBuilder.config?.facetQueries) {
|
||||||
this.facetQueriesPageSize = queryBuilder.config.facetQueries.pageSize || DEFAULT_PAGE_SIZE;
|
this.facetQueriesPageSize = queryBuilder.config.facetQueries.pageSize || DEFAULT_PAGE_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.queryBuilder.configUpdated
|
this.queryBuilder.configUpdated.pipe(takeUntil(this.onDestroy$)).subscribe(() => {
|
||||||
.pipe(takeUntil(this.onDestroy$))
|
|
||||||
.subscribe(() => {
|
|
||||||
this.selectedBuckets = [];
|
this.selectedBuckets = [];
|
||||||
this.responseFacets = null;
|
this.responseFacets = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
this.queryBuilder.updated
|
this.queryBuilder.updated.pipe(takeUntil(this.onDestroy$)).subscribe((query) => this.queryBuilder.execute(query));
|
||||||
.pipe(takeUntil(this.onDestroy$))
|
|
||||||
.subscribe((query) => this.queryBuilder.execute(query));
|
|
||||||
|
|
||||||
this.queryBuilder.executed
|
this.queryBuilder.executed.pipe(takeUntil(this.onDestroy$)).subscribe((resultSetPaging: ResultSetPaging) => {
|
||||||
.pipe(takeUntil(this.onDestroy$))
|
|
||||||
.subscribe((resultSetPaging: ResultSetPaging) => {
|
|
||||||
this.onDataLoaded(resultSetPaging);
|
this.onDataLoaded(resultSetPaging);
|
||||||
this.searchService.dataLoaded.next(resultSetPaging);
|
this.searchService.dataLoaded.next(resultSetPaging);
|
||||||
});
|
});
|
||||||
@@ -104,17 +98,20 @@ export class SearchFacetFiltersService implements OnDestroy {
|
|||||||
private parseFacetItems(context: ResultSetContext, configFacetFields: FacetField[], itemType: string) {
|
private parseFacetItems(context: ResultSetContext, configFacetFields: FacetField[], itemType: string) {
|
||||||
configFacetFields.forEach((facetField) => {
|
configFacetFields.forEach((facetField) => {
|
||||||
const responseField = this.findFacet(context, itemType, facetField.label);
|
const responseField = this.findFacet(context, itemType, facetField.label);
|
||||||
const responseBuckets = this.getResponseBuckets(responseField, facetField)
|
const responseBuckets = this.getResponseBuckets(responseField, facetField).filter(this.getFilterByMinCount(facetField.mincount));
|
||||||
.filter(this.getFilterByMinCount(facetField.mincount));
|
this.sortFacetBuckets(
|
||||||
this.sortFacetBuckets(responseBuckets, facetField.settings?.bucketSortBy, facetField.settings?.bucketSortDirection ?? FacetBucketSortDirection.ASCENDING);
|
responseBuckets,
|
||||||
|
facetField.settings?.bucketSortBy,
|
||||||
|
facetField.settings?.bucketSortDirection ?? FacetBucketSortDirection.ASCENDING
|
||||||
|
);
|
||||||
const alreadyExistingField = this.findResponseFacet(itemType, facetField.label);
|
const alreadyExistingField = this.findResponseFacet(itemType, facetField.label);
|
||||||
|
|
||||||
if (facetField.field === 'cm:categories'){
|
if (facetField.field === 'cm:categories') {
|
||||||
this.loadCategoryNames(responseBuckets);
|
this.loadCategoryNames(responseBuckets);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (alreadyExistingField) {
|
if (alreadyExistingField) {
|
||||||
const alreadyExistingBuckets = alreadyExistingField.buckets && alreadyExistingField.buckets.items || [];
|
const alreadyExistingBuckets = alreadyExistingField.buckets?.items || [];
|
||||||
|
|
||||||
this.updateExistingBuckets(responseField, responseBuckets, alreadyExistingField, alreadyExistingBuckets);
|
this.updateExistingBuckets(responseField, responseBuckets, alreadyExistingField, alreadyExistingBuckets);
|
||||||
} else if (responseField) {
|
} else if (responseField) {
|
||||||
@@ -166,18 +163,18 @@ export class SearchFacetFiltersService implements OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private parseFacetFields(context: ResultSetContext) {
|
private parseFacetFields(context: ResultSetContext) {
|
||||||
const configFacetFields = this.queryBuilder.config.facetFields && this.queryBuilder.config.facetFields.fields || [];
|
const configFacetFields = this.queryBuilder.config.facetFields?.fields || [];
|
||||||
this.parseFacetItems(context, configFacetFields, 'field');
|
this.parseFacetItems(context, configFacetFields, 'field');
|
||||||
}
|
}
|
||||||
|
|
||||||
private parseFacetIntervals(context: ResultSetContext) {
|
private parseFacetIntervals(context: ResultSetContext) {
|
||||||
const configFacetIntervals = this.queryBuilder.config.facetIntervals && this.queryBuilder.config.facetIntervals.intervals || [];
|
const configFacetIntervals = this.queryBuilder.config.facetIntervals?.intervals || [];
|
||||||
this.parseFacetItems(context, configFacetIntervals, 'interval');
|
this.parseFacetItems(context, configFacetIntervals, 'interval');
|
||||||
}
|
}
|
||||||
|
|
||||||
private parseFacetQueries(context: ResultSetContext) {
|
private parseFacetQueries(context: ResultSetContext) {
|
||||||
const facetQuerySetting = this.queryBuilder.config.facetQueries?.settings || {};
|
const facetQuerySetting = this.queryBuilder.config.facetQueries?.settings || {};
|
||||||
const configFacetQueries = this.queryBuilder.config.facetQueries && this.queryBuilder.config.facetQueries.queries || [];
|
const configFacetQueries = this.queryBuilder.config.facetQueries?.queries || [];
|
||||||
const configGroups = configFacetQueries.reduce((acc, query) => {
|
const configGroups = configFacetQueries.reduce((acc, query) => {
|
||||||
const group = this.queryBuilder.getQueryGroup(query);
|
const group = this.queryBuilder.getQueryGroup(query);
|
||||||
if (acc[group]) {
|
if (acc[group]) {
|
||||||
@@ -188,18 +185,21 @@ export class SearchFacetFiltersService implements OnDestroy {
|
|||||||
return acc;
|
return acc;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const mincount = this.queryBuilder.config.facetQueries && this.queryBuilder.config.facetQueries.mincount;
|
const minCount = this.queryBuilder.config.facetQueries?.mincount;
|
||||||
const mincountFilter = this.getFilterByMinCount(mincount);
|
const minCountFilter = this.getFilterByMinCount(minCount);
|
||||||
|
|
||||||
Object.keys(configGroups).forEach((group) => {
|
Object.keys(configGroups).forEach((group) => {
|
||||||
const responseField = this.findFacet(context, 'query', group);
|
const responseField = this.findFacet(context, 'query', group);
|
||||||
const responseBuckets = this.getResponseQueryBuckets(responseField, configGroups[group])
|
const responseBuckets = this.getResponseQueryBuckets(responseField, configGroups[group]).filter(minCountFilter);
|
||||||
.filter(mincountFilter);
|
this.sortFacetBuckets(
|
||||||
this.sortFacetBuckets(responseBuckets, facetQuerySetting?.bucketSortBy, facetQuerySetting.bucketSortDirection ?? FacetBucketSortDirection.ASCENDING);
|
responseBuckets,
|
||||||
|
facetQuerySetting?.bucketSortBy,
|
||||||
|
facetQuerySetting.bucketSortDirection ?? FacetBucketSortDirection.ASCENDING
|
||||||
|
);
|
||||||
const alreadyExistingField = this.findResponseFacet('query', group);
|
const alreadyExistingField = this.findResponseFacet('query', group);
|
||||||
|
|
||||||
if (alreadyExistingField) {
|
if (alreadyExistingField) {
|
||||||
const alreadyExistingBuckets = alreadyExistingField.buckets && alreadyExistingField.buckets.items || [];
|
const alreadyExistingBuckets = alreadyExistingField.buckets?.items || [];
|
||||||
|
|
||||||
this.updateExistingBuckets(responseField, responseBuckets, alreadyExistingField, alreadyExistingBuckets);
|
this.updateExistingBuckets(responseField, responseBuckets, alreadyExistingField, alreadyExistingBuckets);
|
||||||
} else if (responseField) {
|
} else if (responseField) {
|
||||||
@@ -229,8 +229,7 @@ export class SearchFacetFiltersService implements OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getResponseBuckets(responseField: GenericFacetResponse, configField: FacetField): FacetFieldBucket[] {
|
private getResponseBuckets(responseField: GenericFacetResponse, configField: FacetField): FacetFieldBucket[] {
|
||||||
return ((responseField && responseField.buckets) || []).map((respBucket) => {
|
return (responseField?.buckets || []).map((respBucket) => {
|
||||||
|
|
||||||
respBucket['count'] = this.getCountValue(respBucket);
|
respBucket['count'] = this.getCountValue(respBucket);
|
||||||
respBucket.filterQuery = respBucket.filterQuery || this.getCorrespondingFilterQuery(configField, respBucket.label);
|
respBucket.filterQuery = respBucket.filterQuery || this.getCorrespondingFilterQuery(configField, respBucket.label);
|
||||||
return {
|
return {
|
||||||
@@ -244,8 +243,7 @@ export class SearchFacetFiltersService implements OnDestroy {
|
|||||||
|
|
||||||
private getResponseQueryBuckets(responseField: GenericFacetResponse, configGroup: any): FacetFieldBucket[] {
|
private getResponseQueryBuckets(responseField: GenericFacetResponse, configGroup: any): FacetFieldBucket[] {
|
||||||
return (configGroup || []).map((query) => {
|
return (configGroup || []).map((query) => {
|
||||||
const respBucket = ((responseField && responseField.buckets) || [])
|
const respBucket = (responseField?.buckets || []).find((bucket) => bucket.label === query.label) || {};
|
||||||
.find((bucket) => bucket.label === query.label) || {};
|
|
||||||
|
|
||||||
respBucket['count'] = this.getCountValue(respBucket);
|
respBucket['count'] = this.getCountValue(respBucket);
|
||||||
return {
|
return {
|
||||||
@@ -261,7 +259,9 @@ export class SearchFacetFiltersService implements OnDestroy {
|
|||||||
switch (sortBy) {
|
switch (sortBy) {
|
||||||
case FacetBucketSortBy.LABEL:
|
case FacetBucketSortBy.LABEL:
|
||||||
buckets.sort((bucket1, bucket2) =>
|
buckets.sort((bucket1, bucket2) =>
|
||||||
sortDirection === FacetBucketSortDirection.ASCENDING ? bucket1.label.localeCompare(bucket2.label) : bucket2.label.localeCompare(bucket1.label)
|
sortDirection === FacetBucketSortDirection.ASCENDING
|
||||||
|
? bucket1.label.localeCompare(bucket2.label)
|
||||||
|
: bucket2.label.localeCompare(bucket1.label)
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case FacetBucketSortBy.COUNT:
|
case FacetBucketSortBy.COUNT:
|
||||||
@@ -282,28 +282,26 @@ export class SearchFacetFiltersService implements OnDestroy {
|
|||||||
return bucket.count === null ? '' : `(${bucket.count})`;
|
return bucket.count === null ? '' : `(${bucket.count})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getFilterByMinCount(mincountInput: number) {
|
private getFilterByMinCount =
|
||||||
return (bucket) => {
|
(minCountInput: number) =>
|
||||||
let mincount = mincountInput;
|
(bucket: FacetFieldBucket): boolean => {
|
||||||
if (mincount === undefined) {
|
let minCount = minCountInput;
|
||||||
mincount = 1;
|
if (minCount === undefined) {
|
||||||
|
minCount = 1;
|
||||||
}
|
}
|
||||||
return bucket.count >= mincount;
|
return bucket.count >= minCount;
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
private getCorrespondingFilterQuery(configFacetItem: FacetField, bucketLabel: string): string {
|
private getCorrespondingFilterQuery(configFacetItem: FacetField, bucketLabel: string): string {
|
||||||
let filterQuery = null;
|
let filterQuery = null;
|
||||||
|
|
||||||
if (configFacetItem.field && bucketLabel) {
|
if (configFacetItem.field && bucketLabel) {
|
||||||
|
|
||||||
if (configFacetItem.sets) {
|
if (configFacetItem.sets) {
|
||||||
const configSet = configFacetItem.sets.find((set) => bucketLabel === set.label);
|
const configSet = configFacetItem.sets.find((set) => bucketLabel === set.label);
|
||||||
|
|
||||||
if (configSet) {
|
if (configSet) {
|
||||||
filterQuery = this.buildIntervalQuery(configFacetItem.field, configSet);
|
filterQuery = this.buildIntervalQuery(configFacetItem.field, configSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
filterQuery = `${configFacetItem.field}:"${bucketLabel}"`;
|
filterQuery = `${configFacetItem.field}:"${bucketLabel}"`;
|
||||||
}
|
}
|
||||||
@@ -315,8 +313,8 @@ export class SearchFacetFiltersService implements OnDestroy {
|
|||||||
private buildIntervalQuery(fieldName: string, interval: any): string {
|
private buildIntervalQuery(fieldName: string, interval: any): string {
|
||||||
const start = interval.start;
|
const start = interval.start;
|
||||||
const end = interval.end;
|
const end = interval.end;
|
||||||
const startLimit = (interval.startInclusive === undefined || interval.startInclusive === true) ? '[' : '<';
|
const startLimit = interval.startInclusive === undefined || interval.startInclusive === true ? '[' : '<';
|
||||||
const endLimit = (interval.endInclusive === undefined || interval.endInclusive === true) ? ']' : '>';
|
const endLimit = interval.endInclusive === undefined || interval.endInclusive === true ? ']' : '>';
|
||||||
|
|
||||||
return `${fieldName}:${startLimit}"${start}" TO "${end}"${endLimit}`;
|
return `${fieldName}:${startLimit}"${start}" TO "${end}"${endLimit}`;
|
||||||
}
|
}
|
||||||
@@ -329,12 +327,16 @@ export class SearchFacetFiltersService implements OnDestroy {
|
|||||||
return (this.responseFacets || []).find((response) => response.type === itemType && response.label === fieldLabel);
|
return (this.responseFacets || []).find((response) => response.type === itemType && response.label === fieldLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateExistingBuckets(responseField, responseBuckets, alreadyExistingField, alreadyExistingBuckets) {
|
private updateExistingBuckets(
|
||||||
|
responseField: GenericFacetResponse,
|
||||||
|
responseBuckets: FacetFieldBucket[],
|
||||||
|
alreadyExistingField: FacetField,
|
||||||
|
alreadyExistingBuckets: FacetFieldBucket[]
|
||||||
|
) {
|
||||||
const bucketsToDelete = [];
|
const bucketsToDelete = [];
|
||||||
|
|
||||||
alreadyExistingBuckets
|
alreadyExistingBuckets.forEach((bucket) => {
|
||||||
.map((bucket) => {
|
const responseBucket = (responseField?.buckets || []).find((respBucket) => respBucket.label === bucket.label);
|
||||||
const responseBucket = ((responseField && responseField.buckets) || []).find((respBucket) => respBucket.label === bucket.label);
|
|
||||||
|
|
||||||
if (!responseBucket) {
|
if (!responseBucket) {
|
||||||
bucketsToDelete.push(bucket);
|
bucketsToDelete.push(bucket);
|
||||||
@@ -343,8 +345,9 @@ export class SearchFacetFiltersService implements OnDestroy {
|
|||||||
return bucket;
|
return bucket;
|
||||||
});
|
});
|
||||||
|
|
||||||
const hasSelection = this.selectedBuckets
|
const hasSelection = !!this.selectedBuckets.find(
|
||||||
.find((selBuckets) => alreadyExistingField.label === selBuckets.field.label && alreadyExistingField.type === selBuckets.field.type);
|
(selBuckets) => alreadyExistingField.label === selBuckets.field.label && alreadyExistingField.type === selBuckets.field.type
|
||||||
|
);
|
||||||
|
|
||||||
if (!hasSelection && bucketsToDelete.length) {
|
if (!hasSelection && bucketsToDelete.length) {
|
||||||
bucketsToDelete.forEach((bucket) => {
|
bucketsToDelete.forEach((bucket) => {
|
||||||
@@ -361,8 +364,9 @@ export class SearchFacetFiltersService implements OnDestroy {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private getBucketFilterFunction(bucketList) {
|
private getBucketFilterFunction =
|
||||||
return (bucket: FacetFieldBucket): boolean => {
|
(bucketList: SearchFilterList<FacetFieldBucket>) =>
|
||||||
|
(bucket: FacetFieldBucket): boolean => {
|
||||||
if (bucket && bucketList.filterText) {
|
if (bucket && bucketList.filterText) {
|
||||||
const pattern = (bucketList.filterText || '').toLowerCase();
|
const pattern = (bucketList.filterText || '').toLowerCase();
|
||||||
const label = (this.translationService.instant(bucket.display) || this.translationService.instant(bucket.label)).toLowerCase();
|
const label = (this.translationService.instant(bucket.display) || this.translationService.instant(bucket.label)).toLowerCase();
|
||||||
@@ -370,21 +374,19 @@ export class SearchFacetFiltersService implements OnDestroy {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
private loadCategoryNames(bucketList: FacetFieldBucket[]) {
|
private loadCategoryNames(bucketList: FacetFieldBucket[]) {
|
||||||
bucketList.forEach((item) => {
|
bucketList.forEach((item) => {
|
||||||
const categoryId = item.label.split('/').pop();
|
const categoryId = item.label.split('/').pop();
|
||||||
this.categoryService.getCategory(categoryId, {include: ['path']})
|
this.categoryService
|
||||||
.pipe(catchError(error => throwError(error)))
|
.getCategory(categoryId, { include: ['path'] })
|
||||||
.subscribe(
|
.pipe(catchError((error) => throwError(error)))
|
||||||
category => {
|
.subscribe((category) => {
|
||||||
const nextAfterGeneralPathPartIndex = 3;
|
const nextAfterGeneralPathPartIndex = 3;
|
||||||
const pathSeparator = '/';
|
const pathSeparator = '/';
|
||||||
const path = category.entry.path.split(pathSeparator).slice(nextAfterGeneralPathPartIndex).join('/');
|
const path = category.entry.path.split(pathSeparator).slice(nextAfterGeneralPathPartIndex).join('/');
|
||||||
item.display = path ? `${path}/${category.entry.name}` : category.entry.name;
|
item.display = path ? `${path}/${category.entry.name}` : category.entry.name;
|
||||||
}
|
});
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -401,14 +403,15 @@ export class SearchFacetFiltersService implements OnDestroy {
|
|||||||
updateSelectedBuckets() {
|
updateSelectedBuckets() {
|
||||||
if (this.responseFacets) {
|
if (this.responseFacets) {
|
||||||
this.selectedBuckets = [];
|
this.selectedBuckets = [];
|
||||||
let facetFields = this.tabbedFacet === null ? [] : Object.keys(this.tabbedFacet?.fields).map(field => this.tabbedFacet.facets[field]);
|
let facetFields = this.tabbedFacet === null ? [] : Object.keys(this.tabbedFacet?.fields).map((field) => this.tabbedFacet.facets[field]);
|
||||||
facetFields = [...facetFields, ...this.responseFacets];
|
facetFields = [...facetFields, ...this.responseFacets];
|
||||||
for (const facetField of facetFields) {
|
for (const facetField of facetFields) {
|
||||||
if (facetField?.buckets) {
|
if (facetField?.buckets) {
|
||||||
this.selectedBuckets.push(
|
this.selectedBuckets.push(
|
||||||
...this.queryBuilder.getUserFacetBuckets(facetField.field)
|
...this.queryBuilder
|
||||||
|
.getUserFacetBuckets(facetField.field)
|
||||||
.filter((bucket) => bucket.checked)
|
.filter((bucket) => bucket.checked)
|
||||||
.map((bucket) => ({field: facetField, bucket}))
|
.map((bucket) => ({ field: facetField, bucket }))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } fro
|
|||||||
import { LogService, InfiniteSelectScrollDirective, AuthenticationService } from '@alfresco/adf-core';
|
import { LogService, InfiniteSelectScrollDirective, AuthenticationService } from '@alfresco/adf-core';
|
||||||
import { SitePaging, SiteEntry, Site } from '@alfresco/js-api';
|
import { SitePaging, SiteEntry, Site } from '@alfresco/js-api';
|
||||||
import { MatSelectChange } from '@angular/material/select';
|
import { MatSelectChange } from '@angular/material/select';
|
||||||
import {LiveAnnouncer} from '@angular/cdk/a11y';
|
import { LiveAnnouncer } from '@angular/cdk/a11y';
|
||||||
import {TranslateService} from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { SitesService } from '../common/services/sites.service';
|
import { SitesService } from '../common/services/sites.service';
|
||||||
|
|
||||||
/* eslint-disable no-shadow */
|
/* eslint-disable no-shadow */
|
||||||
@@ -39,7 +39,6 @@ export enum Relations {
|
|||||||
host: { class: 'adf-sites-dropdown' }
|
host: { class: 'adf-sites-dropdown' }
|
||||||
})
|
})
|
||||||
export class DropdownSitesComponent implements OnInit {
|
export class DropdownSitesComponent implements OnInit {
|
||||||
|
|
||||||
/** Hide the "My Files" option. */
|
/** Hide the "My Files" option. */
|
||||||
@Input()
|
@Input()
|
||||||
hideMyFiles: boolean = false;
|
hideMyFiles: boolean = false;
|
||||||
@@ -81,12 +80,13 @@ export class DropdownSitesComponent implements OnInit {
|
|||||||
selected: SiteEntry = null;
|
selected: SiteEntry = null;
|
||||||
MY_FILES_VALUE = '-my-';
|
MY_FILES_VALUE = '-my-';
|
||||||
|
|
||||||
constructor(private authService: AuthenticationService,
|
constructor(
|
||||||
|
private authService: AuthenticationService,
|
||||||
private sitesService: SitesService,
|
private sitesService: SitesService,
|
||||||
private logService: LogService,
|
private logService: LogService,
|
||||||
private liveAnnouncer: LiveAnnouncer,
|
private liveAnnouncer: LiveAnnouncer,
|
||||||
private translateService: TranslateService) {
|
private translateService: TranslateService
|
||||||
}
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
if (!this.siteList) {
|
if (!this.siteList) {
|
||||||
@@ -102,10 +102,12 @@ export class DropdownSitesComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
selectedSite(event: MatSelectChange) {
|
selectedSite(event: MatSelectChange) {
|
||||||
this.liveAnnouncer.announce(this.translateService.instant('ADF_DROPDOWN.SELECTION_ARIA_LABEL', {
|
this.liveAnnouncer.announce(
|
||||||
|
this.translateService.instant('ADF_DROPDOWN.SELECTION_ARIA_LABEL', {
|
||||||
placeholder: this.translateService.instant(this.placeholder),
|
placeholder: this.translateService.instant(this.placeholder),
|
||||||
selectedOption: this.translateService.instant(event.value.entry.title)
|
selectedOption: this.translateService.instant(event.value.entry.title)
|
||||||
}));
|
})
|
||||||
|
);
|
||||||
this.change.emit(event.value);
|
this.change.emit(event.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,8 +123,8 @@ export class DropdownSitesComponent implements OnInit {
|
|||||||
extendedOptions.relations = [this.relations];
|
extendedOptions.relations = [this.relations];
|
||||||
}
|
}
|
||||||
|
|
||||||
this.sitesService.getSites(extendedOptions).subscribe((sitePaging: SitePaging) => {
|
this.sitesService.getSites(extendedOptions).subscribe(
|
||||||
|
(sitePaging: SitePaging) => {
|
||||||
if (!this.siteList) {
|
if (!this.siteList) {
|
||||||
this.siteList = this.relations === Relations.Members ? this.filteredResultsByMember(sitePaging) : sitePaging;
|
this.siteList = this.relations === Relations.Members ? this.filteredResultsByMember(sitePaging) : sitePaging;
|
||||||
|
|
||||||
@@ -137,7 +139,6 @@ export class DropdownSitesComponent implements OnInit {
|
|||||||
this.value = this.MY_FILES_VALUE;
|
this.value = this.MY_FILES_VALUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
const siteList: SitePaging = this.relations === Relations.Members ? this.filteredResultsByMember(sitePaging) : sitePaging;
|
const siteList: SitePaging = this.relations === Relations.Members ? this.filteredResultsByMember(sitePaging) : sitePaging;
|
||||||
|
|
||||||
@@ -155,7 +156,8 @@ export class DropdownSitesComponent implements OnInit {
|
|||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.logService.error(error);
|
this.logService.error(error);
|
||||||
});
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
showLoading(): boolean {
|
showLoading(): boolean {
|
||||||
@@ -167,7 +169,7 @@ export class DropdownSitesComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private siteListHasMoreItems(): boolean {
|
private siteListHasMoreItems(): boolean {
|
||||||
return this.siteList && this.siteList.list.pagination && this.siteList.list.pagination.hasMoreItems;
|
return this.siteList?.list.pagination?.hasMoreItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
private filteredResultsByMember(sites: SitePaging): SitePaging {
|
private filteredResultsByMember(sites: SitePaging): SitePaging {
|
||||||
@@ -177,7 +179,9 @@ export class DropdownSitesComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private isCurrentUserMember(site: SiteEntry, loggedUserName: string): boolean {
|
private isCurrentUserMember(site: SiteEntry, loggedUserName: string): boolean {
|
||||||
return site.entry.visibility === 'PUBLIC' ||
|
return (
|
||||||
!!site.relations.members.list.entries.find((member) => member.entry.id.toLowerCase() === loggedUserName.toLowerCase());
|
site.entry.visibility === 'PUBLIC' ||
|
||||||
|
!!site.relations.members.list.entries.find((member) => member.entry.id.toLowerCase() === loggedUserName.toLowerCase())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,9 +27,7 @@ import { NodeEntry } from '@alfresco/js-api';
|
|||||||
templateUrl: './tree-view.component.html',
|
templateUrl: './tree-view.component.html',
|
||||||
styleUrls: ['./tree-view.component.scss']
|
styleUrls: ['./tree-view.component.scss']
|
||||||
})
|
})
|
||||||
|
|
||||||
export class TreeViewComponent implements OnChanges {
|
export class TreeViewComponent implements OnChanges {
|
||||||
|
|
||||||
/** Identifier of the node to display. */
|
/** Identifier of the node to display. */
|
||||||
@Input()
|
@Input()
|
||||||
nodeId: string;
|
nodeId: string;
|
||||||
@@ -51,8 +49,7 @@ export class TreeViewComponent implements OnChanges {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges) {
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
if (changes['nodeId'] && changes['nodeId'].currentValue &&
|
if (changes['nodeId']?.currentValue && changes['nodeId'].currentValue !== changes['nodeId'].previousValue) {
|
||||||
changes['nodeId'].currentValue !== changes['nodeId'].previousValue) {
|
|
||||||
this.loadTreeNode();
|
this.loadTreeNode();
|
||||||
} else {
|
} else {
|
||||||
this.dataSource.data = [];
|
this.dataSource.data = [];
|
||||||
@@ -70,8 +67,7 @@ export class TreeViewComponent implements OnChanges {
|
|||||||
hasChild = (_: number, nodeData: TreeBaseNode) => nodeData.expandable;
|
hasChild = (_: number, nodeData: TreeBaseNode) => nodeData.expandable;
|
||||||
|
|
||||||
private loadTreeNode() {
|
private loadTreeNode() {
|
||||||
this.treeViewService.getTreeNodes(this.nodeId)
|
this.treeViewService.getTreeNodes(this.nodeId).subscribe(
|
||||||
.subscribe(
|
|
||||||
(treeNode: TreeBaseNode[]) => {
|
(treeNode: TreeBaseNode[]) => {
|
||||||
this.dataSource.data = treeNode;
|
this.dataSource.data = treeNode;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -38,7 +38,10 @@ export abstract class TreeService<T extends TreeNode> extends DataSource<T> {
|
|||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.treeControl = new FlatTreeControl<T>(node => node.level, node => node.hasChildren);
|
this.treeControl = new FlatTreeControl<T>(
|
||||||
|
(node) => node.level,
|
||||||
|
(node) => node.hasChildren
|
||||||
|
);
|
||||||
this.treeNodes = [];
|
this.treeNodes = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +69,7 @@ export abstract class TreeService<T extends TreeNode> extends DataSource<T> {
|
|||||||
* @param nodeToCollapse Node to be collapsed
|
* @param nodeToCollapse Node to be collapsed
|
||||||
*/
|
*/
|
||||||
public collapseNode(nodeToCollapse: T): void {
|
public collapseNode(nodeToCollapse: T): void {
|
||||||
if (nodeToCollapse != null && nodeToCollapse.hasChildren) {
|
if (nodeToCollapse?.hasChildren) {
|
||||||
this.treeControl.collapse(nodeToCollapse);
|
this.treeControl.collapse(nodeToCollapse);
|
||||||
const children: T[] = this.treeNodes.filter((node: T) => nodeToCollapse.id === node.parentId);
|
const children: T[] = this.treeNodes.filter((node: T) => nodeToCollapse.id === node.parentId);
|
||||||
children.forEach((child: T) => {
|
children.forEach((child: T) => {
|
||||||
@@ -142,9 +145,7 @@ export abstract class TreeService<T extends TreeNode> extends DataSource<T> {
|
|||||||
const index: number = this.treeNodes.indexOf(nodeToCollapse);
|
const index: number = this.treeNodes.indexOf(nodeToCollapse);
|
||||||
this.treeNodes.splice(index, 1);
|
this.treeNodes.splice(index, 1);
|
||||||
if (nodeToCollapse.hasChildren) {
|
if (nodeToCollapse.hasChildren) {
|
||||||
this.treeNodes
|
this.treeNodes.filter((node: T) => nodeToCollapse.id === node.parentId).forEach((child: T) => this.collapseInnerNode(child));
|
||||||
.filter((node: T) => nodeToCollapse.id === node.parentId)
|
|
||||||
.forEach((child: T) => this.collapseInnerNode(child));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-18
@@ -36,9 +36,11 @@ export class FileUploadingListRowComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
showCancelledStatus(): boolean {
|
showCancelledStatus(): boolean {
|
||||||
return this.file.status === FileUploadStatus.Cancelled ||
|
return (
|
||||||
|
this.file.status === FileUploadStatus.Cancelled ||
|
||||||
this.file.status === FileUploadStatus.Aborted ||
|
this.file.status === FileUploadStatus.Aborted ||
|
||||||
this.file.status === FileUploadStatus.Deleted;
|
this.file.status === FileUploadStatus.Deleted
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
get versionNumber(): string {
|
get versionNumber(): string {
|
||||||
@@ -46,29 +48,19 @@ export class FileUploadingListRowComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get mimeType(): string {
|
get mimeType(): string {
|
||||||
if (this.file && this.file.file && this.file.file.type) {
|
return this.file?.file?.type || 'default';
|
||||||
return this.file.file.type;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 'default';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
isUploadVersion(): boolean {
|
isUploadVersion(): boolean {
|
||||||
return (
|
return !!this.file.data && this.file.options?.newVersion && this.file.data.entry.properties?.['cm:versionLabel'];
|
||||||
!!this.file.data &&
|
|
||||||
this.file.options &&
|
|
||||||
this.file.options.newVersion &&
|
|
||||||
this.file.data.entry.properties &&
|
|
||||||
this.file.data.entry.properties['cm:versionLabel']
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
canCancelUpload(): boolean {
|
canCancelUpload(): boolean {
|
||||||
return this.file && this.file.status === FileUploadStatus.Pending;
|
return this.file?.status === FileUploadStatus.Pending;
|
||||||
}
|
}
|
||||||
|
|
||||||
isUploadError(): boolean {
|
isUploadError(): boolean {
|
||||||
return this.file && this.file.status === FileUploadStatus.Error;
|
return this.file?.status === FileUploadStatus.Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
isUploading(): boolean {
|
isUploading(): boolean {
|
||||||
@@ -76,10 +68,10 @@ export class FileUploadingListRowComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
isUploadComplete(): boolean {
|
isUploadComplete(): boolean {
|
||||||
return this.file.status === FileUploadStatus.Complete && !this.isUploadVersion();
|
return this.file?.status === FileUploadStatus.Complete && !this.isUploadVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
isUploadVersionComplete(): boolean {
|
isUploadVersionComplete(): boolean {
|
||||||
return this.file && (this.file.status === FileUploadStatus.Complete && this.isUploadVersion());
|
return this.file?.status === FileUploadStatus.Complete && this.isUploadVersion();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,10 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { EXTENDIBLE_COMPONENT, FileUtils, LogService } from '@alfresco/adf-core';
|
import { EXTENDIBLE_COMPONENT, FileUtils, LogService } from '@alfresco/adf-core';
|
||||||
import {
|
import { Component, EventEmitter, forwardRef, Input, OnChanges, OnInit, Output, SimpleChanges, ViewEncapsulation, inject } from '@angular/core';
|
||||||
Component, EventEmitter, forwardRef, Input,
|
|
||||||
OnChanges, OnInit, Output, SimpleChanges, ViewEncapsulation, inject
|
|
||||||
} from '@angular/core';
|
|
||||||
import { NodesApiService } from '../../common/services/nodes-api.service';
|
import { NodesApiService } from '../../common/services/nodes-api.service';
|
||||||
import { ContentService } from '../../common/services/content.service';
|
import { ContentService } from '../../common/services/content.service';
|
||||||
import { AllowableOperationsEnum } from '../../common/models/allowable-operations.enum';
|
import { AllowableOperationsEnum } from '../../common/models/allowable-operations.enum';
|
||||||
@@ -33,9 +30,7 @@ import { NodeAllowableOperationSubject } from '../../interfaces/node-allowable-o
|
|||||||
selector: 'adf-upload-button',
|
selector: 'adf-upload-button',
|
||||||
templateUrl: './upload-button.component.html',
|
templateUrl: './upload-button.component.html',
|
||||||
styleUrls: ['./upload-button.component.scss'],
|
styleUrls: ['./upload-button.component.scss'],
|
||||||
viewProviders: [
|
viewProviders: [{ provide: EXTENDIBLE_COMPONENT, useExisting: forwardRef(() => UploadButtonComponent) }],
|
||||||
{ provide: EXTENDIBLE_COMPONENT, useExisting: forwardRef(() => UploadButtonComponent) }
|
|
||||||
],
|
|
||||||
encapsulation: ViewEncapsulation.None
|
encapsulation: ViewEncapsulation.None
|
||||||
})
|
})
|
||||||
export class UploadButtonComponent extends UploadBase implements OnInit, OnChanges, NodeAllowableOperationSubject {
|
export class UploadButtonComponent extends UploadBase implements OnInit, OnChanges, NodeAllowableOperationSubject {
|
||||||
@@ -78,7 +73,7 @@ export class UploadButtonComponent extends UploadBase implements OnInit, OnChang
|
|||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges) {
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
const rootFolderId = changes['rootFolderId'];
|
const rootFolderId = changes['rootFolderId'];
|
||||||
if (rootFolderId && rootFolderId.currentValue) {
|
if (rootFolderId?.currentValue) {
|
||||||
this.checkPermission();
|
this.checkPermission();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -88,7 +83,7 @@ export class UploadButtonComponent extends UploadBase implements OnInit, OnChang
|
|||||||
}
|
}
|
||||||
|
|
||||||
onFilesAdded($event: any): void {
|
onFilesAdded($event: any): void {
|
||||||
const files: File[] = FileUtils.toFileArray($event.currentTarget.files);
|
const files = FileUtils.toFileArray($event.currentTarget.files);
|
||||||
|
|
||||||
if (this.hasAllowableOperations) {
|
if (this.hasAllowableOperations) {
|
||||||
this.uploadFiles(files);
|
this.uploadFiles(files);
|
||||||
@@ -101,7 +96,7 @@ export class UploadButtonComponent extends UploadBase implements OnInit, OnChang
|
|||||||
|
|
||||||
onClickUploadButton(): void {
|
onClickUploadButton(): void {
|
||||||
if (this.file) {
|
if (this.file) {
|
||||||
const files: File[] = [this.file];
|
const files = [this.file];
|
||||||
|
|
||||||
if (this.hasAllowableOperations) {
|
if (this.hasAllowableOperations) {
|
||||||
this.uploadFiles(files);
|
this.uploadFiles(files);
|
||||||
@@ -113,7 +108,7 @@ export class UploadButtonComponent extends UploadBase implements OnInit, OnChang
|
|||||||
|
|
||||||
onDirectoryAdded($event: any): void {
|
onDirectoryAdded($event: any): void {
|
||||||
if (this.hasAllowableOperations) {
|
if (this.hasAllowableOperations) {
|
||||||
const files: File[] = FileUtils.toFileArray($event.currentTarget.files);
|
const files = FileUtils.toFileArray($event.currentTarget.files);
|
||||||
this.uploadFiles(files);
|
this.uploadFiles(files);
|
||||||
} else {
|
} else {
|
||||||
this.permissionEvent.emit(new PermissionModel({ type: 'content', action: 'upload', permission: 'create' }));
|
this.permissionEvent.emit(new PermissionModel({ type: 'content', action: 'upload', permission: 'create' }));
|
||||||
@@ -132,10 +127,10 @@ export class UploadButtonComponent extends UploadBase implements OnInit, OnChang
|
|||||||
this.nodesApiService.getNode(this.rootFolderId, opts).subscribe(
|
this.nodesApiService.getNode(this.rootFolderId, opts).subscribe(
|
||||||
(res) => this.permissionValue.next(this.nodeHasPermission(res, AllowableOperationsEnum.CREATE)),
|
(res) => this.permissionValue.next(this.nodeHasPermission(res, AllowableOperationsEnum.CREATE)),
|
||||||
(error: { error: Error }) => {
|
(error: { error: Error }) => {
|
||||||
if (error && error.error) {
|
if (error?.error) {
|
||||||
this.error.emit({ error: error.error.message } as any);
|
this.error.emit({ error: error.error.message } as any);
|
||||||
} else {
|
} else {
|
||||||
this.error.emit({ error: 'FILE_UPLOAD.BUTTON.PERMISSION_CHECK_ERROR'} as any);
|
this.error.emit({ error: 'FILE_UPLOAD.BUTTON.PERMISSION_CHECK_ERROR' } as any);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -22,15 +22,14 @@ import { UploadBase } from './base-upload/upload-base';
|
|||||||
import { AllowableOperationsEnum } from '../../common/models/allowable-operations.enum';
|
import { AllowableOperationsEnum } from '../../common/models/allowable-operations.enum';
|
||||||
import { ContentService } from '../../common/services/content.service';
|
import { ContentService } from '../../common/services/content.service';
|
||||||
import { FileModel } from '../../common/models/file.model';
|
import { FileModel } from '../../common/models/file.model';
|
||||||
|
import { Node } from '@alfresco/js-api';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'adf-upload-drag-area',
|
selector: 'adf-upload-drag-area',
|
||||||
templateUrl: './upload-drag-area.component.html',
|
templateUrl: './upload-drag-area.component.html',
|
||||||
styleUrls: ['./upload-drag-area.component.scss'],
|
styleUrls: ['./upload-drag-area.component.scss'],
|
||||||
host: { class: 'adf-upload-drag-area' },
|
host: { class: 'adf-upload-drag-area' },
|
||||||
viewProviders: [
|
viewProviders: [{ provide: EXTENDIBLE_COMPONENT, useExisting: forwardRef(() => UploadDragAreaComponent) }],
|
||||||
{provide: EXTENDIBLE_COMPONENT, useExisting: forwardRef(() => UploadDragAreaComponent)}
|
|
||||||
],
|
|
||||||
encapsulation: ViewEncapsulation.None
|
encapsulation: ViewEncapsulation.None
|
||||||
})
|
})
|
||||||
export class UploadDragAreaComponent extends UploadBase implements NodeAllowableOperationSubject {
|
export class UploadDragAreaComponent extends UploadBase implements NodeAllowableOperationSubject {
|
||||||
@@ -70,7 +69,10 @@ export class UploadDragAreaComponent extends UploadBase implements NodeAllowable
|
|||||||
const messageTranslate = this.translationService.instant('FILE_UPLOAD.MESSAGES.PROGRESS');
|
const messageTranslate = this.translationService.instant('FILE_UPLOAD.MESSAGES.PROGRESS');
|
||||||
const actionTranslate = this.translationService.instant('FILE_UPLOAD.ACTION.UNDO');
|
const actionTranslate = this.translationService.instant('FILE_UPLOAD.ACTION.UNDO');
|
||||||
|
|
||||||
this.notificationService.openSnackMessageAction(messageTranslate, actionTranslate).onAction().subscribe(() => {
|
this.notificationService
|
||||||
|
.openSnackMessageAction(messageTranslate, actionTranslate)
|
||||||
|
.onAction()
|
||||||
|
.subscribe(() => {
|
||||||
this.uploadService.cancelUpload(...latestFilesAdded);
|
this.uploadService.cancelUpload(...latestFilesAdded);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -88,27 +90,29 @@ export class UploadDragAreaComponent extends UploadBase implements NodeAllowable
|
|||||||
onUploadFiles(event: CustomEvent) {
|
onUploadFiles(event: CustomEvent) {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const isAllowed: boolean = this.isTargetNodeFolder(event) ?
|
|
||||||
this.contentService.hasAllowableOperations(event.detail.data.obj.entry, AllowableOperationsEnum.CREATE)
|
const node: Node = event.detail.data.obj.entry;
|
||||||
: this.contentService.hasAllowableOperations(event.detail.data.obj.entry, AllowableOperationsEnum.UPDATE);
|
const files: FileInfo[] = event.detail?.files || [];
|
||||||
|
|
||||||
|
const isAllowed: boolean = this.isTargetNodeFolder(node)
|
||||||
|
? this.contentService.hasAllowableOperations(node, AllowableOperationsEnum.CREATE)
|
||||||
|
: this.contentService.hasAllowableOperations(node, AllowableOperationsEnum.UPDATE);
|
||||||
|
|
||||||
if (isAllowed) {
|
if (isAllowed) {
|
||||||
if (!this.isTargetNodeFolder(event) && event.detail.files.length === 1) {
|
if (!this.isTargetNodeFolder(node) && files.length === 1) {
|
||||||
this.updateFileVersion.emit(event);
|
this.updateFileVersion.emit(event);
|
||||||
} else {
|
} else {
|
||||||
const fileInfo: FileInfo[] = event.detail.files;
|
if (this.isTargetNodeFolder(node)) {
|
||||||
if (this.isTargetNodeFolder(event)) {
|
files.forEach((file) => (file.relativeFolder = node.name ? node.name.concat(file.relativeFolder) : file.relativeFolder));
|
||||||
const destinationFolderName = event.detail.data.obj.entry.name;
|
|
||||||
fileInfo.map((file) => file.relativeFolder = destinationFolderName ? destinationFolderName.concat(file.relativeFolder) : file.relativeFolder);
|
|
||||||
}
|
}
|
||||||
if (fileInfo && fileInfo.length > 0) {
|
if (files?.length > 0) {
|
||||||
this.uploadFilesInfo(fileInfo);
|
this.uploadFilesInfo(files);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private isTargetNodeFolder(event: CustomEvent): boolean {
|
private isTargetNodeFolder(node: Node): boolean {
|
||||||
return event.detail.data.obj && event.detail.data.obj.entry.isFolder;
|
return !!node?.isFolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,17 +42,7 @@ import {
|
|||||||
ViewUtilService
|
ViewUtilService
|
||||||
} from '@alfresco/adf-core';
|
} from '@alfresco/adf-core';
|
||||||
import { Subject } from 'rxjs';
|
import { Subject } from 'rxjs';
|
||||||
import {
|
import { ContentApi, Node, NodeEntry, NodesApi, RenditionEntry, SharedlinksApi, Version, VersionEntry, VersionsApi } from '@alfresco/js-api';
|
||||||
ContentApi,
|
|
||||||
Node,
|
|
||||||
NodeEntry,
|
|
||||||
NodesApi,
|
|
||||||
RenditionEntry,
|
|
||||||
SharedlinksApi,
|
|
||||||
Version,
|
|
||||||
VersionEntry,
|
|
||||||
VersionsApi
|
|
||||||
} from '@alfresco/js-api';
|
|
||||||
import { RenditionService } from '../../common/services/rendition.service';
|
import { RenditionService } from '../../common/services/rendition.service';
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
import { filter, takeUntil } from 'rxjs/operators';
|
import { filter, takeUntil } from 'rxjs/operators';
|
||||||
@@ -66,12 +56,11 @@ import { NodeActionsService } from '../../document-list';
|
|||||||
selector: 'adf-alfresco-viewer',
|
selector: 'adf-alfresco-viewer',
|
||||||
templateUrl: './alfresco-viewer.component.html',
|
templateUrl: './alfresco-viewer.component.html',
|
||||||
styleUrls: ['./alfresco-viewer.component.scss'],
|
styleUrls: ['./alfresco-viewer.component.scss'],
|
||||||
host: {class: 'adf-alfresco-viewer'},
|
host: { class: 'adf-alfresco-viewer' },
|
||||||
encapsulation: ViewEncapsulation.None,
|
encapsulation: ViewEncapsulation.None,
|
||||||
providers: [ViewUtilService]
|
providers: [ViewUtilService]
|
||||||
})
|
})
|
||||||
export class AlfrescoViewerComponent implements OnChanges, OnInit, OnDestroy {
|
export class AlfrescoViewerComponent implements OnChanges, OnInit, OnDestroy {
|
||||||
|
|
||||||
@ViewChild('adfViewer')
|
@ViewChild('adfViewer')
|
||||||
adfViewer: ViewerComponent<{ node: Node }>;
|
adfViewer: ViewerComponent<{ node: Node }>;
|
||||||
|
|
||||||
@@ -204,8 +193,8 @@ export class AlfrescoViewerComponent implements OnChanges, OnInit, OnDestroy {
|
|||||||
tracks: Track[] = [];
|
tracks: Track[] = [];
|
||||||
readOnly: boolean = true;
|
readOnly: boolean = true;
|
||||||
|
|
||||||
sidebarRightTemplateContext: { node: Node } = {node: null};
|
sidebarRightTemplateContext: { node: Node } = { node: null };
|
||||||
sidebarLeftTemplateContext: { node: Node } = {node: null};
|
sidebarLeftTemplateContext: { node: Node } = { node: null };
|
||||||
|
|
||||||
_sharedLinksApi: SharedlinksApi;
|
_sharedLinksApi: SharedlinksApi;
|
||||||
get sharedLinksApi(): SharedlinksApi {
|
get sharedLinksApi(): SharedlinksApi {
|
||||||
@@ -231,7 +220,8 @@ export class AlfrescoViewerComponent implements OnChanges, OnInit, OnDestroy {
|
|||||||
return this._contentApi;
|
return this._contentApi;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(private apiService: AlfrescoApiService,
|
constructor(
|
||||||
|
private apiService: AlfrescoApiService,
|
||||||
private nodesApiService: NodesApiService,
|
private nodesApiService: NodesApiService,
|
||||||
private renditionService: RenditionService,
|
private renditionService: RenditionService,
|
||||||
private viewUtilService: ViewUtilService,
|
private viewUtilService: ViewUtilService,
|
||||||
@@ -240,18 +230,23 @@ export class AlfrescoViewerComponent implements OnChanges, OnInit, OnDestroy {
|
|||||||
private uploadService: UploadService,
|
private uploadService: UploadService,
|
||||||
public dialog: MatDialog,
|
public dialog: MatDialog,
|
||||||
private cdr: ChangeDetectorRef,
|
private cdr: ChangeDetectorRef,
|
||||||
private nodeActionsService: NodeActionsService) {
|
private nodeActionsService: NodeActionsService
|
||||||
|
) {
|
||||||
renditionService.maxRetries = this.maxRetries;
|
renditionService.maxRetries = this.maxRetries;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.nodesApiService.nodeUpdated.pipe(
|
this.nodesApiService.nodeUpdated
|
||||||
filter((node) => node && node.id === this.nodeId &&
|
.pipe(
|
||||||
(node.name !== this.fileName ||
|
filter(
|
||||||
this.getNodeVersionProperty(this.nodeEntry.entry) !== this.getNodeVersionProperty(node))),
|
(node) =>
|
||||||
|
node &&
|
||||||
|
node.id === this.nodeId &&
|
||||||
|
(node.name !== this.fileName || this.getNodeVersionProperty(this.nodeEntry.entry) !== this.getNodeVersionProperty(node))
|
||||||
|
),
|
||||||
takeUntil(this.onDestroy$)
|
takeUntil(this.onDestroy$)
|
||||||
).subscribe((node) => this.onNodeUpdated(node));
|
)
|
||||||
|
.subscribe((node) => this.onNodeUpdated(node));
|
||||||
}
|
}
|
||||||
|
|
||||||
private async onNodeUpdated(node: Node) {
|
private async onNodeUpdated(node: Node) {
|
||||||
@@ -282,7 +277,7 @@ export class AlfrescoViewerComponent implements OnChanges, OnInit, OnDestroy {
|
|||||||
|
|
||||||
private async setupNode() {
|
private async setupNode() {
|
||||||
try {
|
try {
|
||||||
this.nodeEntry = await this.nodesApi.getNode(this.nodeId, {include: ['allowableOperations']});
|
this.nodeEntry = await this.nodesApi.getNode(this.nodeId, { include: ['allowableOperations'] });
|
||||||
if (this.versionId) {
|
if (this.versionId) {
|
||||||
this.versionEntry = await this.versionsApi.getVersion(this.nodeId, this.versionId);
|
this.versionEntry = await this.versionsApi.getVersion(this.nodeId, this.versionId);
|
||||||
await this.setUpNodeFile(this.nodeEntry.entry, this.versionEntry.entry);
|
await this.setUpNodeFile(this.nodeEntry.entry, this.versionEntry.entry);
|
||||||
@@ -297,24 +292,24 @@ export class AlfrescoViewerComponent implements OnChanges, OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async setUpNodeFile(nodeData: Node, versionData?: Version): Promise<void> {
|
private async setUpNodeFile(nodeData: Node, versionData?: Version): Promise<void> {
|
||||||
|
|
||||||
this.readOnly = !this.contentService.hasAllowableOperations(nodeData, 'update');
|
this.readOnly = !this.contentService.hasAllowableOperations(nodeData, 'update');
|
||||||
let mimeType;
|
let mimeType: string;
|
||||||
let urlFileContent;
|
let urlFileContent: string;
|
||||||
|
|
||||||
if (versionData && versionData.content) {
|
if (versionData?.content) {
|
||||||
mimeType = versionData.content.mimeType;
|
mimeType = versionData.content.mimeType;
|
||||||
} else if (nodeData.content) {
|
} else if (nodeData.content) {
|
||||||
mimeType = nodeData.content.mimeType;
|
mimeType = nodeData.content.mimeType;
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentFileVersion = this.nodeEntry?.entry?.properties && this.nodeEntry.entry.properties['cm:versionLabel'] ?
|
const currentFileVersion = this.nodeEntry?.entry?.properties?.['cm:versionLabel']
|
||||||
encodeURI(this.nodeEntry?.entry?.properties['cm:versionLabel']) : encodeURI('1.0');
|
? encodeURI(this.nodeEntry?.entry?.properties['cm:versionLabel'])
|
||||||
|
: encodeURI('1.0');
|
||||||
|
|
||||||
urlFileContent = versionData ? this.contentApi.getVersionContentUrl(this.nodeId, versionData.id) :
|
urlFileContent = versionData ? this.contentApi.getVersionContentUrl(this.nodeId, versionData.id) : this.contentApi.getContentUrl(this.nodeId);
|
||||||
this.contentApi.getContentUrl(this.nodeId);
|
urlFileContent = this.cacheBusterNumber
|
||||||
urlFileContent = this.cacheBusterNumber ? urlFileContent + '&' + currentFileVersion + '&' + this.cacheBusterNumber :
|
? urlFileContent + '&' + currentFileVersion + '&' + this.cacheBusterNumber
|
||||||
urlFileContent + '&' + currentFileVersion;
|
: urlFileContent + '&' + currentFileVersion;
|
||||||
|
|
||||||
const fileExtension = this.viewUtilService.getFileExtension(versionData ? versionData.name : nodeData.name);
|
const fileExtension = this.viewUtilService.getFileExtension(versionData ? versionData.name : nodeData.name);
|
||||||
this.fileName = versionData ? versionData.name : nodeData.name;
|
this.fileName = versionData ? versionData.name : nodeData.name;
|
||||||
@@ -349,10 +344,7 @@ export class AlfrescoViewerComponent implements OnChanges, OnInit, OnDestroy {
|
|||||||
const viewerType = this.viewUtilService.getViewerType(fileExtension, mimeType);
|
const viewerType = this.viewUtilService.getViewerType(fileExtension, mimeType);
|
||||||
|
|
||||||
if (viewerType === 'unknown') {
|
if (viewerType === 'unknown') {
|
||||||
({
|
({ url: urlFileContent, mimeType } = await this.getSharedLinkRendition(this.sharedLinkId));
|
||||||
url: urlFileContent,
|
|
||||||
mimeType
|
|
||||||
} = await this.getSharedLinkRendition(this.sharedLinkId));
|
|
||||||
}
|
}
|
||||||
this.mimeType = mimeType;
|
this.mimeType = mimeType;
|
||||||
this.urlFileContent = urlFileContent;
|
this.urlFileContent = urlFileContent;
|
||||||
@@ -363,7 +355,7 @@ export class AlfrescoViewerComponent implements OnChanges, OnInit, OnDestroy {
|
|||||||
const rendition: RenditionEntry = await this.sharedLinksApi.getSharedLinkRendition(sharedId, 'pdf');
|
const rendition: RenditionEntry = await this.sharedLinksApi.getSharedLinkRendition(sharedId, 'pdf');
|
||||||
if (rendition.entry.status.toString() === 'CREATED') {
|
if (rendition.entry.status.toString() === 'CREATED') {
|
||||||
const urlFileContent = this.contentApi.getSharedLinkRenditionUrl(sharedId, 'pdf');
|
const urlFileContent = this.contentApi.getSharedLinkRenditionUrl(sharedId, 'pdf');
|
||||||
return {url: urlFileContent, mimeType: 'application/pdf'};
|
return { url: urlFileContent, mimeType: 'application/pdf' };
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.logService.error(error);
|
this.logService.error(error);
|
||||||
@@ -371,8 +363,7 @@ export class AlfrescoViewerComponent implements OnChanges, OnInit, OnDestroy {
|
|||||||
const rendition: RenditionEntry = await this.sharedLinksApi.getSharedLinkRendition(sharedId, 'imgpreview');
|
const rendition: RenditionEntry = await this.sharedLinksApi.getSharedLinkRendition(sharedId, 'imgpreview');
|
||||||
if (rendition.entry.status.toString() === 'CREATED') {
|
if (rendition.entry.status.toString() === 'CREATED') {
|
||||||
const urlFileContent = this.contentApi.getSharedLinkRenditionUrl(sharedId, 'imgpreview');
|
const urlFileContent = this.contentApi.getSharedLinkRenditionUrl(sharedId, 'imgpreview');
|
||||||
return {url: urlFileContent, mimeType: 'image/png'};
|
return { url: urlFileContent, mimeType: 'image/png' };
|
||||||
|
|
||||||
}
|
}
|
||||||
} catch (renditionError) {
|
} catch (renditionError) {
|
||||||
this.logService.error(renditionError);
|
this.logService.error(renditionError);
|
||||||
@@ -404,7 +395,7 @@ export class AlfrescoViewerComponent implements OnChanges, OnInit, OnDestroy {
|
|||||||
|
|
||||||
onSubmitFile(newImageBlob: Blob) {
|
onSubmitFile(newImageBlob: Blob) {
|
||||||
if (this?.nodeEntry?.entry?.id && !this.readOnly) {
|
if (this?.nodeEntry?.entry?.id && !this.readOnly) {
|
||||||
const newImageFile: File = new File([newImageBlob], this?.nodeEntry?.entry?.name, {type: this?.nodeEntry?.entry?.content?.mimeType});
|
const newImageFile: File = new File([newImageBlob], this?.nodeEntry?.entry?.name, { type: this?.nodeEntry?.entry?.content?.mimeType });
|
||||||
const newFile = new FileModel(
|
const newFile = new FileModel(
|
||||||
newImageFile,
|
newImageFile,
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
"extends": "./tsconfig.json",
|
"extends": "./tsconfig.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"outDir": "../../dist/out-tsc",
|
"outDir": "../../dist/out-tsc",
|
||||||
|
"declaration": true,
|
||||||
"declarationMap": true,
|
"declarationMap": true,
|
||||||
"paths": {
|
"paths": {
|
||||||
"@alfresco/adf-extensions": ["../../../dist/libs/extensions"],
|
"@alfresco/adf-extensions": ["../../../dist/libs/extensions"],
|
||||||
|
|||||||
@@ -63,10 +63,6 @@
|
|||||||
"@typescript-eslint/no-inferrable-types": "off",
|
"@typescript-eslint/no-inferrable-types": "off",
|
||||||
"@typescript-eslint/no-require-imports": "off",
|
"@typescript-eslint/no-require-imports": "off",
|
||||||
"@typescript-eslint/no-var-requires": "error",
|
"@typescript-eslint/no-var-requires": "error",
|
||||||
"brace-style": [
|
|
||||||
"error",
|
|
||||||
"1tbs"
|
|
||||||
],
|
|
||||||
"comma-dangle": "error",
|
"comma-dangle": "error",
|
||||||
"default-case": "error",
|
"default-case": "error",
|
||||||
"import/order": "off",
|
"import/order": "off",
|
||||||
|
|||||||
@@ -15,14 +15,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, CanActivateChild, UrlTree } from '@angular/router';
|
||||||
Router,
|
|
||||||
CanActivate,
|
|
||||||
ActivatedRouteSnapshot,
|
|
||||||
RouterStateSnapshot,
|
|
||||||
CanActivateChild,
|
|
||||||
UrlTree
|
|
||||||
} from '@angular/router';
|
|
||||||
import { AuthenticationService } from '../services/authentication.service';
|
import { AuthenticationService } from '../services/authentication.service';
|
||||||
import { AppConfigService, AppConfigValues } from '../../app-config/app-config.service';
|
import { AppConfigService, AppConfigValues } from '../../app-config/app-config.service';
|
||||||
import { OauthConfigModel } from '../models/oauth-config.model';
|
import { OauthConfigModel } from '../models/oauth-config.model';
|
||||||
@@ -39,10 +32,7 @@ export abstract class AuthGuardBase implements CanActivate, CanActivateChild {
|
|||||||
private storageService = inject(StorageService);
|
private storageService = inject(StorageService);
|
||||||
|
|
||||||
protected get withCredentials(): boolean {
|
protected get withCredentials(): boolean {
|
||||||
return this.appConfigService.get<boolean>(
|
return this.appConfigService.get<boolean>('auth.withCredentials', false);
|
||||||
'auth.withCredentials',
|
|
||||||
false
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract checkLogin(
|
abstract checkLogin(
|
||||||
@@ -54,7 +44,6 @@ export abstract class AuthGuardBase implements CanActivate, CanActivateChild {
|
|||||||
route: ActivatedRouteSnapshot,
|
route: ActivatedRouteSnapshot,
|
||||||
state: RouterStateSnapshot
|
state: RouterStateSnapshot
|
||||||
): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
|
): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
|
||||||
|
|
||||||
if (this.authenticationService.isLoggedIn() && this.authenticationService.isOauth() && this.isLoginFragmentPresent()) {
|
if (this.authenticationService.isLoggedIn() && this.authenticationService.isOauth() && this.isLoginFragmentPresent()) {
|
||||||
return this.redirectSSOSuccessURL();
|
return this.redirectSSOSuccessURL();
|
||||||
}
|
}
|
||||||
@@ -116,23 +105,11 @@ export abstract class AuthGuardBase implements CanActivate, CanActivateChild {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected getLoginRoute(): string {
|
protected getLoginRoute(): string {
|
||||||
return (
|
return this.appConfigService.get<string>(AppConfigValues.LOGIN_ROUTE, 'login');
|
||||||
this.appConfigService &&
|
|
||||||
this.appConfigService.get<string>(
|
|
||||||
AppConfigValues.LOGIN_ROUTE,
|
|
||||||
'login'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected getProvider(): string {
|
protected getProvider(): string {
|
||||||
return (
|
return this.appConfigService.get<string>(AppConfigValues.PROVIDERS, 'ALL');
|
||||||
this.appConfigService &&
|
|
||||||
this.appConfigService.get<string>(
|
|
||||||
AppConfigValues.PROVIDERS,
|
|
||||||
'ALL'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected isOAuthWithoutSilentLogin(): boolean {
|
protected isOAuthWithoutSilentLogin(): boolean {
|
||||||
@@ -141,8 +118,7 @@ export abstract class AuthGuardBase implements CanActivate, CanActivateChild {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected isSilentLogin(): boolean {
|
protected isSilentLogin(): boolean {
|
||||||
const oauth = this.appConfigService.oauth2;;
|
const oauth = this.appConfigService.oauth2;
|
||||||
return this.authenticationService.isOauth() && oauth && oauth.silentLogin;
|
return this.authenticationService.isOauth() && oauth && oauth.silentLogin;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-10
@@ -42,7 +42,6 @@ const templateTypes = {
|
|||||||
encapsulation: ViewEncapsulation.None
|
encapsulation: ViewEncapsulation.None
|
||||||
})
|
})
|
||||||
export class CardViewTextItemComponent extends BaseCardView<CardViewTextItemModel> implements OnChanges, OnDestroy {
|
export class CardViewTextItemComponent extends BaseCardView<CardViewTextItemModel> implements OnChanges, OnDestroy {
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
editable: boolean = false;
|
editable: boolean = false;
|
||||||
|
|
||||||
@@ -69,21 +68,19 @@ export class CardViewTextItemComponent extends BaseCardView<CardViewTextItemMode
|
|||||||
|
|
||||||
private onDestroy$ = new Subject<boolean>();
|
private onDestroy$ = new Subject<boolean>();
|
||||||
|
|
||||||
constructor(private clipboardService: ClipboardService,
|
constructor(private clipboardService: ClipboardService, private translateService: TranslationService, private cd: ChangeDetectorRef) {
|
||||||
private translateService: TranslationService,
|
|
||||||
private cd: ChangeDetectorRef) {
|
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges): void {
|
ngOnChanges(changes: SimpleChanges): void {
|
||||||
if (changes.property && changes.property.firstChange) {
|
if (changes.property?.firstChange) {
|
||||||
this.textInput.valueChanges
|
this.textInput.valueChanges
|
||||||
.pipe(
|
.pipe(
|
||||||
filter(textInputValue => textInputValue !== this.editedValue && textInputValue !== null),
|
filter((textInputValue) => textInputValue !== this.editedValue && textInputValue !== null),
|
||||||
debounceTime(50),
|
debounceTime(50),
|
||||||
takeUntil(this.onDestroy$)
|
takeUntil(this.onDestroy$)
|
||||||
)
|
)
|
||||||
.subscribe(textInputValue => {
|
.subscribe((textInputValue) => {
|
||||||
this.editedValue = textInputValue;
|
this.editedValue = textInputValue;
|
||||||
this.update();
|
this.update();
|
||||||
});
|
});
|
||||||
@@ -143,8 +140,7 @@ export class CardViewTextItemComponent extends BaseCardView<CardViewTextItemMode
|
|||||||
|
|
||||||
prepareValueForUpload(property: CardViewTextItemModel, value: string | string[]): string | string[] {
|
prepareValueForUpload(property: CardViewTextItemModel, value: string | string[]): string | string[] {
|
||||||
if (property.multivalued && typeof value === 'string') {
|
if (property.multivalued && typeof value === 'string') {
|
||||||
const listOfValues = value.split(this.multiValueSeparator.trim()).map((item) => item.trim());
|
return value.split(this.multiValueSeparator.trim()).map((item) => item.trim());
|
||||||
return listOfValues;
|
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
@@ -226,7 +222,7 @@ export class CardViewTextItemComponent extends BaseCardView<CardViewTextItemMode
|
|||||||
}
|
}
|
||||||
|
|
||||||
get hasErrors(): boolean {
|
get hasErrors(): boolean {
|
||||||
return (!!this.errors?.length) ?? false;
|
return !!this.errors?.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
get isChipViewEnabled(): boolean {
|
get isChipViewEnabled(): boolean {
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ export abstract class CardViewBaseItemModel {
|
|||||||
|
|
||||||
constructor(cardViewItemProperties: CardViewItemProperties) {
|
constructor(cardViewItemProperties: CardViewItemProperties) {
|
||||||
this.label = cardViewItemProperties.label || '';
|
this.label = cardViewItemProperties.label || '';
|
||||||
this.value = cardViewItemProperties.value && cardViewItemProperties.value.displayName || cardViewItemProperties.value;
|
this.value = cardViewItemProperties.value?.displayName || cardViewItemProperties.value;
|
||||||
this.key = cardViewItemProperties.key;
|
this.key = cardViewItemProperties.key;
|
||||||
this.default = cardViewItemProperties.default;
|
this.default = cardViewItemProperties.default;
|
||||||
this.editable = !!cardViewItemProperties.editable;
|
this.editable = !!cardViewItemProperties.editable;
|
||||||
@@ -63,9 +63,7 @@ export abstract class CardViewBaseItemModel {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.validators
|
return this.validators.map((validator) => validator.isValid(newValue)).reduce((isValidUntilNow, isValid) => isValidUntilNow && isValid, true);
|
||||||
.map((validator) => validator.isValid(newValue))
|
|
||||||
.reduce((isValidUntilNow, isValid) => isValidUntilNow && isValid, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getValidationErrors(value): CardViewItemValidator[] {
|
getValidationErrors(value): CardViewItemValidator[] {
|
||||||
|
|||||||
@@ -19,7 +19,10 @@ import { Type } from '@angular/core';
|
|||||||
|
|
||||||
const getType = (type: any): any => () => type;
|
const getType = (type: any): any => () => type;
|
||||||
|
|
||||||
export interface DynamicComponentModel { type: string }
|
export interface DynamicComponentModel {
|
||||||
|
type: string;
|
||||||
|
}
|
||||||
|
|
||||||
export type DynamicComponentResolveFunction = (model: DynamicComponentModel) => Type<any>;
|
export type DynamicComponentResolveFunction = (model: DynamicComponentModel) => Type<any>;
|
||||||
export class DynamicComponentResolver {
|
export class DynamicComponentResolver {
|
||||||
static fromType(type: Type<any>): DynamicComponentResolveFunction {
|
static fromType(type: Type<any>): DynamicComponentResolveFunction {
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import moment, { isMoment, Moment } from 'moment';
|
|||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class MomentDateAdapter extends DateAdapter<Moment> {
|
export class MomentDateAdapter extends DateAdapter<Moment> {
|
||||||
|
|
||||||
private localeData: any = moment.localeData();
|
private localeData: any = moment.localeData();
|
||||||
|
|
||||||
overrideDisplayFormat: string;
|
overrideDisplayFormat: string;
|
||||||
@@ -50,7 +49,7 @@ export class MomentDateAdapter extends DateAdapter<Moment> {
|
|||||||
return this.localeData.monthsShort();
|
return this.localeData.monthsShort();
|
||||||
case 'narrow':
|
case 'narrow':
|
||||||
return this.localeData.monthsShort().map((month) => month[0]);
|
return this.localeData.monthsShort().map((month) => month[0]);
|
||||||
default :
|
default:
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -72,7 +71,7 @@ export class MomentDateAdapter extends DateAdapter<Moment> {
|
|||||||
return this.localeData.weekdaysShort();
|
return this.localeData.weekdaysShort();
|
||||||
case 'narrow':
|
case 'narrow':
|
||||||
return this.localeData.weekdaysShort();
|
return this.localeData.weekdaysShort();
|
||||||
default :
|
default:
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -134,7 +133,7 @@ export class MomentDateAdapter extends DateAdapter<Moment> {
|
|||||||
date = this.clone(date);
|
date = this.clone(date);
|
||||||
displayFormat = this.overrideDisplayFormat ? this.overrideDisplayFormat : displayFormat;
|
displayFormat = this.overrideDisplayFormat ? this.overrideDisplayFormat : displayFormat;
|
||||||
|
|
||||||
if (date && date.format) {
|
if (date?.format) {
|
||||||
return date.utc().local().format(displayFormat);
|
return date.utc().local().format(displayFormat);
|
||||||
} else {
|
} else {
|
||||||
return '';
|
return '';
|
||||||
|
|||||||
@@ -15,10 +15,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import { Component, ViewEncapsulation, HostListener, AfterViewInit, Optional, Inject, QueryList, ViewChildren } from '@angular/core';
|
||||||
Component, ViewEncapsulation, HostListener, AfterViewInit,
|
|
||||||
Optional, Inject, QueryList, ViewChildren
|
|
||||||
} from '@angular/core';
|
|
||||||
import { trigger } from '@angular/animations';
|
import { trigger } from '@angular/animations';
|
||||||
import { DOWN_ARROW, UP_ARROW } from '@angular/cdk/keycodes';
|
import { DOWN_ARROW, UP_ARROW } from '@angular/cdk/keycodes';
|
||||||
import { FocusKeyManager } from '@angular/cdk/a11y';
|
import { FocusKeyManager } from '@angular/cdk/a11y';
|
||||||
@@ -33,13 +30,15 @@ import { CONTEXT_MENU_DATA } from './context-menu.tokens';
|
|||||||
<div mat-menu class="mat-menu-panel" @panelAnimation>
|
<div mat-menu class="mat-menu-panel" @panelAnimation>
|
||||||
<div id="adf-context-menu-content" class="mat-menu-content">
|
<div id="adf-context-menu-content" class="mat-menu-content">
|
||||||
<ng-container *ngFor="let link of links">
|
<ng-container *ngFor="let link of links">
|
||||||
<button *ngIf="link.model?.visible"
|
<button
|
||||||
[attr.data-automation-id]="'context-'+((link.title || link.model?.title) | translate)"
|
*ngIf="link.model?.visible"
|
||||||
|
[attr.data-automation-id]="'context-' + (link.title || link.model?.title | translate)"
|
||||||
mat-menu-item
|
mat-menu-item
|
||||||
[disabled]="link.model?.disabled"
|
[disabled]="link.model?.disabled"
|
||||||
(click)="onMenuItemClick($event, link)">
|
(click)="onMenuItemClick($event, link)"
|
||||||
|
>
|
||||||
<mat-icon *ngIf="link.model?.icon">{{ link.model.icon }}</mat-icon>
|
<mat-icon *ngIf="link.model?.icon">{{ link.model.icon }}</mat-icon>
|
||||||
<span>{{ (link.title || link.model?.title) | translate }}</span>
|
<span>{{ link.title || link.model?.title | translate }}</span>
|
||||||
</button>
|
</button>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</div>
|
</div>
|
||||||
@@ -50,9 +49,7 @@ import { CONTEXT_MENU_DATA } from './context-menu.tokens';
|
|||||||
class: 'adf-context-menu'
|
class: 'adf-context-menu'
|
||||||
},
|
},
|
||||||
encapsulation: ViewEncapsulation.None,
|
encapsulation: ViewEncapsulation.None,
|
||||||
animations: [
|
animations: [trigger('panelAnimation', contextMenuAnimation)]
|
||||||
trigger('panelAnimation', contextMenuAnimation)
|
|
||||||
]
|
|
||||||
})
|
})
|
||||||
export class ContextMenuListComponent implements AfterViewInit {
|
export class ContextMenuListComponent implements AfterViewInit {
|
||||||
private keyManager: FocusKeyManager<MatMenuItem>;
|
private keyManager: FocusKeyManager<MatMenuItem>;
|
||||||
@@ -84,7 +81,7 @@ export class ContextMenuListComponent implements AfterViewInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMenuItemClick(event: Event, menuItem: any) {
|
onMenuItemClick(event: Event, menuItem: any) {
|
||||||
if (menuItem && menuItem.model && menuItem.model.disabled) {
|
if (menuItem?.model?.disabled) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopImmediatePropagation();
|
event.stopImmediatePropagation();
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -15,14 +15,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import { ChangeDetectionStrategy, Component, Input, OnInit, ViewEncapsulation, OnDestroy, Optional } from '@angular/core';
|
||||||
ChangeDetectionStrategy,
|
|
||||||
Component,
|
|
||||||
Input,
|
|
||||||
OnInit,
|
|
||||||
ViewEncapsulation,
|
|
||||||
OnDestroy, Optional
|
|
||||||
} from '@angular/core';
|
|
||||||
import { DataColumn } from '../../data/data-column.model';
|
import { DataColumn } from '../../data/data-column.model';
|
||||||
import { DataRow } from '../../data/data-row.model';
|
import { DataRow } from '../../data/data-row.model';
|
||||||
import { DataTableAdapter } from '../../data/datatable-adapter';
|
import { DataTableAdapter } from '../../data/datatable-adapter';
|
||||||
@@ -35,23 +28,22 @@ import { DataTableService } from '../../services/datatable.service';
|
|||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
template: `
|
template: `
|
||||||
<ng-container>
|
<ng-container>
|
||||||
<span *ngIf="copyContent; else defaultCell"
|
<span
|
||||||
|
*ngIf="copyContent; else defaultCell"
|
||||||
adf-clipboard="CLIPBOARD.CLICK_TO_COPY"
|
adf-clipboard="CLIPBOARD.CLICK_TO_COPY"
|
||||||
[clipboard-notification]="'CLIPBOARD.SUCCESS_COPY'"
|
[clipboard-notification]="'CLIPBOARD.SUCCESS_COPY'"
|
||||||
[attr.aria-label]="value$ | async"
|
[attr.aria-label]="value$ | async"
|
||||||
[title]="tooltip"
|
[title]="tooltip"
|
||||||
class="adf-datatable-cell-value"
|
class="adf-datatable-cell-value"
|
||||||
>{{ value$ | async }}</span>
|
>{{ value$ | async }}</span
|
||||||
|
>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<ng-template #defaultCell>
|
<ng-template #defaultCell>
|
||||||
<span
|
<span [title]="tooltip" class="adf-datatable-cell-value">{{ value$ | async }}</span>
|
||||||
[title]="tooltip"
|
|
||||||
class="adf-datatable-cell-value"
|
|
||||||
>{{ value$ | async }}</span>
|
|
||||||
</ng-template>
|
</ng-template>
|
||||||
`,
|
`,
|
||||||
encapsulation: ViewEncapsulation.None,
|
encapsulation: ViewEncapsulation.None,
|
||||||
host: {class: 'adf-datatable-content-cell'}
|
host: { class: 'adf-datatable-content-cell' }
|
||||||
})
|
})
|
||||||
export class DataTableCellComponent implements OnInit, OnDestroy {
|
export class DataTableCellComponent implements OnInit, OnDestroy {
|
||||||
/** Data table adapter instance. */
|
/** Data table adapter instance. */
|
||||||
@@ -82,20 +74,19 @@ export class DataTableCellComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
protected onDestroy$ = new Subject<boolean>();
|
protected onDestroy$ = new Subject<boolean>();
|
||||||
|
|
||||||
constructor(@Optional() protected dataTableService: DataTableService) {
|
constructor(@Optional() protected dataTableService: DataTableService) {}
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.updateValue();
|
this.updateValue();
|
||||||
if(this.dataTableService) {
|
if (this.dataTableService) {
|
||||||
this.dataTableService.rowUpdate
|
this.dataTableService.rowUpdate.pipe(takeUntil(this.onDestroy$)).subscribe((data) => {
|
||||||
.pipe(takeUntil(this.onDestroy$))
|
if (data?.id) {
|
||||||
.subscribe(data => {
|
|
||||||
if (data && data.id) {
|
|
||||||
if (this.row.id === data.id) {
|
if (this.row.id === data.id) {
|
||||||
if (this.row.obj && data.obj) {
|
if (this.row.obj && data.obj) {
|
||||||
this.row.obj = data.obj;
|
this.row.obj = data.obj;
|
||||||
this.row['cache'][this.column.key] = this.column.key.split('.').reduce((source, key) => source ? source[key] : '', data.obj);
|
this.row['cache'][this.column.key] = this.column.key
|
||||||
|
.split('.')
|
||||||
|
.reduce((source, key) => (source ? source[key] : ''), data.obj);
|
||||||
|
|
||||||
this.updateValue();
|
this.updateValue();
|
||||||
}
|
}
|
||||||
@@ -106,7 +97,7 @@ export class DataTableCellComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected updateValue() {
|
protected updateValue() {
|
||||||
if (this.column && this.column.key && this.row && this.data) {
|
if (this.column?.key && this.row && this.data) {
|
||||||
const value = this.data.getValue(this.row, this.column, this.resolverFn);
|
const value = this.data.getValue(this.row, this.column, this.resolverFn);
|
||||||
|
|
||||||
this.value$.next(value);
|
this.value$.next(value);
|
||||||
|
|||||||
@@ -269,16 +269,12 @@ export class DataTableComponent implements OnInit, AfterContentInit, OnChanges,
|
|||||||
this.keyManager.onKeydown(event);
|
this.keyManager.onKeydown(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(private elementRef: ElementRef,
|
constructor(private elementRef: ElementRef, differs: IterableDiffers, private matIconRegistry: MatIconRegistry, private sanitizer: DomSanitizer) {
|
||||||
differs: IterableDiffers,
|
|
||||||
private matIconRegistry: MatIconRegistry,
|
|
||||||
private sanitizer: DomSanitizer) {
|
|
||||||
if (differs) {
|
if (differs) {
|
||||||
this.differ = differs.find([]).create(null);
|
this.differ = differs.find([]).create(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.click$ = new Observable<DataRowEvent>((observer) => this.clickObserver = observer)
|
this.click$ = new Observable<DataRowEvent>((observer) => (this.clickObserver = observer)).pipe(share());
|
||||||
.pipe(share());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
@@ -298,14 +294,12 @@ export class DataTableComponent implements OnInit, AfterContentInit, OnChanges,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngAfterViewInit() {
|
ngAfterViewInit() {
|
||||||
this.keyManager = new FocusKeyManager(this.rowsList)
|
this.keyManager = new FocusKeyManager(this.rowsList).withWrap().skipPredicate((item) => item.disabled);
|
||||||
.withWrap()
|
|
||||||
.skipPredicate(item => item.disabled);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges) {
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
this.initAndSubscribeClickStream();
|
this.initAndSubscribeClickStream();
|
||||||
if(this.selectedRowId) {
|
if (this.selectedRowId) {
|
||||||
this.setRowAsContextSource();
|
this.setRowAsContextSource();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -358,8 +352,8 @@ export class DataTableComponent implements OnInit, AfterContentInit, OnChanges,
|
|||||||
|
|
||||||
onDropHeaderColumn(event: CdkDragDrop<unknown>): void {
|
onDropHeaderColumn(event: CdkDragDrop<unknown>): void {
|
||||||
const allColumns = this.data.getColumns();
|
const allColumns = this.data.getColumns();
|
||||||
const shownColumns = allColumns.filter(column => !column.isHidden);
|
const shownColumns = allColumns.filter((column) => !column.isHidden);
|
||||||
const hiddenColumns = allColumns.filter(column => column.isHidden);
|
const hiddenColumns = allColumns.filter((column) => column.isHidden);
|
||||||
|
|
||||||
moveItemInArray(shownColumns, event.previousIndex, event.currentIndex);
|
moveItemInArray(shownColumns, event.previousIndex, event.currentIndex);
|
||||||
const allColumnsWithNewOrder = [...shownColumns, ...hiddenColumns];
|
const allColumnsWithNewOrder = [...shownColumns, ...hiddenColumns];
|
||||||
@@ -378,14 +372,14 @@ export class DataTableComponent implements OnInit, AfterContentInit, OnChanges,
|
|||||||
}
|
}
|
||||||
|
|
||||||
isPropertyChanged(property: SimpleChange): boolean {
|
isPropertyChanged(property: SimpleChange): boolean {
|
||||||
return !!(property && property.currentValue);
|
return !!property?.currentValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
convertToRowsData(rows: any []): ObjectDataRow[] {
|
convertToRowsData(rows: any[]): ObjectDataRow[] {
|
||||||
return rows.map((row) => new ObjectDataRow(row, row.isSelected));
|
return rows.map((row) => new ObjectDataRow(row, row.isSelected));
|
||||||
}
|
}
|
||||||
|
|
||||||
convertToColumnsData(columns: any []): ObjectDataColumn[] {
|
convertToColumnsData(columns: any[]): ObjectDataColumn[] {
|
||||||
return columns.map((column) => new ObjectDataColumn(column));
|
return columns.map((column) => new ObjectDataColumn(column));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -398,13 +392,8 @@ export class DataTableComponent implements OnInit, AfterContentInit, OnChanges,
|
|||||||
|
|
||||||
private initAndSubscribeClickStream() {
|
private initAndSubscribeClickStream() {
|
||||||
this.unsubscribeClickStream();
|
this.unsubscribeClickStream();
|
||||||
const singleClickStream = this.click$
|
const singleClickStream = this.click$.pipe(
|
||||||
.pipe(
|
buffer(this.click$.pipe(debounceTime(250))),
|
||||||
buffer(
|
|
||||||
this.click$.pipe(
|
|
||||||
debounceTime(250)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
map((list) => list),
|
map((list) => list),
|
||||||
filter((x) => x.length === 1)
|
filter((x) => x.length === 1)
|
||||||
);
|
);
|
||||||
@@ -423,13 +412,8 @@ export class DataTableComponent implements OnInit, AfterContentInit, OnChanges,
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const multiClickStream = this.click$
|
const multiClickStream = this.click$.pipe(
|
||||||
.pipe(
|
buffer(this.click$.pipe(debounceTime(250))),
|
||||||
buffer(
|
|
||||||
this.click$.pipe(
|
|
||||||
debounceTime(250)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
map((list) => list),
|
map((list) => list),
|
||||||
filter((x) => x.length >= 2)
|
filter((x) => x.length >= 2)
|
||||||
);
|
);
|
||||||
@@ -489,10 +473,7 @@ export class DataTableComponent implements OnInit, AfterContentInit, OnChanges,
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getRuntimeColumns(): any[] {
|
private getRuntimeColumns(): any[] {
|
||||||
return [
|
return [...(this.columns || []), ...this.getSchemaFromHtml()];
|
||||||
...(this.columns || []),
|
|
||||||
...this.getSchemaFromHtml()
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private setTableSchema() {
|
private setTableSchema() {
|
||||||
@@ -511,7 +492,7 @@ export class DataTableComponent implements OnInit, AfterContentInit, OnChanges,
|
|||||||
|
|
||||||
public getSchemaFromHtml(): any {
|
public getSchemaFromHtml(): any {
|
||||||
let schema = [];
|
let schema = [];
|
||||||
if (this.columnList && this.columnList.columns && this.columnList.columns.length > 0) {
|
if (this.columnList?.columns?.length > 0) {
|
||||||
schema = this.columnList.columns.map((c) => c as DataColumn);
|
schema = this.columnList.columns.map((c) => c as DataColumn);
|
||||||
}
|
}
|
||||||
return schema;
|
return schema;
|
||||||
@@ -577,7 +558,7 @@ export class DataTableComponent implements OnInit, AfterContentInit, OnChanges,
|
|||||||
if (this.data) {
|
if (this.data) {
|
||||||
const rows = this.data.getRows();
|
const rows = this.data.getRows();
|
||||||
if (rows && rows.length > 0) {
|
if (rows && rows.length > 0) {
|
||||||
rows.forEach((r) => r.isSelected = false);
|
rows.forEach((r) => (r.isSelected = false));
|
||||||
}
|
}
|
||||||
this.selection = [];
|
this.selection = [];
|
||||||
}
|
}
|
||||||
@@ -722,7 +703,7 @@ export class DataTableComponent implements OnInit, AfterContentInit, OnChanges,
|
|||||||
isIconValue(row: DataRow, col: DataColumn): boolean {
|
isIconValue(row: DataRow, col: DataColumn): boolean {
|
||||||
if (row && col) {
|
if (row && col) {
|
||||||
const value = row.getValue(col.key);
|
const value = row.getValue(col.key);
|
||||||
return value && value.startsWith('material-icons://');
|
return value?.startsWith('material-icons://');
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -809,13 +790,13 @@ export class DataTableComponent implements OnInit, AfterContentInit, OnChanges,
|
|||||||
|
|
||||||
markRowAsContextMenuSource(selectedRow: DataRow): void {
|
markRowAsContextMenuSource(selectedRow: DataRow): void {
|
||||||
this.selectedRowId = selectedRow.id ? selectedRow.id : '';
|
this.selectedRowId = selectedRow.id ? selectedRow.id : '';
|
||||||
this.data.getRows().forEach((row) => row.isContextMenuSource = false);
|
this.data.getRows().forEach((row) => (row.isContextMenuSource = false));
|
||||||
selectedRow.isContextMenuSource = true;
|
selectedRow.isContextMenuSource = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private setRowAsContextSource(): void {
|
private setRowAsContextSource(): void {
|
||||||
const selectedRow = this.data.getRows().find((row) => this.selectedRowId === row.id);
|
const selectedRow = this.data.getRows().find((row) => this.selectedRowId === row.id);
|
||||||
if(selectedRow) {
|
if (selectedRow) {
|
||||||
selectedRow.isContextMenuSource = true;
|
selectedRow.isContextMenuSource = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -845,7 +826,7 @@ export class DataTableComponent implements OnInit, AfterContentInit, OnChanges,
|
|||||||
}
|
}
|
||||||
|
|
||||||
findSelectionById(id: string): number {
|
findSelectionById(id: string): number {
|
||||||
return this.selection.findIndex(selection => selection?.id === id);
|
return this.selection.findIndex((selection) => selection?.id === id);
|
||||||
}
|
}
|
||||||
|
|
||||||
getCellTooltip(row: DataRow, col: DataColumn): string {
|
getCellTooltip(row: DataRow, col: DataColumn): string {
|
||||||
@@ -931,7 +912,7 @@ export class DataTableComponent implements OnInit, AfterContentInit, OnChanges,
|
|||||||
}
|
}
|
||||||
|
|
||||||
getNameColumnValue() {
|
getNameColumnValue() {
|
||||||
return this.data.getColumns().find( (el: any) => el.key.includes('name'));
|
return this.data.getColumns().find((el: any) => el.key.includes('name'));
|
||||||
}
|
}
|
||||||
|
|
||||||
getAutomationValue(row: DataRow): any {
|
getAutomationValue(row: DataRow): any {
|
||||||
@@ -944,35 +925,27 @@ export class DataTableComponent implements OnInit, AfterContentInit, OnChanges,
|
|||||||
return 'ADF-DATATABLE.ACCESSIBILITY.SORT_NONE';
|
return 'ADF-DATATABLE.ACCESSIBILITY.SORT_NONE';
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.isColumnSorted(column, 'asc') ?
|
return this.isColumnSorted(column, 'asc') ? 'ADF-DATATABLE.ACCESSIBILITY.SORT_ASCENDING' : 'ADF-DATATABLE.ACCESSIBILITY.SORT_DESCENDING';
|
||||||
'ADF-DATATABLE.ACCESSIBILITY.SORT_ASCENDING' :
|
|
||||||
'ADF-DATATABLE.ACCESSIBILITY.SORT_DESCENDING';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getSortLiveAnnouncement(column: DataColumn): string {
|
getSortLiveAnnouncement(column: DataColumn): string {
|
||||||
if (!this.isColumnSortActive(column)) {
|
if (!this.isColumnSortActive(column)) {
|
||||||
return 'ADF-DATATABLE.ACCESSIBILITY.SORT_DEFAULT' ;
|
return 'ADF-DATATABLE.ACCESSIBILITY.SORT_DEFAULT';
|
||||||
}
|
}
|
||||||
return this.isColumnSorted(column, 'asc') ?
|
return this.isColumnSorted(column, 'asc')
|
||||||
'ADF-DATATABLE.ACCESSIBILITY.SORT_ASCENDING_BY' :
|
? 'ADF-DATATABLE.ACCESSIBILITY.SORT_ASCENDING_BY'
|
||||||
'ADF-DATATABLE.ACCESSIBILITY.SORT_DESCENDING_BY';
|
: 'ADF-DATATABLE.ACCESSIBILITY.SORT_DESCENDING_BY';
|
||||||
}
|
}
|
||||||
|
|
||||||
private registerDragHandleIcon(): void {
|
private registerDragHandleIcon(): void {
|
||||||
const iconUrl = this.sanitizer.bypassSecurityTrustResourceUrl(
|
const iconUrl = this.sanitizer.bypassSecurityTrustResourceUrl('./assets/images/drag_indicator_24px.svg');
|
||||||
'./assets/images/drag_indicator_24px.svg'
|
|
||||||
);
|
|
||||||
|
|
||||||
this.matIconRegistry.addSvgIconInNamespace(
|
this.matIconRegistry.addSvgIconInNamespace('adf', 'drag_indicator', iconUrl);
|
||||||
'adf',
|
|
||||||
'drag_indicator',
|
|
||||||
iconUrl
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onResizing({ rectangle: { width } }: ResizeEvent, colIndex: number): void {
|
onResizing({ rectangle: { width } }: ResizeEvent, colIndex: number): void {
|
||||||
const timeoutId = setTimeout(() => {
|
const timeoutId = setTimeout(() => {
|
||||||
const allColumns = this.data.getColumns().filter(column => !column.isHidden);
|
const allColumns = this.data.getColumns().filter((column) => !column.isHidden);
|
||||||
allColumns[colIndex].width = width;
|
allColumns[colIndex].width = width;
|
||||||
this.data.setColumns(allColumns);
|
this.data.setColumns(allColumns);
|
||||||
|
|
||||||
@@ -1003,11 +976,9 @@ export class DataTableComponent implements OnInit, AfterContentInit, OnChanges,
|
|||||||
headerContainerColumns.forEach((column: HTMLElement, index: number): void => {
|
headerContainerColumns.forEach((column: HTMLElement, index: number): void => {
|
||||||
if (allColumns[index]) {
|
if (allColumns[index]) {
|
||||||
if (index === 0) {
|
if (index === 0) {
|
||||||
allColumns[index].width =
|
allColumns[index].width = column.clientWidth - parseInt(window.getComputedStyle(column).paddingLeft, 10);
|
||||||
column.clientWidth - parseInt(window.getComputedStyle(column).paddingLeft, 10);
|
} else if (index === headerContainerColumns.length - 1) {
|
||||||
} else if ( index === headerContainerColumns.length - 1) {
|
allColumns[index].width = column.clientWidth - parseInt(window.getComputedStyle(column).paddingRight, 10);
|
||||||
allColumns[index].width =
|
|
||||||
column.clientWidth - parseInt(window.getComputedStyle(column).paddingRight, 10);
|
|
||||||
} else {
|
} else {
|
||||||
allColumns[index].width = column.clientWidth;
|
allColumns[index].width = column.clientWidth;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,29 +38,23 @@ import { DataTableService } from '../../services/datatable.service';
|
|||||||
host: { class: 'adf-datatable-content-cell' }
|
host: { class: 'adf-datatable-content-cell' }
|
||||||
})
|
})
|
||||||
export class JsonCellComponent extends DataTableCellComponent implements OnInit {
|
export class JsonCellComponent extends DataTableCellComponent implements OnInit {
|
||||||
|
|
||||||
/** Editable JSON. */
|
/** Editable JSON. */
|
||||||
@Input()
|
@Input()
|
||||||
editable: boolean = false;
|
editable: boolean = false;
|
||||||
|
|
||||||
constructor(
|
constructor(private dialog: MatDialog, @Optional() dataTableService: DataTableService) {
|
||||||
private dialog: MatDialog,
|
|
||||||
@Optional() dataTableService: DataTableService
|
|
||||||
) {
|
|
||||||
super(dataTableService);
|
super(dataTableService);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
if (this.column && this.column.key && this.row && this.data) {
|
if (this.column?.key && this.row && this.data) {
|
||||||
this.value$.next(this.data.getValue(this.row, this.column, this.resolverFn));
|
this.value$.next(this.data.getValue(this.row, this.column, this.resolverFn));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
view() {
|
view() {
|
||||||
const rawValue: string | any = this.data.getValue(this.row, this.column, this.resolverFn);
|
const rawValue: string | any = this.data.getValue(this.row, this.column, this.resolverFn);
|
||||||
const value = typeof rawValue === 'object'
|
const value = typeof rawValue === 'object' ? JSON.stringify(rawValue || {}, null, 2) : rawValue;
|
||||||
? JSON.stringify(rawValue || {}, null, 2)
|
|
||||||
: rawValue;
|
|
||||||
|
|
||||||
const settings: EditJsonDialogSettings = {
|
const settings: EditJsonDialogSettings = {
|
||||||
title: this.column.title,
|
title: this.column.title,
|
||||||
@@ -68,11 +62,14 @@ export class JsonCellComponent extends DataTableCellComponent implements OnInit
|
|||||||
value
|
value
|
||||||
};
|
};
|
||||||
|
|
||||||
this.dialog.open(EditJsonDialogComponent, {
|
this.dialog
|
||||||
|
.open(EditJsonDialogComponent, {
|
||||||
data: settings,
|
data: settings,
|
||||||
minWidth: '50%',
|
minWidth: '50%',
|
||||||
minHeight: '50%'
|
minHeight: '50%'
|
||||||
}).afterClosed().subscribe((/*result: string*/) => {
|
})
|
||||||
|
.afterClosed()
|
||||||
|
.subscribe((/*result: string*/) => {
|
||||||
if (typeof rawValue === 'object') {
|
if (typeof rawValue === 'object') {
|
||||||
// todo: update cell value as object
|
// todo: update cell value as object
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -15,13 +15,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import { ChangeDetectionStrategy, Component, Input, OnInit, Optional, ViewEncapsulation } from '@angular/core';
|
||||||
ChangeDetectionStrategy,
|
|
||||||
Component,
|
|
||||||
Input,
|
|
||||||
OnInit, Optional,
|
|
||||||
ViewEncapsulation
|
|
||||||
} from '@angular/core';
|
|
||||||
import { DataTableCellComponent } from '../datatable-cell/datatable-cell.component';
|
import { DataTableCellComponent } from '../datatable-cell/datatable-cell.component';
|
||||||
import { DataTableService } from '../../services/datatable.service';
|
import { DataTableService } from '../../services/datatable.service';
|
||||||
|
|
||||||
@@ -48,14 +42,10 @@ export class LocationCellComponent extends DataTableCellComponent implements OnI
|
|||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
if (this.column && this.column.key && this.row && this.data) {
|
if (this.column?.key && this.row && this.data) {
|
||||||
const path: any = this.data.getValue(
|
const path: any = this.data.getValue(this.row, this.column, this.resolverFn);
|
||||||
this.row,
|
|
||||||
this.column,
|
|
||||||
this.resolverFn
|
|
||||||
);
|
|
||||||
|
|
||||||
if (path && path.name && path.elements) {
|
if (path?.name && path.elements) {
|
||||||
this.value$.next(path.name.split('/').pop());
|
this.value$.next(path.name.split('/').pop());
|
||||||
|
|
||||||
if (!this.tooltip) {
|
if (!this.tooltip) {
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ import { ObjectDataColumn } from './object-datacolumn.model';
|
|||||||
@Directive()
|
@Directive()
|
||||||
// eslint-disable-next-line @angular-eslint/directive-class-suffix
|
// eslint-disable-next-line @angular-eslint/directive-class-suffix
|
||||||
export abstract class DataTableSchema<T = unknown> {
|
export abstract class DataTableSchema<T = unknown> {
|
||||||
|
|
||||||
@ContentChild(DataColumnListComponent)
|
@ContentChild(DataColumnListComponent)
|
||||||
columnList: DataColumnListComponent;
|
columnList: DataColumnListComponent;
|
||||||
|
|
||||||
@@ -39,16 +38,14 @@ export abstract class DataTableSchema<T = unknown> {
|
|||||||
protected columnsOrderedByKey: string = 'id';
|
protected columnsOrderedByKey: string = 'id';
|
||||||
|
|
||||||
protected columnsVisibility: { [columnId: string]: boolean } | undefined;
|
protected columnsVisibility: { [columnId: string]: boolean } | undefined;
|
||||||
protected columnsWidths: { [columnId: string]: number} | undefined;
|
protected columnsWidths: { [columnId: string]: number } | undefined;
|
||||||
|
|
||||||
private layoutPresets = {};
|
private layoutPresets = {};
|
||||||
|
|
||||||
private columnsSchemaSubject$ = new ReplaySubject<boolean>();
|
private columnsSchemaSubject$ = new ReplaySubject<boolean>();
|
||||||
isColumnSchemaCreated$ = this.columnsSchemaSubject$.asObservable();
|
isColumnSchemaCreated$ = this.columnsSchemaSubject$.asObservable();
|
||||||
|
|
||||||
constructor(private appConfigService: AppConfigService,
|
constructor(private appConfigService: AppConfigService, protected presetKey: string, protected presetsModel: any) {}
|
||||||
protected presetKey: string,
|
|
||||||
protected presetsModel: any) { }
|
|
||||||
|
|
||||||
public createDatatableSchema(): void {
|
public createDatatableSchema(): void {
|
||||||
this.loadLayoutPresets();
|
this.loadLayoutPresets();
|
||||||
@@ -81,10 +78,7 @@ export abstract class DataTableSchema<T = unknown> {
|
|||||||
const configSchemaColumns = this.getSchemaFromConfig(this.presetColumn);
|
const configSchemaColumns = this.getSchemaFromConfig(this.presetColumn);
|
||||||
const htmlSchemaColumns = this.getSchemaFromHtml(this.columnList);
|
const htmlSchemaColumns = this.getSchemaFromHtml(this.columnList);
|
||||||
|
|
||||||
let customSchemaColumns = [
|
let customSchemaColumns = [...configSchemaColumns, ...htmlSchemaColumns];
|
||||||
...configSchemaColumns,
|
|
||||||
...htmlSchemaColumns
|
|
||||||
];
|
|
||||||
|
|
||||||
if (customSchemaColumns.length === 0) {
|
if (customSchemaColumns.length === 0) {
|
||||||
customSchemaColumns = this.getDefaultLayoutPreset();
|
customSchemaColumns = this.getDefaultLayoutPreset();
|
||||||
@@ -95,18 +89,18 @@ export abstract class DataTableSchema<T = unknown> {
|
|||||||
|
|
||||||
public getSchemaFromHtml(columnList: DataColumnListComponent): DataColumn[] {
|
public getSchemaFromHtml(columnList: DataColumnListComponent): DataColumn[] {
|
||||||
let schema = [];
|
let schema = [];
|
||||||
if (columnList && columnList.columns && columnList.columns.length > 0) {
|
if (columnList?.columns?.length > 0) {
|
||||||
schema = columnList.columns.map((c) => c as DataColumn);
|
schema = columnList.columns.map((c) => c as DataColumn);
|
||||||
}
|
}
|
||||||
return schema;
|
return schema;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getSchemaFromConfig(presetColumn: string): DataColumn[] {
|
public getSchemaFromConfig(presetColumn: string): DataColumn[] {
|
||||||
return presetColumn ? (this.layoutPresets[presetColumn]).map((col) => new ObjectDataColumn(col)) : [];
|
return presetColumn ? this.layoutPresets[presetColumn].map((col) => new ObjectDataColumn(col)) : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
private getDefaultLayoutPreset(): DataColumn[] {
|
private getDefaultLayoutPreset(): DataColumn[] {
|
||||||
return (this.layoutPresets['default']).map((col) => new ObjectDataColumn(col));
|
return this.layoutPresets['default'].map((col) => new ObjectDataColumn(col));
|
||||||
}
|
}
|
||||||
|
|
||||||
public setPresetKey(presetKey: string) {
|
public setPresetKey(presetKey: string) {
|
||||||
@@ -121,8 +115,8 @@ export abstract class DataTableSchema<T = unknown> {
|
|||||||
const defaultColumns = [...columns];
|
const defaultColumns = [...columns];
|
||||||
const columnsWithProperOrder = [];
|
const columnsWithProperOrder = [];
|
||||||
|
|
||||||
(this.columnsOrder ?? []).forEach(columnKey => {
|
(this.columnsOrder ?? []).forEach((columnKey) => {
|
||||||
const originalColumnIndex = defaultColumns.findIndex(defaultColumn => defaultColumn[this.columnsOrderedByKey] === columnKey);
|
const originalColumnIndex = defaultColumns.findIndex((defaultColumn) => defaultColumn[this.columnsOrderedByKey] === columnKey);
|
||||||
|
|
||||||
if (originalColumnIndex > -1) {
|
if (originalColumnIndex > -1) {
|
||||||
columnsWithProperOrder.push(defaultColumns[originalColumnIndex]);
|
columnsWithProperOrder.push(defaultColumns[originalColumnIndex]);
|
||||||
@@ -135,12 +129,10 @@ export abstract class DataTableSchema<T = unknown> {
|
|||||||
|
|
||||||
private setHiddenColumns(columns: DataColumn[]): DataColumn[] {
|
private setHiddenColumns(columns: DataColumn[]): DataColumn[] {
|
||||||
if (this.columnsVisibility) {
|
if (this.columnsVisibility) {
|
||||||
return columns.map(column => {
|
return columns.map((column) => {
|
||||||
const isColumnVisible = this.columnsVisibility[column.id];
|
const isColumnVisible = this.columnsVisibility[column.id];
|
||||||
|
|
||||||
return isColumnVisible === undefined ?
|
return isColumnVisible === undefined ? column : { ...column, isHidden: !isColumnVisible };
|
||||||
column :
|
|
||||||
{ ...column, isHidden: !isColumnVisible };
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,10 +140,10 @@ export abstract class DataTableSchema<T = unknown> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private setColumnsWidth(columns: DataColumn[]): DataColumn[] {
|
private setColumnsWidth(columns: DataColumn[]): DataColumn[] {
|
||||||
if(this.columnsWidths) {
|
if (this.columnsWidths) {
|
||||||
return columns.map(column => {
|
return columns.map((column) => {
|
||||||
const columnWidth = this.columnsWidths[column.id];
|
const columnWidth = this.columnsWidths[column.id];
|
||||||
return columnWidth === undefined ? column : {...column, width:columnWidth};
|
return columnWidth === undefined ? column : { ...column, width: columnWidth };
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return columns;
|
return columns;
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ import { Subject } from 'rxjs';
|
|||||||
|
|
||||||
// Simple implementation of the DataTableAdapter interface.
|
// Simple implementation of the DataTableAdapter interface.
|
||||||
export class ObjectDataTableAdapter implements DataTableAdapter {
|
export class ObjectDataTableAdapter implements DataTableAdapter {
|
||||||
|
|
||||||
private _sorting: DataSorting;
|
private _sorting: DataSorting;
|
||||||
private _rows: DataRow[];
|
private _rows: DataRow[];
|
||||||
private _columns: DataColumn[];
|
private _columns: DataColumn[];
|
||||||
@@ -36,12 +35,12 @@ export class ObjectDataTableAdapter implements DataTableAdapter {
|
|||||||
static generateSchema(data: any[]) {
|
static generateSchema(data: any[]) {
|
||||||
const schema = [];
|
const schema = [];
|
||||||
|
|
||||||
if (data && data.length) {
|
if (data?.length) {
|
||||||
const rowToExaminate = data[0];
|
const rowToExamine = data[0];
|
||||||
|
|
||||||
if (typeof rowToExaminate === 'object') {
|
if (typeof rowToExamine === 'object') {
|
||||||
for (const key in rowToExaminate) {
|
for (const key in rowToExamine) {
|
||||||
if (rowToExaminate.hasOwnProperty(key)) {
|
if (rowToExamine.hasOwnProperty(key)) {
|
||||||
schema.push({
|
schema.push({
|
||||||
type: 'text',
|
type: 'text',
|
||||||
key,
|
key,
|
||||||
@@ -51,7 +50,6 @@ export class ObjectDataTableAdapter implements DataTableAdapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return schema;
|
return schema;
|
||||||
}
|
}
|
||||||
@@ -99,7 +97,7 @@ export class ObjectDataTableAdapter implements DataTableAdapter {
|
|||||||
this._columns = columns || [];
|
this._columns = columns || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
getValue(row: DataRow, col: DataColumn, resolver?: (_row: DataRow, _col: DataColumn) => any ): any {
|
getValue(row: DataRow, col: DataColumn, resolver?: (_row: DataRow, _col: DataColumn) => any): any {
|
||||||
if (!row) {
|
if (!row) {
|
||||||
throw new Error('Row not found');
|
throw new Error('Row not found');
|
||||||
}
|
}
|
||||||
@@ -111,14 +109,7 @@ export class ObjectDataTableAdapter implements DataTableAdapter {
|
|||||||
return resolver(row, col);
|
return resolver(row, col);
|
||||||
}
|
}
|
||||||
|
|
||||||
const value = row.getValue(col.key);
|
return row.getValue(col.key);
|
||||||
|
|
||||||
if (col.type === 'icon') {
|
|
||||||
const icon = row.getValue(col.key);
|
|
||||||
return icon;
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getSorting(): DataSorting {
|
getSorting(): DataSorting {
|
||||||
@@ -128,7 +119,7 @@ export class ObjectDataTableAdapter implements DataTableAdapter {
|
|||||||
setSorting(sorting: DataSorting): void {
|
setSorting(sorting: DataSorting): void {
|
||||||
this._sorting = sorting;
|
this._sorting = sorting;
|
||||||
|
|
||||||
if (sorting && sorting.key) {
|
if (sorting?.key) {
|
||||||
this._rows.sort((a: DataRow, b: DataRow) => {
|
this._rows.sort((a: DataRow, b: DataRow) => {
|
||||||
let left = a.getValue(sorting.key);
|
let left = a.getValue(sorting.key);
|
||||||
let right = b.getValue(sorting.key);
|
let right = b.getValue(sorting.key);
|
||||||
@@ -137,20 +128,18 @@ export class ObjectDataTableAdapter implements DataTableAdapter {
|
|||||||
return sorting.direction === 'asc' ? left - right : right - left;
|
return sorting.direction === 'asc' ? left - right : right - left;
|
||||||
} else {
|
} else {
|
||||||
if (left) {
|
if (left) {
|
||||||
left = (left instanceof Date) ? left.valueOf().toString() : left.toString();
|
left = left instanceof Date ? left.valueOf().toString() : left.toString();
|
||||||
} else {
|
} else {
|
||||||
left = '';
|
left = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (right) {
|
if (right) {
|
||||||
right = (right instanceof Date) ? right.valueOf().toString() : right.toString();
|
right = right instanceof Date ? right.valueOf().toString() : right.toString();
|
||||||
} else {
|
} else {
|
||||||
right = '';
|
right = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
return sorting.direction === 'asc'
|
return sorting.direction === 'asc' ? left.localeCompare(right) : right.localeCompare(left);
|
||||||
? left.localeCompare(right)
|
|
||||||
: right.localeCompare(left);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,91 +61,56 @@ export class ResizableDirective implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
private currentRect: BoundingRectangle;
|
private currentRect: BoundingRectangle;
|
||||||
|
|
||||||
private unlistenMouseDown: () => void;
|
private unlistenMouseDown?: () => void;
|
||||||
|
private unlistenMouseMove?: () => void;
|
||||||
private unlistenMouseMove: () => void;
|
private unlistenMouseUp?: () => void;
|
||||||
|
|
||||||
private unlistenMouseUp: () => void;
|
|
||||||
|
|
||||||
private destroy$ = new Subject<void>();
|
private destroy$ = new Subject<void>();
|
||||||
|
|
||||||
constructor(
|
constructor(private readonly renderer: Renderer2, private readonly element: ElementRef<HTMLElement>, private readonly zone: NgZone) {
|
||||||
private readonly renderer: Renderer2,
|
this.pointerDown = new Observable((observer: Observer<IResizeMouseEvent>) => {
|
||||||
private readonly element: ElementRef<HTMLElement>,
|
|
||||||
private readonly zone: NgZone
|
|
||||||
) {
|
|
||||||
|
|
||||||
this.pointerDown = new Observable(
|
|
||||||
(observer: Observer<IResizeMouseEvent>) => {
|
|
||||||
zone.runOutsideAngular(() => {
|
zone.runOutsideAngular(() => {
|
||||||
this.unlistenMouseDown = renderer.listen(
|
this.unlistenMouseDown = renderer.listen('document', 'mousedown', (event: MouseEvent) => {
|
||||||
'document',
|
|
||||||
'mousedown',
|
|
||||||
(event: MouseEvent) => {
|
|
||||||
observer.next(event);
|
observer.next(event);
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
).pipe(share());
|
}).pipe(share());
|
||||||
|
|
||||||
this.pointerMove = new Observable(
|
this.pointerMove = new Observable((observer: Observer<IResizeMouseEvent>) => {
|
||||||
(observer: Observer<IResizeMouseEvent>) => {
|
|
||||||
zone.runOutsideAngular(() => {
|
zone.runOutsideAngular(() => {
|
||||||
this.unlistenMouseMove = renderer.listen(
|
this.unlistenMouseMove = renderer.listen('document', 'mousemove', (event: MouseEvent) => {
|
||||||
'document',
|
|
||||||
'mousemove',
|
|
||||||
(event: MouseEvent) => {
|
|
||||||
observer.next(event);
|
observer.next(event);
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
).pipe(share());
|
}).pipe(share());
|
||||||
|
|
||||||
this.pointerUp = new Observable(
|
this.pointerUp = new Observable((observer: Observer<IResizeMouseEvent>) => {
|
||||||
(observer: Observer<IResizeMouseEvent>) => {
|
|
||||||
zone.runOutsideAngular(() => {
|
zone.runOutsideAngular(() => {
|
||||||
this.unlistenMouseUp = renderer.listen(
|
this.unlistenMouseUp = renderer.listen('document', 'mouseup', (event: MouseEvent) => {
|
||||||
'document',
|
|
||||||
'mouseup',
|
|
||||||
(event: MouseEvent) => {
|
|
||||||
observer.next(event);
|
observer.next(event);
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
).pipe(share());
|
}).pipe(share());
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
const mousedown$: Observable<IResizeMouseEvent> = merge(this.pointerDown, this.mousedown);
|
const mousedown$ = merge(this.pointerDown, this.mousedown);
|
||||||
|
const mousemove$ = merge(this.pointerMove, this.mousemove);
|
||||||
|
const mouseup$ = merge(this.pointerUp, this.mouseup);
|
||||||
|
|
||||||
const mousemove$: Observable<IResizeMouseEvent> = merge(this.pointerMove, this.mousemove);
|
const mouseDrag: Observable<IResizeMouseEvent | ICoordinateX> = mousedown$
|
||||||
|
|
||||||
const mouseup$: Observable<IResizeMouseEvent> = merge(this.pointerUp, this.mouseup);
|
|
||||||
|
|
||||||
const mousedrag: Observable<IResizeMouseEvent | ICoordinateX> = mousedown$
|
|
||||||
.pipe(
|
.pipe(
|
||||||
mergeMap(({ clientX = 0 }) => merge(
|
mergeMap(({ clientX = 0 }) =>
|
||||||
mousemove$.pipe(take(1)).pipe(map((coords) => [, coords])),
|
merge(mousemove$.pipe(take(1)).pipe(map((coords) => [, coords])), mousemove$.pipe(pairwise()))
|
||||||
mousemove$.pipe(pairwise())
|
|
||||||
)
|
|
||||||
.pipe(
|
.pipe(
|
||||||
map(([previousCoords = {}, newCoords = {}]) =>
|
map(([previousCoords = {}, newCoords = {}]) => [
|
||||||
[
|
|
||||||
{ clientX: previousCoords.clientX - clientX },
|
{ clientX: previousCoords.clientX - clientX },
|
||||||
{ clientX: newCoords.clientX - clientX }
|
{ clientX: newCoords.clientX - clientX }
|
||||||
]
|
])
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
.pipe(filter(([previousCoords = {}, newCoords = {}]) => Math.ceil(previousCoords.clientX) !== Math.ceil(newCoords.clientX)))
|
||||||
.pipe(
|
.pipe(
|
||||||
filter(([previousCoords = {}, newCoords = {}]) =>
|
map(([, newCoords]) => ({
|
||||||
Math.ceil(previousCoords.clientX) !== Math.ceil(newCoords.clientX))
|
|
||||||
)
|
|
||||||
.pipe(
|
|
||||||
map(([, newCoords]) =>
|
|
||||||
({
|
|
||||||
clientX: Math.round(newCoords.clientX)
|
clientX: Math.round(newCoords.clientX)
|
||||||
}))
|
}))
|
||||||
)
|
)
|
||||||
@@ -154,10 +119,8 @@ export class ResizableDirective implements OnInit, OnDestroy {
|
|||||||
)
|
)
|
||||||
.pipe(filter(() => !!this.currentRect));
|
.pipe(filter(() => !!this.currentRect));
|
||||||
|
|
||||||
mousedrag
|
mouseDrag
|
||||||
.pipe(
|
.pipe(map(({ clientX }) => this.getNewBoundingRectangle(this.startingRect, clientX + this.coverPadding)))
|
||||||
map(({ clientX }) => this.getNewBoundingRectangle(this.startingRect, clientX + this.coverPadding))
|
|
||||||
)
|
|
||||||
.subscribe((rectangle: BoundingRectangle) => {
|
.subscribe((rectangle: BoundingRectangle) => {
|
||||||
if (this.resizing.observers.length > 0) {
|
if (this.resizing.observers.length > 0) {
|
||||||
this.zone.run(() => {
|
this.zone.run(() => {
|
||||||
@@ -207,9 +170,9 @@ export class ResizableDirective implements OnInit, OnDestroy {
|
|||||||
this.mousedown.complete();
|
this.mousedown.complete();
|
||||||
this.mousemove.complete();
|
this.mousemove.complete();
|
||||||
this.mouseup.complete();
|
this.mouseup.complete();
|
||||||
this.unlistenMouseDown && this.unlistenMouseDown();
|
this.unlistenMouseDown?.();
|
||||||
this.unlistenMouseMove && this.unlistenMouseMove();
|
this.unlistenMouseMove?.();
|
||||||
this.unlistenMouseUp && this.unlistenMouseUp();
|
this.unlistenMouseUp?.();
|
||||||
this.destroy$.next();
|
this.destroy$.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,7 +189,6 @@ export class ResizableDirective implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getElementRect({ nativeElement }: ElementRef): BoundingRectangle {
|
private getElementRect({ nativeElement }: ElementRef): BoundingRectangle {
|
||||||
|
|
||||||
const { height = 0, width = 0, top = 0, bottom = 0, right = 0, left = 0 }: BoundingRectangle = nativeElement.getBoundingClientRect();
|
const { height = 0, width = 0, top = 0, bottom = 0, right = 0, left = 0 }: BoundingRectangle = nativeElement.getBoundingClientRect();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -28,36 +28,26 @@ export class ResizeHandleDirective implements OnInit, OnDestroy {
|
|||||||
*/
|
*/
|
||||||
@Input() resizableContainer: ResizableDirective;
|
@Input() resizableContainer: ResizableDirective;
|
||||||
|
|
||||||
private unlistenMouseDown: () => void;
|
private unlistenMouseDown?: () => void;
|
||||||
|
private unlistenMouseMove?: () => void;
|
||||||
private unlistenMouseMove: () => void;
|
private unlistenMouseUp?: () => void;
|
||||||
|
|
||||||
private unlistenMouseUp: () => void;
|
|
||||||
|
|
||||||
private destroy$ = new Subject<void>();
|
private destroy$ = new Subject<void>();
|
||||||
|
|
||||||
constructor(
|
constructor(private readonly renderer: Renderer2, private readonly element: ElementRef, private readonly zone: NgZone) {}
|
||||||
private readonly renderer: Renderer2,
|
|
||||||
private readonly element: ElementRef,
|
|
||||||
private readonly zone: NgZone
|
|
||||||
) { }
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.zone.runOutsideAngular(() => {
|
this.zone.runOutsideAngular(() => {
|
||||||
this.unlistenMouseDown = this.renderer.listen(
|
this.unlistenMouseDown = this.renderer.listen(this.element.nativeElement, 'mousedown', (mouseDownEvent: MouseEvent) => {
|
||||||
this.element.nativeElement,
|
|
||||||
'mousedown',
|
|
||||||
(mouseDownEvent: MouseEvent) => {
|
|
||||||
this.onMousedown(mouseDownEvent);
|
this.onMousedown(mouseDownEvent);
|
||||||
}
|
});
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
this.unlistenMouseDown && this.unlistenMouseDown();
|
this.unlistenMouseDown?.();
|
||||||
this.unlistenMouseMove && this.unlistenMouseMove();
|
this.unlistenMouseMove?.();
|
||||||
this.unlistenMouseUp && this.unlistenMouseUp();
|
this.unlistenMouseUp?.();
|
||||||
this.destroy$.next();
|
this.destroy$.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,28 +57,20 @@ export class ResizeHandleDirective implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!this.unlistenMouseMove) {
|
if (!this.unlistenMouseMove) {
|
||||||
this.unlistenMouseMove = this.renderer.listen(
|
this.unlistenMouseMove = this.renderer.listen(this.element.nativeElement, 'mousemove', (mouseMoveEvent: MouseEvent) => {
|
||||||
this.element.nativeElement,
|
|
||||||
'mousemove',
|
|
||||||
(mouseMoveEvent: MouseEvent) => {
|
|
||||||
this.onMousemove(mouseMoveEvent);
|
this.onMousemove(mouseMoveEvent);
|
||||||
}
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.unlistenMouseUp = this.renderer.listen(
|
this.unlistenMouseUp = this.renderer.listen('document', 'mouseup', (mouseUpEvent: MouseEvent) => {
|
||||||
'document',
|
|
||||||
'mouseup',
|
|
||||||
(mouseUpEvent: MouseEvent) => {
|
|
||||||
this.onMouseup(mouseUpEvent);
|
this.onMouseup(mouseUpEvent);
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
this.resizableContainer.mousedown.next({ ...event, resize: true });
|
this.resizableContainer.mousedown.next({ ...event, resize: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
private onMouseup(event: MouseEvent): void {
|
private onMouseup(event: MouseEvent): void {
|
||||||
this.unlistenMouseMove && this.unlistenMouseMove();
|
this.unlistenMouseMove?.();
|
||||||
this.unlistenMouseUp();
|
this.unlistenMouseUp();
|
||||||
this.resizableContainer.mouseup.next(event);
|
this.resizableContainer.mouseup.next(event);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import { FileInfo, FileUtils } from '../common/utils/file-utils';
|
|||||||
selector: '[adf-upload]'
|
selector: '[adf-upload]'
|
||||||
})
|
})
|
||||||
export class UploadDirective implements OnInit, OnDestroy {
|
export class UploadDirective implements OnInit, OnDestroy {
|
||||||
|
|
||||||
/** Enables/disables uploading. */
|
/** Enables/disables uploading. */
|
||||||
@Input('adf-upload')
|
@Input('adf-upload')
|
||||||
enabled: boolean = true;
|
enabled: boolean = true;
|
||||||
@@ -135,7 +134,6 @@ export class UploadDirective implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
onDrop(event: Event) {
|
onDrop(event: Event) {
|
||||||
if (this.isDropMode()) {
|
if (this.isDropMode()) {
|
||||||
|
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
@@ -147,7 +145,6 @@ export class UploadDirective implements OnInit, OnDestroy {
|
|||||||
this.getFilesDropped(dataTransfer).then((files) => {
|
this.getFilesDropped(dataTransfer).then((files) => {
|
||||||
this.onUploadFiles(files);
|
this.onUploadFiles(files);
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -181,10 +178,10 @@ export class UploadDirective implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getDataTransfer(event: Event | any): DataTransfer {
|
getDataTransfer(event: Event | any): DataTransfer {
|
||||||
if (event && event.dataTransfer) {
|
if (event?.dataTransfer) {
|
||||||
return event.dataTransfer;
|
return event.dataTransfer;
|
||||||
}
|
}
|
||||||
if (event && event.originalEvent && event.originalEvent.dataTransfer) {
|
if (event?.originalEvent?.dataTransfer) {
|
||||||
return event.originalEvent.dataTransfer;
|
return event.originalEvent.dataTransfer;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@@ -207,30 +204,34 @@ export class UploadDirective implements OnInit, OnDestroy {
|
|||||||
const item = items[i].webkitGetAsEntry();
|
const item = items[i].webkitGetAsEntry();
|
||||||
if (item) {
|
if (item) {
|
||||||
if (item.isFile) {
|
if (item.isFile) {
|
||||||
iterations.push(Promise.resolve({
|
iterations.push(
|
||||||
|
Promise.resolve({
|
||||||
entry: item,
|
entry: item,
|
||||||
file: items[i].getAsFile(),
|
file: items[i].getAsFile(),
|
||||||
relativeFolder: '/'
|
relativeFolder: '/'
|
||||||
}));
|
})
|
||||||
|
);
|
||||||
} else if (item.isDirectory) {
|
} else if (item.isDirectory) {
|
||||||
iterations.push(new Promise((resolveFolder) => {
|
iterations.push(
|
||||||
|
new Promise((resolveFolder) => {
|
||||||
FileUtils.flatten(item).then((files) => resolveFolder(files));
|
FileUtils.flatten(item).then((files) => resolveFolder(files));
|
||||||
}));
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
iterations.push(Promise.resolve({
|
iterations.push(
|
||||||
|
Promise.resolve({
|
||||||
entry: null,
|
entry: null,
|
||||||
file: items[i].getAsFile(),
|
file: items[i].getAsFile(),
|
||||||
relativeFolder: '/'
|
relativeFolder: '/'
|
||||||
}));
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// safari or FF
|
// safari or FF
|
||||||
const files = FileUtils
|
const files = FileUtils.toFileArray(dataTransfer.files).map((file) => ({
|
||||||
.toFileArray(dataTransfer.files)
|
|
||||||
.map((file) => ({
|
|
||||||
entry: null,
|
entry: null,
|
||||||
file,
|
file,
|
||||||
relativeFolder: '/'
|
relativeFolder: '/'
|
||||||
@@ -255,11 +256,13 @@ export class UploadDirective implements OnInit, OnDestroy {
|
|||||||
if (this.isClickMode()) {
|
if (this.isClickMode()) {
|
||||||
const input = event.currentTarget;
|
const input = event.currentTarget;
|
||||||
const files = FileUtils.toFileArray(input.files);
|
const files = FileUtils.toFileArray(input.files);
|
||||||
this.onUploadFiles(files.map((file) => ({
|
this.onUploadFiles(
|
||||||
|
files.map((file) => ({
|
||||||
entry: null,
|
entry: null,
|
||||||
file,
|
file,
|
||||||
relativeFolder: '/'
|
relativeFolder: '/'
|
||||||
})));
|
}))
|
||||||
|
);
|
||||||
event.target.value = '';
|
event.target.value = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import { ThemePalette } from '@angular/material/core';
|
|||||||
@Directive()
|
@Directive()
|
||||||
// eslint-disable-next-line @angular-eslint/directive-class-suffix
|
// eslint-disable-next-line @angular-eslint/directive-class-suffix
|
||||||
export abstract class FormBaseComponent {
|
export abstract class FormBaseComponent {
|
||||||
|
|
||||||
static SAVE_OUTCOME_ID: string = '$save';
|
static SAVE_OUTCOME_ID: string = '$save';
|
||||||
static COMPLETE_OUTCOME_ID: string = '$complete';
|
static COMPLETE_OUTCOME_ID: string = '$complete';
|
||||||
static START_PROCESS_OUTCOME_ID: string = '$startProcess';
|
static START_PROCESS_OUTCOME_ID: string = '$startProcess';
|
||||||
@@ -137,7 +136,7 @@ export abstract class FormBaseComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
isOutcomeButtonVisible(outcome: FormOutcomeModel, isFormReadOnly: boolean): boolean {
|
isOutcomeButtonVisible(outcome: FormOutcomeModel, isFormReadOnly: boolean): boolean {
|
||||||
if (outcome && outcome.name) {
|
if (outcome?.name) {
|
||||||
if (outcome.name === FormOutcomeModel.COMPLETE_ACTION) {
|
if (outcome.name === FormOutcomeModel.COMPLETE_ACTION) {
|
||||||
return this.showCompleteButton;
|
return this.showCompleteButton;
|
||||||
}
|
}
|
||||||
@@ -162,7 +161,6 @@ export abstract class FormBaseComponent {
|
|||||||
*/
|
*/
|
||||||
onOutcomeClicked(outcome: FormOutcomeModel): boolean {
|
onOutcomeClicked(outcome: FormOutcomeModel): boolean {
|
||||||
if (!this.readOnly && outcome && this.form) {
|
if (!this.readOnly && outcome && this.form) {
|
||||||
|
|
||||||
if (!this.onExecuteOutcome(outcome)) {
|
if (!this.onExecuteOutcome(outcome)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,8 @@
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
Compiler,
|
Compiler,
|
||||||
Component, ComponentFactory,
|
Component,
|
||||||
|
ComponentFactory,
|
||||||
ComponentFactoryResolver,
|
ComponentFactoryResolver,
|
||||||
ComponentRef,
|
ComponentRef,
|
||||||
Input,
|
Input,
|
||||||
@@ -39,19 +40,20 @@ declare const adf: any;
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'adf-form-field',
|
selector: 'adf-form-field',
|
||||||
template: `
|
template: `
|
||||||
<div [id]="'field-'+field?.id+'-container'"
|
<div
|
||||||
|
[id]="'field-' + field?.id + '-container'"
|
||||||
[style.visibility]="!field?.isVisible ? 'hidden' : 'visible'"
|
[style.visibility]="!field?.isVisible ? 'hidden' : 'visible'"
|
||||||
[style.display]="!field?.isVisible ? 'none' : 'block'"
|
[style.display]="!field?.isVisible ? 'none' : 'block'"
|
||||||
[class.adf-focus]="focus"
|
[class.adf-focus]="focus"
|
||||||
(focusin)="focusToggle()"
|
(focusin)="focusToggle()"
|
||||||
(focusout)="focusToggle()">
|
(focusout)="focusToggle()"
|
||||||
|
>
|
||||||
<div #container></div>
|
<div #container></div>
|
||||||
</div>
|
</div>
|
||||||
`,
|
`,
|
||||||
encapsulation: ViewEncapsulation.None
|
encapsulation: ViewEncapsulation.None
|
||||||
})
|
})
|
||||||
export class FormFieldComponent implements OnInit, OnDestroy {
|
export class FormFieldComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
@ViewChild('container', { read: ViewContainerRef, static: true })
|
@ViewChild('container', { read: ViewContainerRef, static: true })
|
||||||
container: ViewContainerRef;
|
container: ViewContainerRef;
|
||||||
|
|
||||||
@@ -67,11 +69,12 @@ export class FormFieldComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
focus: boolean = false;
|
focus: boolean = false;
|
||||||
|
|
||||||
constructor(private formRenderingService: FormRenderingService,
|
constructor(
|
||||||
|
private formRenderingService: FormRenderingService,
|
||||||
private componentFactoryResolver: ComponentFactoryResolver,
|
private componentFactoryResolver: ComponentFactoryResolver,
|
||||||
private visibilityService: WidgetVisibilityService,
|
private visibilityService: WidgetVisibilityService,
|
||||||
private compiler: Compiler) {
|
private compiler: Compiler
|
||||||
}
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
const w: any = window;
|
const w: any = window;
|
||||||
@@ -114,9 +117,9 @@ export class FormFieldComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getField(): FormFieldModel {
|
private getField(): FormFieldModel {
|
||||||
if (this.field && this.field.params) {
|
if (this.field?.params) {
|
||||||
const wrappedField = this.field.params.field;
|
const wrappedField = this.field.params.field;
|
||||||
if (wrappedField && wrappedField.type) {
|
if (wrappedField?.type) {
|
||||||
return wrappedField as FormFieldModel;
|
return wrappedField as FormFieldModel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -124,7 +127,7 @@ export class FormFieldComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private hasController(type: string): boolean {
|
private hasController(type: string): boolean {
|
||||||
return (adf && adf.components && adf.components[type]);
|
return adf?.components?.[type];
|
||||||
}
|
}
|
||||||
|
|
||||||
private getComponentFactorySync(type: string, template: string): ComponentFactory<any> {
|
private getComponentFactorySync(type: string, template: string): ComponentFactory<any> {
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ import { FormService } from '../services/form.service';
|
|||||||
encapsulation: ViewEncapsulation.None
|
encapsulation: ViewEncapsulation.None
|
||||||
})
|
})
|
||||||
export class FormRendererComponent<T> implements OnChanges, OnDestroy {
|
export class FormRendererComponent<T> implements OnChanges, OnDestroy {
|
||||||
|
|
||||||
/** Toggle debug options. */
|
/** Toggle debug options. */
|
||||||
@Input()
|
@Input()
|
||||||
showDebugButton: boolean = false;
|
showDebugButton: boolean = false;
|
||||||
@@ -47,8 +46,7 @@ export class FormRendererComponent<T> implements OnChanges, OnDestroy {
|
|||||||
|
|
||||||
fields: FormFieldModel[];
|
fields: FormFieldModel[];
|
||||||
|
|
||||||
constructor(public formService: FormService, private formRulesManager: FormRulesManager<T>) {
|
constructor(public formService: FormService, private formRulesManager: FormRulesManager<T>) {}
|
||||||
}
|
|
||||||
|
|
||||||
ngOnChanges(): void {
|
ngOnChanges(): void {
|
||||||
this.formRulesManager.initialize(this.formDefinition);
|
this.formRulesManager.initialize(this.formDefinition);
|
||||||
@@ -67,15 +65,15 @@ export class FormRendererComponent<T> implements OnChanges, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onExpanderClicked(content: ContainerModel) {
|
onExpanderClicked(content: ContainerModel) {
|
||||||
if (content && content.isCollapsible()) {
|
if (content?.isCollapsible()) {
|
||||||
content.isExpanded = !content.isExpanded;
|
content.isExpanded = !content.isExpanded;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getNumberOfColumns(content: ContainerModel): number {
|
getNumberOfColumns(content: ContainerModel): number {
|
||||||
return (content.json?.numberOfColumns || 1) > (content.columns?.length || 1) ?
|
return (content.json?.numberOfColumns || 1) > (content.columns?.length || 1)
|
||||||
(content.json?.numberOfColumns || 1) :
|
? content.json?.numberOfColumns || 1
|
||||||
(content.columns?.length || 1);
|
: content.columns?.length || 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -106,7 +104,8 @@ export class FormRendererComponent<T> implements OnChanges, OnDestroy {
|
|||||||
let maxFieldSize = 0;
|
let maxFieldSize = 0;
|
||||||
if (content?.columns?.length > 0) {
|
if (content?.columns?.length > 0) {
|
||||||
maxFieldSize = content?.columns?.reduce((prevColumn, currentColumn) =>
|
maxFieldSize = content?.columns?.reduce((prevColumn, currentColumn) =>
|
||||||
currentColumn.fields.length > prevColumn?.fields?.length ? currentColumn : prevColumn)?.fields?.length;
|
currentColumn.fields.length > prevColumn?.fields?.length ? currentColumn : prevColumn
|
||||||
|
)?.fields?.length;
|
||||||
}
|
}
|
||||||
return maxFieldSize;
|
return maxFieldSize;
|
||||||
}
|
}
|
||||||
@@ -120,5 +119,4 @@ export class FormRendererComponent<T> implements OnChanges, OnDestroy {
|
|||||||
const colspan = container ? container.field.colspan : 1;
|
const colspan = container ? container.field.colspan : 1;
|
||||||
return (100 / container.field.numberOfColumns) * colspan + '';
|
return (100 / container.field.numberOfColumns) * colspan + '';
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* eslint-disable @angular-eslint/component-selector */
|
/* eslint-disable @angular-eslint/component-selector */
|
||||||
|
|
||||||
import { Component, OnInit, ViewEncapsulation, InjectionToken, Inject, Optional } from '@angular/core';
|
import { Component, OnInit, ViewEncapsulation, InjectionToken, Inject, Optional } from '@angular/core';
|
||||||
import { FormService } from '../../../services/form.service';
|
import { FormService } from '../../../services/form.service';
|
||||||
@@ -45,7 +45,6 @@ export const ADF_AMOUNT_SETTINGS = new InjectionToken<AmountWidgetSettings>('adf
|
|||||||
encapsulation: ViewEncapsulation.None
|
encapsulation: ViewEncapsulation.None
|
||||||
})
|
})
|
||||||
export class AmountWidgetComponent extends WidgetComponent implements OnInit {
|
export class AmountWidgetComponent extends WidgetComponent implements OnInit {
|
||||||
|
|
||||||
static DEFAULT_CURRENCY: string = '$';
|
static DEFAULT_CURRENCY: string = '$';
|
||||||
private showPlaceholder = true;
|
private showPlaceholder = true;
|
||||||
|
|
||||||
@@ -71,9 +70,8 @@ export class AmountWidgetComponent extends WidgetComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.field.readOnly) {
|
if (this.field.readOnly) {
|
||||||
this.showPlaceholder = this.settings && this.settings.showReadonlyPlaceholder;
|
this.showPlaceholder = this.settings?.showReadonlyPlaceholder;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,10 +15,9 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* eslint-disable @angular-eslint/component-selector */
|
/* eslint-disable @angular-eslint/component-selector */
|
||||||
|
|
||||||
export class ContentLinkModel {
|
|
||||||
|
|
||||||
|
export class ContentLinkModel {
|
||||||
contentAvailable: boolean;
|
contentAvailable: boolean;
|
||||||
created: Date;
|
created: Date;
|
||||||
createdBy: any;
|
createdBy: any;
|
||||||
@@ -36,18 +35,18 @@
|
|||||||
thumbnailStatus: string;
|
thumbnailStatus: string;
|
||||||
|
|
||||||
constructor(obj?: any) {
|
constructor(obj?: any) {
|
||||||
this.contentAvailable = obj && obj.contentAvailable;
|
this.contentAvailable = obj?.contentAvailable;
|
||||||
this.created = obj && obj.created;
|
this.created = obj?.created;
|
||||||
this.createdBy = obj && obj.createdBy || {};
|
this.createdBy = obj?.createdBy || {};
|
||||||
this.id = obj && obj.id;
|
this.id = obj?.id;
|
||||||
this.link = obj && obj.link;
|
this.link = obj?.link;
|
||||||
this.mimeType = obj && obj.mimeType;
|
this.mimeType = obj?.mimeType;
|
||||||
this.name = obj && obj.name;
|
this.name = obj?.name;
|
||||||
this.previewStatus = obj && obj.previewStatus;
|
this.previewStatus = obj?.previewStatus;
|
||||||
this.relatedContent = obj && obj.relatedContent;
|
this.relatedContent = obj?.relatedContent;
|
||||||
this.simpleType = obj && obj.simpleType;
|
this.simpleType = obj?.simpleType;
|
||||||
this.thumbnailStatus = obj && obj.thumbnailStatus;
|
this.thumbnailStatus = obj?.thumbnailStatus;
|
||||||
this.nodeId = obj && obj.nodeId;
|
this.nodeId = obj?.nodeId;
|
||||||
}
|
}
|
||||||
|
|
||||||
hasPreviewStatus(): boolean {
|
hasPreviewStatus(): boolean {
|
||||||
|
|||||||
@@ -18,12 +18,11 @@
|
|||||||
/* eslint-disable @angular-eslint/component-selector */
|
/* eslint-disable @angular-eslint/component-selector */
|
||||||
|
|
||||||
export class ErrorMessageModel {
|
export class ErrorMessageModel {
|
||||||
|
|
||||||
message: string = '';
|
message: string = '';
|
||||||
attributes: Map<string, string> = null;
|
attributes: Map<string, string> = null;
|
||||||
|
|
||||||
constructor(obj?: any) {
|
constructor(obj?: any) {
|
||||||
this.message = obj && obj.message ? obj.message : '';
|
this.message = obj?.message || '';
|
||||||
this.attributes = new Map();
|
this.attributes = new Map();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ import { DataColumn } from '../../../../datatable/data/data-column.model';
|
|||||||
|
|
||||||
// Maps to FormFieldRepresentation
|
// Maps to FormFieldRepresentation
|
||||||
export class FormFieldModel extends FormWidgetModel {
|
export class FormFieldModel extends FormWidgetModel {
|
||||||
|
|
||||||
private _value: string;
|
private _value: string;
|
||||||
private _readOnly: boolean = false;
|
private _readOnly: boolean = false;
|
||||||
private _isValid: boolean = true;
|
private _isValid: boolean = true;
|
||||||
@@ -105,7 +104,7 @@ export class FormFieldModel extends FormWidgetModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get readOnly(): boolean {
|
get readOnly(): boolean {
|
||||||
if (this.form && this.form.readOnly) {
|
if (this.form?.readOnly) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return this._readOnly;
|
return this._readOnly;
|
||||||
@@ -206,7 +205,7 @@ export class FormFieldModel extends FormWidgetModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (FormFieldTypes.isReadOnlyType(this.type)) {
|
if (FormFieldTypes.isReadOnlyType(this.type)) {
|
||||||
if (this.params && this.params.field) {
|
if (this.params?.field) {
|
||||||
this.setValueForReadonlyType(form);
|
this.setValueForReadonlyType(form);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -241,9 +240,7 @@ export class FormFieldModel extends FormWidgetModel {
|
|||||||
|
|
||||||
private getDefaultDateFormat(jsonField: any): string {
|
private getDefaultDateFormat(jsonField: any): string {
|
||||||
let originalType = jsonField.type;
|
let originalType = jsonField.type;
|
||||||
if (FormFieldTypes.isReadOnlyType(jsonField.type) &&
|
if (FormFieldTypes.isReadOnlyType(jsonField.type) && jsonField.params && jsonField.params.field) {
|
||||||
jsonField.params &&
|
|
||||||
jsonField.params.field) {
|
|
||||||
originalType = jsonField.params.field.type;
|
originalType = jsonField.params.field.type;
|
||||||
}
|
}
|
||||||
return originalType === FormFieldTypes.DATETIME ? this.defaultDateTimeFormat : this.defaultDateFormat;
|
return originalType === FormFieldTypes.DATETIME ? this.defaultDateTimeFormat : this.defaultDateFormat;
|
||||||
@@ -301,7 +298,6 @@ export class FormFieldModel extends FormWidgetModel {
|
|||||||
but saving back as object: { id: <id>, name: <name> }
|
but saving back as object: { id: <id>, name: <name> }
|
||||||
*/
|
*/
|
||||||
if (json.type === FormFieldTypes.DROPDOWN) {
|
if (json.type === FormFieldTypes.DROPDOWN) {
|
||||||
|
|
||||||
if (json.options) {
|
if (json.options) {
|
||||||
if (json.hasEmptyValue) {
|
if (json.hasEmptyValue) {
|
||||||
const emptyOption = json.options[0];
|
const emptyOption = json.options[0];
|
||||||
@@ -328,8 +324,9 @@ export class FormFieldModel extends FormWidgetModel {
|
|||||||
// Activiti has a bug with default radio button value where initial selection passed as `name` value
|
// Activiti has a bug with default radio button value where initial selection passed as `name` value
|
||||||
// so try resolving current one with a fallback to first entry via name or id
|
// so try resolving current one with a fallback to first entry via name or id
|
||||||
// TODO: needs to be reported and fixed at Activiti side
|
// TODO: needs to be reported and fixed at Activiti side
|
||||||
const entry: FormFieldOption[] = this.options.filter((opt) =>
|
const entry: FormFieldOption[] = this.options.filter(
|
||||||
opt.id === value || opt.name === value || (value && (opt.id === value.id || opt.name === value.name)));
|
(opt) => opt.id === value || opt.name === value || (value && (opt.id === value.id || opt.name === value.name))
|
||||||
|
);
|
||||||
if (entry.length > 0) {
|
if (entry.length > 0) {
|
||||||
value = entry[0].id;
|
value = entry[0].id;
|
||||||
}
|
}
|
||||||
@@ -347,7 +344,7 @@ export class FormFieldModel extends FormWidgetModel {
|
|||||||
} else {
|
} else {
|
||||||
dateValue = this.isDateTimeField(json) ? moment.utc(value, 'YYYY-MM-DD hh:mm A') : moment.utc(value.split('T')[0], 'YYYY-M-D');
|
dateValue = this.isDateTimeField(json) ? moment.utc(value, 'YYYY-MM-DD hh:mm A') : moment.utc(value.split('T')[0], 'YYYY-M-D');
|
||||||
}
|
}
|
||||||
if (dateValue && dateValue.isValid()) {
|
if (dateValue?.isValid()) {
|
||||||
value = dateValue.utc().format(this.dateDisplayFormat);
|
value = dateValue.utc().format(this.dateDisplayFormat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -367,7 +364,6 @@ export class FormFieldModel extends FormWidgetModel {
|
|||||||
|
|
||||||
switch (this.type) {
|
switch (this.type) {
|
||||||
case FormFieldTypes.DROPDOWN:
|
case FormFieldTypes.DROPDOWN:
|
||||||
|
|
||||||
if (!this.value) {
|
if (!this.value) {
|
||||||
this.form.values[this.id] = null;
|
this.form.values[this.id] = null;
|
||||||
break;
|
break;
|
||||||
@@ -422,7 +418,7 @@ export class FormFieldModel extends FormWidgetModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const dateValue = moment(this.value, this.dateDisplayFormat, true);
|
const dateValue = moment(this.value, this.dateDisplayFormat, true);
|
||||||
if (dateValue && dateValue.isValid()) {
|
if (dateValue?.isValid()) {
|
||||||
this.form.values[this.id] = `${dateValue.format('YYYY-MM-DD')}T00:00:00.000Z`;
|
this.form.values[this.id] = `${dateValue.format('YYYY-MM-DD')}T00:00:00.000Z`;
|
||||||
} else {
|
} else {
|
||||||
this.form.values[this.id] = null;
|
this.form.values[this.id] = null;
|
||||||
@@ -435,7 +431,7 @@ export class FormFieldModel extends FormWidgetModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const dateTimeValue = moment.utc(this.value, this.dateDisplayFormat, true);
|
const dateTimeValue = moment.utc(this.value, this.dateDisplayFormat, true);
|
||||||
if (dateTimeValue && dateTimeValue.isValid()) {
|
if (dateTimeValue?.isValid()) {
|
||||||
/* cspell:disable-next-line */
|
/* cspell:disable-next-line */
|
||||||
this.form.values[this.id] = `${dateTimeValue.utc().format('YYYY-MM-DDTHH:mm:ss')}.000Z`;
|
this.form.values[this.id] = `${dateTimeValue.utc().format('YYYY-MM-DDTHH:mm:ss')}.000Z`;
|
||||||
} else {
|
} else {
|
||||||
@@ -450,7 +446,7 @@ export class FormFieldModel extends FormWidgetModel {
|
|||||||
this.form.values[this.id] = this.enableFractions ? parseFloat(this.value) : parseInt(this.value, 10);
|
this.form.values[this.id] = this.enableFractions ? parseFloat(this.value) : parseInt(this.value, 10);
|
||||||
break;
|
break;
|
||||||
case FormFieldTypes.BOOLEAN:
|
case FormFieldTypes.BOOLEAN:
|
||||||
this.form.values[this.id] = (this.value !== null && this.value !== undefined) ? this.value : false;
|
this.form.values[this.id] = this.value !== null && this.value !== undefined ? this.value : false;
|
||||||
break;
|
break;
|
||||||
case FormFieldTypes.PEOPLE:
|
case FormFieldTypes.PEOPLE:
|
||||||
this.form.values[this.id] = this.value ? this.value : null;
|
this.form.values[this.id] = this.value ? this.value : null;
|
||||||
@@ -482,28 +478,18 @@ export class FormFieldModel extends FormWidgetModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
hasOptions() {
|
hasOptions() {
|
||||||
return this.options && this.options.length > 0;
|
return this.options?.length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private isDateField(json: any) {
|
private isDateField(json: any) {
|
||||||
return (json.params &&
|
return json.params?.field?.type === FormFieldTypes.DATE || json.type === FormFieldTypes.DATE;
|
||||||
json.params.field &&
|
|
||||||
json.params.field.type === FormFieldTypes.DATE) ||
|
|
||||||
json.type === FormFieldTypes.DATE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private isDateTimeField(json: any): boolean {
|
private isDateTimeField(json: any): boolean {
|
||||||
return (json.params &&
|
return json.params?.field?.type === FormFieldTypes.DATETIME || json.type === FormFieldTypes.DATETIME;
|
||||||
json.params.field &&
|
|
||||||
json.params.field.type === FormFieldTypes.DATETIME) ||
|
|
||||||
json.type === FormFieldTypes.DATETIME;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private isCheckboxField(json: any): boolean {
|
private isCheckboxField(json: any): boolean {
|
||||||
return (json.params &&
|
return json.params?.field?.type === FormFieldTypes.BOOLEAN || json.type === FormFieldTypes.BOOLEAN;
|
||||||
json.params.field &&
|
|
||||||
json.params.field.type === FormFieldTypes.BOOLEAN) ||
|
|
||||||
json.type === FormFieldTypes.BOOLEAN;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,7 +59,6 @@ export interface FormRepresentationModel {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
export class FormModel implements ProcessFormModel {
|
export class FormModel implements ProcessFormModel {
|
||||||
|
|
||||||
static UNSET_TASK_NAME: string = 'Nameless task';
|
static UNSET_TASK_NAME: string = 'Nameless task';
|
||||||
static SAVE_OUTCOME: string = '$save';
|
static SAVE_OUTCOME: string = '$save';
|
||||||
static COMPLETE_OUTCOME: string = '$complete';
|
static COMPLETE_OUTCOME: string = '$complete';
|
||||||
@@ -112,7 +111,7 @@ export class FormModel implements ProcessFormModel {
|
|||||||
this.className = json.className || '';
|
this.className = json.className || '';
|
||||||
this.variables = json.variables || json.formDefinition?.variables || [];
|
this.variables = json.variables || json.formDefinition?.variables || [];
|
||||||
this.processVariables = json.processVariables || [];
|
this.processVariables = json.processVariables || [];
|
||||||
this.enableFixedSpace = enableFixedSpace ? true : false;
|
this.enableFixedSpace = enableFixedSpace;
|
||||||
this.confirmMessage = json.confirmMessage || {};
|
this.confirmMessage = json.confirmMessage || {};
|
||||||
|
|
||||||
this.tabs = (json.tabs || []).map((tabJson) => new TabModel(this, tabJson));
|
this.tabs = (json.tabs || []).map((tabJson) => new TabModel(this, tabJson));
|
||||||
@@ -161,7 +160,6 @@ export class FormModel implements ProcessFormModel {
|
|||||||
validateFormEvent.errorsField = errorsField;
|
validateFormEvent.errorsField = errorsField;
|
||||||
this.formService.validateForm.next(validateFormEvent);
|
this.formService.validateForm.next(validateFormEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -203,7 +201,7 @@ export class FormModel implements ProcessFormModel {
|
|||||||
|
|
||||||
if (json.fields) {
|
if (json.fields) {
|
||||||
fields = json.fields;
|
fields = json.fields;
|
||||||
} else if (json.formDefinition && json.formDefinition.fields) {
|
} else if (json.formDefinition?.fields) {
|
||||||
fields = json.formDefinition.fields;
|
fields = json.formDefinition.fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,11 +251,7 @@ export class FormModel implements ProcessFormModel {
|
|||||||
*/
|
*/
|
||||||
getFormVariable(identifier: string): FormVariableModel {
|
getFormVariable(identifier: string): FormVariableModel {
|
||||||
if (identifier) {
|
if (identifier) {
|
||||||
return this.variables.find(
|
return this.variables.find((variable) => variable.name === identifier || variable.id === identifier);
|
||||||
variable =>
|
|
||||||
variable.name === identifier ||
|
|
||||||
variable.id === identifier
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@@ -271,7 +265,7 @@ export class FormModel implements ProcessFormModel {
|
|||||||
getDefaultFormVariableValue(identifier: string): any {
|
getDefaultFormVariableValue(identifier: string): any {
|
||||||
const variable = this.getFormVariable(identifier);
|
const variable = this.getFormVariable(identifier);
|
||||||
|
|
||||||
if (variable && variable.hasOwnProperty('value')) {
|
if (variable?.hasOwnProperty('value')) {
|
||||||
return this.parseValue(variable.type, variable.value);
|
return this.parseValue(variable.type, variable.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,11 +282,9 @@ export class FormModel implements ProcessFormModel {
|
|||||||
getProcessVariableValue(name: string): any {
|
getProcessVariableValue(name: string): any {
|
||||||
let value;
|
let value;
|
||||||
if (this.processVariables?.length) {
|
if (this.processVariables?.length) {
|
||||||
const names = [`variables.${ name }`, name];
|
const names = [`variables.${name}`, name];
|
||||||
|
|
||||||
const processVariable = this.processVariables.find(
|
const processVariable = this.processVariables.find((entry) => names.includes(entry.name));
|
||||||
entry => names.includes(entry.name)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (processVariable) {
|
if (processVariable) {
|
||||||
value = this.parseValue(processVariable.type, processVariable.value);
|
value = this.parseValue(processVariable.type, processVariable.value);
|
||||||
@@ -310,13 +302,9 @@ export class FormModel implements ProcessFormModel {
|
|||||||
if (type && value) {
|
if (type && value) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'date':
|
case 'date':
|
||||||
return value
|
return value ? `${value}T00:00:00.000Z` : undefined;
|
||||||
? `${value}T00:00:00.000Z`
|
|
||||||
: undefined;
|
|
||||||
case 'boolean':
|
case 'boolean':
|
||||||
return typeof value === 'string'
|
return typeof value === 'string' ? JSON.parse(value) : value;
|
||||||
? JSON.parse(value)
|
|
||||||
: value;
|
|
||||||
default:
|
default:
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
@@ -356,7 +344,7 @@ export class FormModel implements ProcessFormModel {
|
|||||||
field.field.columns.forEach((column) => {
|
field.field.columns.forEach((column) => {
|
||||||
formFieldModel.push(...column.fields);
|
formFieldModel.push(...column.fields);
|
||||||
});
|
});
|
||||||
}else{
|
} else {
|
||||||
formFieldModel.push(field);
|
formFieldModel.push(field);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -387,20 +375,14 @@ export class FormModel implements ProcessFormModel {
|
|||||||
isSystem: true
|
isSystem: true
|
||||||
});
|
});
|
||||||
|
|
||||||
const customOutcomes = (this.json.outcomes || []).map(
|
const customOutcomes = (this.json.outcomes || []).map((obj) => new FormOutcomeModel(this, obj));
|
||||||
(obj) => new FormOutcomeModel(this, obj)
|
|
||||||
);
|
|
||||||
|
|
||||||
this.outcomes = [saveOutcome].concat(
|
this.outcomes = [saveOutcome].concat(customOutcomes.length > 0 ? customOutcomes : [completeOutcome, startProcessOutcome]);
|
||||||
customOutcomes.length > 0
|
|
||||||
? customOutcomes
|
|
||||||
: [completeOutcome, startProcessOutcome]
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addValuesNotPresent(valuesToSetIfNotPresent: FormValues) {
|
addValuesNotPresent(valuesToSetIfNotPresent: FormValues) {
|
||||||
this.fieldsCache.forEach(field => {
|
this.fieldsCache.forEach((field) => {
|
||||||
if (valuesToSetIfNotPresent[field.id] && (!this.values[field.id] || this.isValidDropDown(field.id))) {
|
if (valuesToSetIfNotPresent[field.id] && (!this.values[field.id] || this.isValidDropDown(field.id))) {
|
||||||
this.values[field.id] = valuesToSetIfNotPresent[field.id];
|
this.values[field.id] = valuesToSetIfNotPresent[field.id];
|
||||||
field.json.value = this.values[field.id];
|
field.json.value = this.values[field.id];
|
||||||
@@ -423,11 +405,11 @@ export class FormModel implements ProcessFormModel {
|
|||||||
setNodeIdValueForViewersLinkedToUploadWidget(linkedUploadWidgetContentSelected: UploadWidgetContentLinkModel) {
|
setNodeIdValueForViewersLinkedToUploadWidget(linkedUploadWidgetContentSelected: UploadWidgetContentLinkModel) {
|
||||||
const linkedWidgetType = linkedUploadWidgetContentSelected?.options?.linkedWidgetType ?? 'uploadWidget';
|
const linkedWidgetType = linkedUploadWidgetContentSelected?.options?.linkedWidgetType ?? 'uploadWidget';
|
||||||
|
|
||||||
const subscribedViewers = this.fieldsCache.filter(field =>
|
const subscribedViewers = this.fieldsCache.filter(
|
||||||
linkedUploadWidgetContentSelected.uploadWidgetId === field.params[linkedWidgetType]
|
(field) => linkedUploadWidgetContentSelected.uploadWidgetId === field.params[linkedWidgetType]
|
||||||
);
|
);
|
||||||
|
|
||||||
subscribedViewers.forEach(viewer => {
|
subscribedViewers.forEach((viewer) => {
|
||||||
this.values[viewer.id] = linkedUploadWidgetContentSelected.id;
|
this.values[viewer.id] = linkedUploadWidgetContentSelected.id;
|
||||||
viewer.json.value = this.values[viewer.id];
|
viewer.json.value = this.values[viewer.id];
|
||||||
viewer.value = viewer.parseValue(viewer.json);
|
viewer.value = viewer.parseValue(viewer.json);
|
||||||
|
|||||||
@@ -29,11 +29,8 @@ import { WidgetComponent } from '../widget.component';
|
|||||||
styleUrls: ['./error.component.scss'],
|
styleUrls: ['./error.component.scss'],
|
||||||
animations: [
|
animations: [
|
||||||
trigger('transitionMessages', [
|
trigger('transitionMessages', [
|
||||||
state('enter', style({opacity: 1, transform: 'translateY(0%)'})),
|
state('enter', style({ opacity: 1, transform: 'translateY(0%)' })),
|
||||||
transition('void => enter', [
|
transition('void => enter', [style({ opacity: 0, transform: 'translateY(-100%)' }), animate('300ms cubic-bezier(0.55, 0, 0.55, 0.2)')])
|
||||||
style({opacity: 0, transform: 'translateY(-100%)'}),
|
|
||||||
animate('300ms cubic-bezier(0.55, 0, 0.55, 0.2)')
|
|
||||||
])
|
|
||||||
])
|
])
|
||||||
],
|
],
|
||||||
host: {
|
host: {
|
||||||
@@ -50,7 +47,6 @@ import { WidgetComponent } from '../widget.component';
|
|||||||
encapsulation: ViewEncapsulation.None
|
encapsulation: ViewEncapsulation.None
|
||||||
})
|
})
|
||||||
export class ErrorWidgetComponent extends WidgetComponent implements OnChanges {
|
export class ErrorWidgetComponent extends WidgetComponent implements OnChanges {
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
error: ErrorMessageModel;
|
error: ErrorMessageModel;
|
||||||
|
|
||||||
@@ -70,7 +66,7 @@ export class ErrorWidgetComponent extends WidgetComponent implements OnChanges {
|
|||||||
this.required = changes.required.currentValue;
|
this.required = changes.required.currentValue;
|
||||||
this.subscriptAnimationState = 'enter';
|
this.subscriptAnimationState = 'enter';
|
||||||
}
|
}
|
||||||
if (changes['error'] && changes['error'].currentValue) {
|
if (changes['error']?.currentValue) {
|
||||||
if (changes.error.currentValue.isActive()) {
|
if (changes.error.currentValue.isActive()) {
|
||||||
this.error = changes.error.currentValue;
|
this.error = changes.error.currentValue;
|
||||||
this.translateParameters = this.error.getAttributesAsJsonObj();
|
this.translateParameters = this.error.getAttributesAsJsonObj();
|
||||||
|
|||||||
@@ -15,18 +15,9 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* eslint-disable @angular-eslint/component-selector, @typescript-eslint/no-use-before-define, @angular-eslint/no-input-rename */
|
/* eslint-disable @angular-eslint/component-selector, @typescript-eslint/no-use-before-define, @angular-eslint/no-input-rename */
|
||||||
|
|
||||||
import {
|
import { Directive, ElementRef, forwardRef, HostListener, Input, OnChanges, Renderer2, SimpleChanges } from '@angular/core';
|
||||||
Directive,
|
|
||||||
ElementRef,
|
|
||||||
forwardRef,
|
|
||||||
HostListener,
|
|
||||||
Input,
|
|
||||||
OnChanges,
|
|
||||||
Renderer2,
|
|
||||||
SimpleChanges
|
|
||||||
} from '@angular/core';
|
|
||||||
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||||
|
|
||||||
export const CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR: any = {
|
export const CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR: any = {
|
||||||
@@ -43,7 +34,6 @@ export const CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR: any = {
|
|||||||
providers: [CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR]
|
providers: [CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR]
|
||||||
})
|
})
|
||||||
export class InputMaskDirective implements OnChanges, ControlValueAccessor {
|
export class InputMaskDirective implements OnChanges, ControlValueAccessor {
|
||||||
|
|
||||||
/** Object defining mask and "reversed" status. */
|
/** Object defining mask and "reversed" status. */
|
||||||
@Input('textMask') inputMask: {
|
@Input('textMask') inputMask: {
|
||||||
mask: string;
|
mask: string;
|
||||||
@@ -62,27 +52,30 @@ export class InputMaskDirective implements OnChanges, ControlValueAccessor {
|
|||||||
private value;
|
private value;
|
||||||
private invalidCharacters = [];
|
private invalidCharacters = [];
|
||||||
|
|
||||||
constructor(private el: ElementRef, private render: Renderer2) {
|
constructor(private el: ElementRef, private render: Renderer2) {}
|
||||||
}
|
|
||||||
|
|
||||||
_onChange = (_: any) => {
|
_onChange = (_: any) => {};
|
||||||
};
|
|
||||||
|
|
||||||
_onTouched = () => {
|
_onTouched = () => {};
|
||||||
};
|
|
||||||
|
|
||||||
@HostListener('input', ['$event'])
|
@HostListener('input', ['$event'])
|
||||||
@HostListener('keyup', ['$event']) onTextInput(event: KeyboardEvent) {
|
@HostListener('keyup', ['$event'])
|
||||||
if (this.inputMask && this.inputMask.mask) {
|
onTextInput(event: KeyboardEvent) {
|
||||||
this.maskValue(this.el.nativeElement.value, this.el.nativeElement.selectionStart,
|
if (this.inputMask?.mask) {
|
||||||
this.inputMask.mask, this.inputMask.isReversed, event.keyCode);
|
this.maskValue(
|
||||||
|
this.el.nativeElement.value,
|
||||||
|
this.el.nativeElement.selectionStart,
|
||||||
|
this.inputMask.mask,
|
||||||
|
this.inputMask.isReversed,
|
||||||
|
event.keyCode
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
this._onChange(this.el.nativeElement.value);
|
this._onChange(this.el.nativeElement.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges) {
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
if (changes['inputMask'] && changes['inputMask'].currentValue['mask']) {
|
if (changes['inputMask']?.currentValue['mask']) {
|
||||||
this.inputMask = changes['inputMask'].currentValue;
|
this.inputMask = changes['inputMask'].currentValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -99,7 +92,7 @@ export class InputMaskDirective implements OnChanges, ControlValueAccessor {
|
|||||||
this._onTouched = fn;
|
this._onTouched = fn;
|
||||||
}
|
}
|
||||||
|
|
||||||
private maskValue(actualValue, startCaret, maskToApply, isMaskReversed, keyCode) {
|
private maskValue(actualValue: string, startCaret: number, maskToApply: string, isMaskReversed: boolean, keyCode: number) {
|
||||||
if (this.byPassKeys.indexOf(keyCode) === -1) {
|
if (this.byPassKeys.indexOf(keyCode) === -1) {
|
||||||
const value = this.getMasked(false, actualValue, maskToApply, isMaskReversed);
|
const value = this.getMasked(false, actualValue, maskToApply, isMaskReversed);
|
||||||
const calculatedCaret = this.calculateCaretPosition(startCaret, actualValue, keyCode);
|
const calculatedCaret = this.calculateCaretPosition(startCaret, actualValue, keyCode);
|
||||||
@@ -111,12 +104,12 @@ export class InputMaskDirective implements OnChanges, ControlValueAccessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private setCaretPosition(caretPosition) {
|
private setCaretPosition(caretPosition: number) {
|
||||||
this.el.nativeElement.moveStart = caretPosition;
|
this.el.nativeElement.moveStart = caretPosition;
|
||||||
this.el.nativeElement.moveEnd = caretPosition;
|
this.el.nativeElement.moveEnd = caretPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
calculateCaretPosition(caretPosition, newValue, keyCode) {
|
calculateCaretPosition(caretPosition: number, newValue: string, keyCode: number): number {
|
||||||
const newValueLength = newValue.length;
|
const newValueLength = newValue.length;
|
||||||
const oldValue = this.getValue() || '';
|
const oldValue = this.getValue() || '';
|
||||||
const oldValueLength = oldValue.length;
|
const oldValueLength = oldValue.length;
|
||||||
@@ -133,7 +126,7 @@ export class InputMaskDirective implements OnChanges, ControlValueAccessor {
|
|||||||
return caretPosition;
|
return caretPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
getMasked(skipMaskChars, val, mask, isReversed = false) {
|
getMasked(skipMaskChars: boolean, val: string, mask: string, isReversed = false) {
|
||||||
const buf = [];
|
const buf = [];
|
||||||
const value = val;
|
const value = val;
|
||||||
let maskIndex = 0;
|
let maskIndex = 0;
|
||||||
@@ -143,9 +136,9 @@ export class InputMaskDirective implements OnChanges, ControlValueAccessor {
|
|||||||
let offset = 1;
|
let offset = 1;
|
||||||
let addMethod = 'push';
|
let addMethod = 'push';
|
||||||
let resetPos = -1;
|
let resetPos = -1;
|
||||||
let lastMaskChar;
|
let lastMaskChar: number;
|
||||||
let lastUntranslatedMaskChar;
|
let lastUntranslatedMaskChar: string;
|
||||||
let check;
|
let check: boolean;
|
||||||
|
|
||||||
if (isReversed) {
|
if (isReversed) {
|
||||||
addMethod = 'unshift';
|
addMethod = 'unshift';
|
||||||
@@ -211,12 +204,12 @@ export class InputMaskDirective implements OnChanges, ControlValueAccessor {
|
|||||||
return buf.join('');
|
return buf.join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
private isToCheck(isReversed, maskIndex, maskLen, valueIndex, valueLength) {
|
private isToCheck(isReversed: boolean, maskIndex: number, maskLen: number, valueIndex: number, valueLength: number): boolean {
|
||||||
let check = false;
|
let check = false;
|
||||||
if (isReversed) {
|
if (isReversed) {
|
||||||
check = (maskIndex > -1) && (valueIndex > -1);
|
check = maskIndex > -1 && valueIndex > -1;
|
||||||
} else {
|
} else {
|
||||||
check = (maskIndex < maskLen) && (valueIndex < valueLength);
|
check = maskIndex < maskLen && valueIndex < valueLength;
|
||||||
}
|
}
|
||||||
return check;
|
return check;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ import { FormFieldModel } from './core';
|
|||||||
encapsulation: ViewEncapsulation.None
|
encapsulation: ViewEncapsulation.None
|
||||||
})
|
})
|
||||||
export class WidgetComponent implements AfterViewInit {
|
export class WidgetComponent implements AfterViewInit {
|
||||||
|
|
||||||
/** Does the widget show a read-only value? (ie, can't be edited) */
|
/** Does the widget show a read-only value? (ie, can't be edited) */
|
||||||
@Input()
|
@Input()
|
||||||
readOnly: boolean = false;
|
readOnly: boolean = false;
|
||||||
@@ -60,8 +59,7 @@ export class WidgetComponent implements AfterViewInit {
|
|||||||
|
|
||||||
touched: boolean = false;
|
touched: boolean = false;
|
||||||
|
|
||||||
constructor(public formService?: FormService) {
|
constructor(public formService?: FormService) {}
|
||||||
}
|
|
||||||
|
|
||||||
hasField(): boolean {
|
hasField(): boolean {
|
||||||
return !!this.field;
|
return !!this.field;
|
||||||
@@ -70,7 +68,7 @@ export class WidgetComponent implements AfterViewInit {
|
|||||||
// Note for developers:
|
// Note for developers:
|
||||||
// returns <any> object to be able binding it to the <element required="required"> attribute
|
// returns <any> object to be able binding it to the <element required="required"> attribute
|
||||||
isRequired(): any {
|
isRequired(): any {
|
||||||
if (this.field && this.field.required) {
|
if (this.field?.required) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@@ -85,9 +83,7 @@ export class WidgetComponent implements AfterViewInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
hasValue(): boolean {
|
hasValue(): boolean {
|
||||||
return this.field &&
|
return this.field?.value !== null && this.field?.value !== undefined;
|
||||||
this.field.value !== null &&
|
|
||||||
this.field.value !== undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
isInvalidFieldRequired() {
|
isInvalidFieldRequired() {
|
||||||
|
|||||||
@@ -18,13 +18,7 @@
|
|||||||
import { LogService } from '../../common/services/log.service';
|
import { LogService } from '../../common/services/log.service';
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import {
|
import { FormFieldModel, FormModel, TabModel, ContainerModel, FormOutcomeModel } from '../components/widgets/core';
|
||||||
FormFieldModel,
|
|
||||||
FormModel,
|
|
||||||
TabModel,
|
|
||||||
ContainerModel,
|
|
||||||
FormOutcomeModel
|
|
||||||
} from '../components/widgets/core';
|
|
||||||
import { TaskProcessVariableModel } from '../models/task-process-variable.model';
|
import { TaskProcessVariableModel } from '../models/task-process-variable.model';
|
||||||
import { WidgetVisibilityModel, WidgetTypeEnum } from '../models/widget-visibility.model';
|
import { WidgetVisibilityModel, WidgetTypeEnum } from '../models/widget-visibility.model';
|
||||||
|
|
||||||
@@ -32,27 +26,27 @@ import { WidgetVisibilityModel, WidgetTypeEnum } from '../models/widget-visibili
|
|||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class WidgetVisibilityService {
|
export class WidgetVisibilityService {
|
||||||
|
|
||||||
private processVarList: TaskProcessVariableModel[];
|
private processVarList: TaskProcessVariableModel[];
|
||||||
private form: FormModel;
|
private form: FormModel;
|
||||||
|
|
||||||
constructor(private logService: LogService) {
|
constructor(private logService: LogService) {}
|
||||||
}
|
|
||||||
|
|
||||||
public refreshVisibility(form: FormModel, processVarList?: TaskProcessVariableModel[]) {
|
public refreshVisibility(form: FormModel, processVarList?: TaskProcessVariableModel[]) {
|
||||||
this.form = form;
|
this.form = form;
|
||||||
|
|
||||||
if (processVarList) {
|
if (processVarList) {
|
||||||
this.processVarList = processVarList;
|
this.processVarList = processVarList;
|
||||||
}
|
}
|
||||||
if (form && form.tabs && form.tabs.length > 0) {
|
|
||||||
|
if (form) {
|
||||||
|
if (form.tabs?.length > 0) {
|
||||||
form.tabs.map((tabModel) => this.refreshEntityVisibility(tabModel));
|
form.tabs.map((tabModel) => this.refreshEntityVisibility(tabModel));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (form && form.outcomes && form.outcomes.length > 0) {
|
if (form.outcomes?.length > 0) {
|
||||||
form.outcomes.map((outcomeModel) => this.refreshOutcomeVisibility(outcomeModel));
|
form.outcomes.map((outcomeModel) => this.refreshOutcomeVisibility(outcomeModel));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (form) {
|
|
||||||
form.getFormFields().map((field) => this.refreshEntityVisibility(field));
|
form.getFormFields().map((field) => this.refreshEntityVisibility(field));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -79,14 +73,14 @@ export class WidgetVisibilityService {
|
|||||||
const rightValue = this.getRightValue(form, visibilityObj);
|
const rightValue = this.getRightValue(form, visibilityObj);
|
||||||
const actualResult = this.evaluateCondition(leftValue, rightValue, visibilityObj.operator);
|
const actualResult = this.evaluateCondition(leftValue, rightValue, visibilityObj.operator);
|
||||||
|
|
||||||
accumulator.push({value: actualResult, operator: visibilityObj.nextConditionOperator});
|
accumulator.push({ value: actualResult, operator: visibilityObj.nextConditionOperator });
|
||||||
|
|
||||||
if (this.isValidCondition(visibilityObj.nextCondition)) {
|
if (this.isValidCondition(visibilityObj.nextCondition)) {
|
||||||
result = this.isFieldVisible(form, visibilityObj.nextCondition, accumulator);
|
result = this.isFieldVisible(form, visibilityObj.nextCondition, accumulator);
|
||||||
} else if (accumulator[0] !== undefined) {
|
} else if (accumulator[0] !== undefined) {
|
||||||
result = Function('"use strict";return (' +
|
result = Function(
|
||||||
accumulator.map((expression) => this.transformToLiteralExpression(expression)).join('') +
|
'"use strict";return (' + accumulator.map((expression) => this.transformToLiteralExpression(expression)).join('') + ')'
|
||||||
')')();
|
)();
|
||||||
} else {
|
} else {
|
||||||
result = actualResult;
|
result = actualResult;
|
||||||
}
|
}
|
||||||
@@ -102,7 +96,7 @@ export class WidgetVisibilityService {
|
|||||||
switch (currentOperator) {
|
switch (currentOperator) {
|
||||||
case 'and':
|
case 'and':
|
||||||
return '&&';
|
return '&&';
|
||||||
case 'or' :
|
case 'or':
|
||||||
return '||';
|
return '||';
|
||||||
case 'and-not':
|
case 'and-not':
|
||||||
return '&& !';
|
return '&& !';
|
||||||
@@ -158,25 +152,25 @@ export class WidgetVisibilityService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public isFormFieldValid(formField: FormFieldModel): boolean {
|
public isFormFieldValid(formField: FormFieldModel): boolean {
|
||||||
return formField && formField.isValid;
|
return formField?.isValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getFieldValue(valueList: any, fieldId: string): any {
|
public getFieldValue(valueList: any, fieldId: string): any {
|
||||||
let labelFilterByName;
|
let labelFilterByName: string;
|
||||||
let valueFound;
|
let valueFound: any;
|
||||||
if (fieldId && fieldId.indexOf('_LABEL') > 0) {
|
if (fieldId && fieldId.indexOf('_LABEL') > 0) {
|
||||||
labelFilterByName = fieldId.substring(0, fieldId.length - 6);
|
labelFilterByName = fieldId.substring(0, fieldId.length - 6);
|
||||||
if (valueList[labelFilterByName]) {
|
if (valueList[labelFilterByName]) {
|
||||||
if (Array.isArray(valueList[labelFilterByName])) {
|
if (Array.isArray(valueList[labelFilterByName])) {
|
||||||
valueFound = valueList[labelFilterByName].map(({name}) => name);
|
valueFound = valueList[labelFilterByName].map(({ name }) => name);
|
||||||
} else {
|
} else {
|
||||||
valueFound = valueList[labelFilterByName].name;
|
valueFound = valueList[labelFilterByName].name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (valueList[fieldId] && valueList[fieldId].id) {
|
} else if (valueList[fieldId]?.id) {
|
||||||
valueFound = valueList[fieldId].id;
|
valueFound = valueList[fieldId].id;
|
||||||
} else if (valueList[fieldId] && Array.isArray(valueList[fieldId])) {
|
} else if (valueList[fieldId] && Array.isArray(valueList[fieldId])) {
|
||||||
valueFound = valueList[fieldId].map(({id}) => id);
|
valueFound = valueList[fieldId].map(({ id }) => id);
|
||||||
} else {
|
} else {
|
||||||
valueFound = valueList[fieldId];
|
valueFound = valueList[fieldId];
|
||||||
}
|
}
|
||||||
@@ -198,7 +192,7 @@ export class WidgetVisibilityService {
|
|||||||
fieldValue = this.getObjectValue(formField, fieldId);
|
fieldValue = this.getObjectValue(formField, fieldId);
|
||||||
|
|
||||||
if (!fieldValue) {
|
if (!fieldValue) {
|
||||||
if (formField.value && formField.value.id) {
|
if (formField.value?.id) {
|
||||||
fieldValue = formField.value.id;
|
fieldValue = formField.value.id;
|
||||||
} else if (!this.isInvalidValue(formField.value)) {
|
} else if (!this.isInvalidValue(formField.value)) {
|
||||||
fieldValue = formField.value;
|
fieldValue = formField.value;
|
||||||
@@ -223,7 +217,7 @@ export class WidgetVisibilityService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getCurrentFieldFromTabById(container: ContainerModel, fieldId: string): FormFieldModel {
|
private getCurrentFieldFromTabById(container: ContainerModel, fieldId: string): FormFieldModel {
|
||||||
const tabFields: FormFieldModel[][] = Object.keys(container.field.fields).map(key => container.field.fields[key]);
|
const tabFields: FormFieldModel[][] = Object.keys(container.field.fields).map((key) => container.field.fields[key]);
|
||||||
let currentField: FormFieldModel;
|
let currentField: FormFieldModel;
|
||||||
|
|
||||||
for (const tabField of tabFields) {
|
for (const tabField of tabFields) {
|
||||||
@@ -237,14 +231,14 @@ export class WidgetVisibilityService {
|
|||||||
|
|
||||||
private getFormTabContainers(form: FormModel): ContainerModel[] {
|
private getFormTabContainers(form: FormModel): ContainerModel[] {
|
||||||
if (!!form) {
|
if (!!form) {
|
||||||
return form.fields.filter(field => field.type === 'container' && field.tab) as ContainerModel[];
|
return form.fields.filter((field) => field.type === 'container' && field.tab) as ContainerModel[];
|
||||||
}
|
}
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
private getObjectValue(field: FormFieldModel, fieldId: string): string {
|
private getObjectValue(field: FormFieldModel, fieldId: string): string {
|
||||||
let value = '';
|
let value = '';
|
||||||
if (field.value && field.value.name) {
|
if (field.value?.name) {
|
||||||
value = field.value.name;
|
value = field.value.name;
|
||||||
} else if (field.options) {
|
} else if (field.options) {
|
||||||
const option = field.options.find((opt) => opt.id === field.value);
|
const option = field.options.find((opt) => opt.id === field.value);
|
||||||
@@ -267,23 +261,19 @@ export class WidgetVisibilityService {
|
|||||||
|
|
||||||
private isSearchedField(field: FormFieldModel, fieldId: string): boolean {
|
private isSearchedField(field: FormFieldModel, fieldId: string): boolean {
|
||||||
const fieldToFind = fieldId?.indexOf('_LABEL') > 0 ? fieldId.replace('_LABEL', '') : fieldId;
|
const fieldToFind = fieldId?.indexOf('_LABEL') > 0 ? fieldId.replace('_LABEL', '') : fieldId;
|
||||||
return (field.id && fieldToFind) ? field.id.toUpperCase() === fieldToFind.toUpperCase() : false;
|
return field.id && fieldToFind ? field.id.toUpperCase() === fieldToFind.toUpperCase() : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getVariableValue(form: FormModel, name: string, processVarList: TaskProcessVariableModel[]): string {
|
public getVariableValue(form: FormModel, name: string, processVarList: TaskProcessVariableModel[]): string {
|
||||||
const processVariableValue = this.getProcessVariableValue(name, processVarList);
|
const processVariableValue = this.getProcessVariableValue(name, processVarList);
|
||||||
const variableDefaultValue = form.getDefaultFormVariableValue(name);
|
const variableDefaultValue = form.getDefaultFormVariableValue(name);
|
||||||
|
|
||||||
return (processVariableValue === undefined) ? variableDefaultValue : processVariableValue;
|
return processVariableValue === undefined ? variableDefaultValue : processVariableValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getProcessVariableValue(name: string, processVarList: TaskProcessVariableModel[]): string {
|
private getProcessVariableValue(name: string, processVarList: TaskProcessVariableModel[]): string {
|
||||||
if (processVarList) {
|
if (processVarList) {
|
||||||
const processVariable = processVarList.find(
|
const processVariable = processVarList.find((variable) => variable.id === name || variable.id === `variables.${name}`);
|
||||||
variable =>
|
|
||||||
variable.id === name ||
|
|
||||||
variable.id === `variables.${name}`
|
|
||||||
);
|
|
||||||
|
|
||||||
if (processVariable) {
|
if (processVariable) {
|
||||||
return processVariable.value;
|
return processVariable.value;
|
||||||
@@ -329,6 +319,6 @@ export class WidgetVisibilityService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private isValidCondition(condition: WidgetVisibilityModel): boolean {
|
private isValidCondition(condition: WidgetVisibilityModel): boolean {
|
||||||
return !!(condition && condition.operator);
|
return !!condition?.operator;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ export class LayoutContainerComponent implements OnInit, OnDestroy, OnChanges {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges) {
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
if (changes && changes.direction) {
|
if (changes?.direction) {
|
||||||
this.contentAnimationState = this.toggledContentAnimation;
|
this.contentAnimationState = this.toggledContentAnimation;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -104,9 +104,7 @@ export class LayoutContainerComponent implements OnInit, OnDestroy, OnChanges {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private get toggledSidenavAnimation(): any {
|
private get toggledSidenavAnimation(): any {
|
||||||
return this.sidenavAnimationState === this.SIDENAV_STATES.EXPANDED
|
return this.sidenavAnimationState === this.SIDENAV_STATES.EXPANDED ? this.SIDENAV_STATES.COMPACT : this.SIDENAV_STATES.EXPANDED;
|
||||||
? this.SIDENAV_STATES.COMPACT
|
|
||||||
: this.SIDENAV_STATES.EXPANDED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private get toggledContentAnimation(): any {
|
private get toggledContentAnimation(): any {
|
||||||
@@ -130,7 +128,6 @@ export class LayoutContainerComponent implements OnInit, OnDestroy, OnChanges {
|
|||||||
if (this.position === 'end' && this.direction === 'rtl') {
|
if (this.position === 'end' && this.direction === 'rtl') {
|
||||||
return { value: 'compact', params: { 'margin-left': this.sidenavMax } };
|
return { value: 'compact', params: { 'margin-left': this.sidenavMax } };
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (this.position === 'start' && this.direction === 'ltr') {
|
if (this.position === 'start' && this.direction === 'ltr') {
|
||||||
return { value: 'expanded', params: { 'margin-left': this.sidenavMin } };
|
return { value: 'expanded', params: { 'margin-left': this.sidenavMin } };
|
||||||
|
|||||||
@@ -42,6 +42,6 @@ export class LoginDialogPanelComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
isValid() {
|
isValid() {
|
||||||
return this.login && this.login.form ? this.login.form.valid : false;
|
return this.login?.form ? this.login.form.valid : false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,10 +15,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import { Component, EventEmitter, Input, OnInit, Output, TemplateRef, ViewEncapsulation, OnDestroy } from '@angular/core';
|
||||||
Component, EventEmitter,
|
|
||||||
Input, OnInit, Output, TemplateRef, ViewEncapsulation, OnDestroy
|
|
||||||
} from '@angular/core';
|
|
||||||
import { AbstractControl, UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
|
import { AbstractControl, UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
|
||||||
import { Router, ActivatedRoute, Params } from '@angular/router';
|
import { Router, ActivatedRoute, Params } from '@angular/router';
|
||||||
import { AuthenticationService } from '../../auth/services/authentication.service';
|
import { AuthenticationService } from '../../auth/services/authentication.service';
|
||||||
@@ -28,10 +25,7 @@ import { UserPreferencesService } from '../../common/services/user-preferences.s
|
|||||||
import { LoginErrorEvent } from '../models/login-error.event';
|
import { LoginErrorEvent } from '../models/login-error.event';
|
||||||
import { LoginSubmitEvent } from '../models/login-submit.event';
|
import { LoginSubmitEvent } from '../models/login-submit.event';
|
||||||
import { LoginSuccessEvent } from '../models/login-success.event';
|
import { LoginSuccessEvent } from '../models/login-success.event';
|
||||||
import {
|
import { AppConfigService, AppConfigValues } from '../../app-config/app-config.service';
|
||||||
AppConfigService,
|
|
||||||
AppConfigValues
|
|
||||||
} from '../../app-config/app-config.service';
|
|
||||||
import { DomSanitizer, SafeStyle } from '@angular/platform-browser';
|
import { DomSanitizer, SafeStyle } from '@angular/platform-browser';
|
||||||
import { Subject } from 'rxjs';
|
import { Subject } from 'rxjs';
|
||||||
import { takeUntil } from 'rxjs/operators';
|
import { takeUntil } from 'rxjs/operators';
|
||||||
@@ -136,8 +130,7 @@ export class LoginComponent implements OnInit, OnDestroy {
|
|||||||
private userPreferences: UserPreferencesService,
|
private userPreferences: UserPreferencesService,
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private sanitizer: DomSanitizer
|
private sanitizer: DomSanitizer
|
||||||
) {
|
) {}
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.initFormError();
|
this.initFormError();
|
||||||
@@ -149,12 +142,11 @@ export class LoginComponent implements OnInit, OnDestroy {
|
|||||||
if (this.authService.isLoggedIn()) {
|
if (this.authService.isLoggedIn()) {
|
||||||
this.router.navigate([this.successRoute]);
|
this.router.navigate([this.successRoute]);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (this.authService.isOauth()) {
|
if (this.authService.isOauth()) {
|
||||||
const oauth = this.appConfig.oauth2;
|
const oauth = this.appConfig.oauth2;
|
||||||
if (oauth && oauth.silentLogin) {
|
if (oauth?.silentLogin) {
|
||||||
this.redirectToImplicitLogin();
|
this.redirectToImplicitLogin();
|
||||||
} else if (oauth && oauth.implicitFlow) {
|
} else if (oauth?.implicitFlow) {
|
||||||
this.implicitFlow = true;
|
this.implicitFlow = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -171,9 +163,7 @@ export class LoginComponent implements OnInit, OnDestroy {
|
|||||||
this.form = this._fb.group(this.fieldsValidation);
|
this.form = this._fb.group(this.fieldsValidation);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.form.valueChanges
|
this.form.valueChanges.pipe(takeUntil(this.onDestroy$)).subscribe((data) => this.onValueChanged(data));
|
||||||
.pipe(takeUntil(this.onDestroy$))
|
|
||||||
.subscribe(data => this.onValueChanged(data));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
@@ -193,7 +183,6 @@ export class LoginComponent implements OnInit, OnDestroy {
|
|||||||
* Method called on submit form
|
* Method called on submit form
|
||||||
*
|
*
|
||||||
* @param values
|
* @param values
|
||||||
* @param event
|
|
||||||
*/
|
*/
|
||||||
onSubmit(values: any): void {
|
onSubmit(values: any): void {
|
||||||
this.disableError();
|
this.disableError();
|
||||||
@@ -227,14 +216,12 @@ export class LoginComponent implements OnInit, OnDestroy {
|
|||||||
if (field) {
|
if (field) {
|
||||||
this.formError[field] = '';
|
this.formError[field] = '';
|
||||||
const hasError =
|
const hasError =
|
||||||
(this.form.controls[field].errors && data[field] !== '') ||
|
(this.form.controls[field].errors && data[field] !== '') || (this.form.controls[field].dirty && !this.form.controls[field].valid);
|
||||||
(this.form.controls[field].dirty &&
|
|
||||||
!this.form.controls[field].valid);
|
|
||||||
if (hasError) {
|
if (hasError) {
|
||||||
for (const key in this.form.controls[field].errors) {
|
for (const key in this.form.controls[field].errors) {
|
||||||
if (key) {
|
if (key) {
|
||||||
const message = this._message[field][key];
|
const message = this._message[field][key];
|
||||||
if (message && message.value) {
|
if (message?.value) {
|
||||||
const translated = this.translateService.instant(message.value, message.params);
|
const translated = this.translateService.instant(message.value, message.params);
|
||||||
this.formError[field] += translated;
|
this.formError[field] += translated;
|
||||||
}
|
}
|
||||||
@@ -246,18 +233,14 @@ export class LoginComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
performLogin(values: { username: string; password: string }) {
|
performLogin(values: { username: string; password: string }) {
|
||||||
this.authService
|
this.authService.login(values.username, values.password, this.rememberMe).subscribe(
|
||||||
.login(values.username, values.password, this.rememberMe)
|
(token) => {
|
||||||
.subscribe(
|
|
||||||
(token: any) => {
|
|
||||||
const redirectUrl = this.authService.getRedirect();
|
const redirectUrl = this.authService.getRedirect();
|
||||||
|
|
||||||
this.actualLoginStep = LoginSteps.Welcome;
|
this.actualLoginStep = LoginSteps.Welcome;
|
||||||
this.userPreferences.setStoragePrefix(values.username);
|
this.userPreferences.setStoragePrefix(values.username);
|
||||||
values.password = null;
|
values.password = null;
|
||||||
this.success.emit(
|
this.success.emit(new LoginSuccessEvent(token, values.username, null));
|
||||||
new LoginSuccessEvent(token, values.username, null)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (redirectUrl) {
|
if (redirectUrl) {
|
||||||
this.authService.setRedirect(null);
|
this.authService.setRedirect(null);
|
||||||
@@ -279,22 +262,11 @@ export class LoginComponent implements OnInit, OnDestroy {
|
|||||||
* Check and display the right error message in the UI
|
* Check and display the right error message in the UI
|
||||||
*/
|
*/
|
||||||
private displayErrorMessage(err: any): void {
|
private displayErrorMessage(err: any): void {
|
||||||
if (
|
if (err.error?.crossDomain && err.error.message.indexOf('Access-Control-Allow-Origin') !== -1) {
|
||||||
err.error &&
|
|
||||||
err.error.crossDomain &&
|
|
||||||
err.error.message.indexOf('Access-Control-Allow-Origin') !== -1
|
|
||||||
) {
|
|
||||||
this.errorMsg = err.error.message;
|
this.errorMsg = err.error.message;
|
||||||
} else if (
|
} else if (err.status === 403 && err.message.indexOf('Invalid CSRF-token') !== -1) {
|
||||||
err.status === 403 &&
|
|
||||||
err.message.indexOf('Invalid CSRF-token') !== -1
|
|
||||||
) {
|
|
||||||
this.errorMsg = 'LOGIN.MESSAGES.LOGIN-ERROR-CSRF';
|
this.errorMsg = 'LOGIN.MESSAGES.LOGIN-ERROR-CSRF';
|
||||||
} else if (
|
} else if (err.status === 403 && err.message.indexOf('The system is currently in read-only mode') !== -1) {
|
||||||
err.status === 403 &&
|
|
||||||
err.message.indexOf('The system is currently in read-only mode') !==
|
|
||||||
-1
|
|
||||||
) {
|
|
||||||
this.errorMsg = 'LOGIN.MESSAGES.LOGIN-ECM-LICENSE';
|
this.errorMsg = 'LOGIN.MESSAGES.LOGIN-ECM-LICENSE';
|
||||||
} else {
|
} else {
|
||||||
this.errorMsg = 'LOGIN.MESSAGES.LOGIN-ERROR-CREDENTIALS';
|
this.errorMsg = 'LOGIN.MESSAGES.LOGIN-ERROR-CREDENTIALS';
|
||||||
@@ -317,13 +289,9 @@ export class LoginComponent implements OnInit, OnDestroy {
|
|||||||
* @param field
|
* @param field
|
||||||
* @param ruleId - i.e. required | minlength | maxlength
|
* @param ruleId - i.e. required | minlength | maxlength
|
||||||
* @param msg
|
* @param msg
|
||||||
|
* @param params
|
||||||
*/
|
*/
|
||||||
addCustomValidationError(
|
addCustomValidationError(field: string, ruleId: string, msg: string, params?: any) {
|
||||||
field: string,
|
|
||||||
ruleId: string,
|
|
||||||
msg: string,
|
|
||||||
params?: any
|
|
||||||
) {
|
|
||||||
if (field !== '__proto__' && field !== 'constructor' && field !== 'prototype') {
|
if (field !== '__proto__' && field !== 'constructor' && field !== 'prototype') {
|
||||||
this._message[field][ruleId] = {
|
this._message[field][ruleId] = {
|
||||||
value: msg,
|
value: msg,
|
||||||
@@ -385,7 +353,6 @@ export class LoginComponent implements OnInit, OnDestroy {
|
|||||||
minLength: this.minLength
|
minLength: this.minLength
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
password: {
|
password: {
|
||||||
required: {
|
required: {
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import { CookieService } from '../common/services/cookie.service';
|
|||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CookieServiceMock extends CookieService {
|
export class CookieServiceMock extends CookieService {
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
isEnabled(): boolean {
|
isEnabled(): boolean {
|
||||||
return true;
|
return true;
|
||||||
@@ -28,18 +27,18 @@ export class CookieServiceMock extends CookieService {
|
|||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
getItem(key: string): string | null {
|
getItem(key: string): string | null {
|
||||||
return this[key] && this[key].data || null;
|
return this[key]?.data || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
setItem(key: string, data: string, expiration: Date | null, path: string | null): void {
|
setItem(key: string, data: string, expiration: Date | null, path: string | null): void {
|
||||||
this[key] = {data, expiration, path};
|
this[key] = { data, expiration, path };
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
clear() {
|
clear() {
|
||||||
Object.keys(this).forEach((key) => {
|
Object.keys(this).forEach((key) => {
|
||||||
if (this.hasOwnProperty(key) && typeof(this[key]) !== 'function') {
|
if (this.hasOwnProperty(key) && typeof this[key] !== 'function') {
|
||||||
this[key] = undefined;
|
this[key] = undefined;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -18,11 +18,11 @@
|
|||||||
export class ComponentTranslationModel {
|
export class ComponentTranslationModel {
|
||||||
name: string;
|
name: string;
|
||||||
path: string;
|
path: string;
|
||||||
json: string [];
|
json: string[];
|
||||||
|
|
||||||
constructor(obj?: any) {
|
constructor(obj?: any) {
|
||||||
this.name = obj && obj.name;
|
this.name = obj?.name;
|
||||||
this.path = obj && obj.path;
|
this.path = obj?.path;
|
||||||
this.json = obj && obj.json || [];
|
this.json = obj?.json || [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import { takeUntil } from 'rxjs/operators';
|
|||||||
pure: false
|
pure: false
|
||||||
})
|
})
|
||||||
export class DecimalNumberPipe implements PipeTransform, OnDestroy {
|
export class DecimalNumberPipe implements PipeTransform, OnDestroy {
|
||||||
|
|
||||||
static DEFAULT_LOCALE = 'en-US';
|
static DEFAULT_LOCALE = 'en-US';
|
||||||
static DEFAULT_MIN_INTEGER_DIGITS = 1;
|
static DEFAULT_MIN_INTEGER_DIGITS = 1;
|
||||||
static DEFAULT_MIN_FRACTION_DIGITS = 0;
|
static DEFAULT_MIN_FRACTION_DIGITS = 0;
|
||||||
@@ -41,14 +40,11 @@ export class DecimalNumberPipe implements PipeTransform, OnDestroy {
|
|||||||
|
|
||||||
onDestroy$: Subject<boolean> = new Subject<boolean>();
|
onDestroy$: Subject<boolean> = new Subject<boolean>();
|
||||||
|
|
||||||
constructor(public userPreferenceService?: UserPreferencesService,
|
constructor(public userPreferenceService?: UserPreferencesService, public appConfig?: AppConfigService) {
|
||||||
public appConfig?: AppConfigService) {
|
|
||||||
|
|
||||||
if (this.userPreferenceService) {
|
if (this.userPreferenceService) {
|
||||||
this.userPreferenceService.select(UserPreferenceValues.Locale)
|
this.userPreferenceService
|
||||||
.pipe(
|
.select(UserPreferenceValues.Locale)
|
||||||
takeUntil(this.onDestroy$)
|
.pipe(takeUntil(this.onDestroy$))
|
||||||
)
|
|
||||||
.subscribe((locale) => {
|
.subscribe((locale) => {
|
||||||
if (locale) {
|
if (locale) {
|
||||||
this.defaultLocale = locale;
|
this.defaultLocale = locale;
|
||||||
@@ -58,15 +54,21 @@ export class DecimalNumberPipe implements PipeTransform, OnDestroy {
|
|||||||
|
|
||||||
if (this.appConfig) {
|
if (this.appConfig) {
|
||||||
this.defaultMinIntegerDigits = this.appConfig.get<number>('decimalValues.minIntegerDigits', DecimalNumberPipe.DEFAULT_MIN_INTEGER_DIGITS);
|
this.defaultMinIntegerDigits = this.appConfig.get<number>('decimalValues.minIntegerDigits', DecimalNumberPipe.DEFAULT_MIN_INTEGER_DIGITS);
|
||||||
this.defaultMinFractionDigits = this.appConfig.get<number>('decimalValues.minFractionDigits', DecimalNumberPipe.DEFAULT_MIN_FRACTION_DIGITS);
|
this.defaultMinFractionDigits = this.appConfig.get<number>(
|
||||||
this.defaultMaxFractionDigits = this.appConfig.get<number>('decimalValues.maxFractionDigits', DecimalNumberPipe.DEFAULT_MAX_FRACTION_DIGITS);
|
'decimalValues.minFractionDigits',
|
||||||
|
DecimalNumberPipe.DEFAULT_MIN_FRACTION_DIGITS
|
||||||
|
);
|
||||||
|
this.defaultMaxFractionDigits = this.appConfig.get<number>(
|
||||||
|
'decimalValues.maxFractionDigits',
|
||||||
|
DecimalNumberPipe.DEFAULT_MAX_FRACTION_DIGITS
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
transform(value: any, digitsInfo?: DecimalNumberModel, locale?: string): any {
|
transform(value: any, digitsInfo?: DecimalNumberModel, locale?: string): any {
|
||||||
const actualMinIntegerDigits: number = digitsInfo && digitsInfo.minIntegerDigits ? digitsInfo.minIntegerDigits : this.defaultMinIntegerDigits;
|
const actualMinIntegerDigits: number = digitsInfo?.minIntegerDigits ? digitsInfo.minIntegerDigits : this.defaultMinIntegerDigits;
|
||||||
const actualMinFractionDigits: number = digitsInfo && digitsInfo.minFractionDigits ? digitsInfo.minFractionDigits : this.defaultMinFractionDigits;
|
const actualMinFractionDigits: number = digitsInfo?.minFractionDigits ? digitsInfo.minFractionDigits : this.defaultMinFractionDigits;
|
||||||
const actualMaxFractionDigits: number = digitsInfo && digitsInfo.maxFractionDigits ? digitsInfo.maxFractionDigits : this.defaultMaxFractionDigits;
|
const actualMaxFractionDigits: number = digitsInfo?.maxFractionDigits ? digitsInfo.maxFractionDigits : this.defaultMaxFractionDigits;
|
||||||
|
|
||||||
const actualDigitsInfo = `${actualMinIntegerDigits}.${actualMinFractionDigits}-${actualMaxFractionDigits}`;
|
const actualDigitsInfo = `${actualMinIntegerDigits}.${actualMinFractionDigits}-${actualMaxFractionDigits}`;
|
||||||
const actualLocale = locale || this.defaultLocale;
|
const actualLocale = locale || this.defaultLocale;
|
||||||
|
|||||||
@@ -18,17 +18,7 @@
|
|||||||
/* eslint-disable @angular-eslint/no-input-rename, @typescript-eslint/no-use-before-define, @angular-eslint/no-input-rename */
|
/* eslint-disable @angular-eslint/no-input-rename, @typescript-eslint/no-use-before-define, @angular-eslint/no-input-rename */
|
||||||
|
|
||||||
import { ENTER, ESCAPE } from '@angular/cdk/keycodes';
|
import { ENTER, ESCAPE } from '@angular/cdk/keycodes';
|
||||||
import {
|
import { ChangeDetectorRef, Directive, ElementRef, forwardRef, Inject, Input, NgZone, OnDestroy, Optional } from '@angular/core';
|
||||||
ChangeDetectorRef,
|
|
||||||
Directive,
|
|
||||||
ElementRef,
|
|
||||||
forwardRef,
|
|
||||||
Inject,
|
|
||||||
Input,
|
|
||||||
NgZone,
|
|
||||||
OnDestroy,
|
|
||||||
Optional
|
|
||||||
} from '@angular/core';
|
|
||||||
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||||
import { DOCUMENT } from '@angular/common';
|
import { DOCUMENT } from '@angular/common';
|
||||||
import { Observable, Subject, Subscription, merge, of, fromEvent } from 'rxjs';
|
import { Observable, Subject, Subscription, merge, of, fromEvent } from 'rxjs';
|
||||||
@@ -71,14 +61,16 @@ export class SearchTriggerDirective implements ControlValueAccessor, OnDestroy {
|
|||||||
private closingActionsSubscription: Subscription;
|
private closingActionsSubscription: Subscription;
|
||||||
private escapeEventStream = new Subject<void>();
|
private escapeEventStream = new Subject<void>();
|
||||||
|
|
||||||
onChange: (value: any) => void = () => { };
|
onChange: (value: any) => void = () => {};
|
||||||
|
|
||||||
onTouched = () => { };
|
onTouched = () => {};
|
||||||
|
|
||||||
constructor(private element: ElementRef,
|
constructor(
|
||||||
|
private element: ElementRef,
|
||||||
private ngZone: NgZone,
|
private ngZone: NgZone,
|
||||||
private changeDetectorRef: ChangeDetectorRef,
|
private changeDetectorRef: ChangeDetectorRef,
|
||||||
@Optional() @Inject(DOCUMENT) private document: any) { }
|
@Optional() @Inject(DOCUMENT) private document: any
|
||||||
|
) {}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
this.onDestroy$.next(true);
|
this.onDestroy$.next(true);
|
||||||
@@ -87,7 +79,7 @@ export class SearchTriggerDirective implements ControlValueAccessor, OnDestroy {
|
|||||||
if (this.escapeEventStream) {
|
if (this.escapeEventStream) {
|
||||||
this.escapeEventStream = null;
|
this.escapeEventStream = null;
|
||||||
}
|
}
|
||||||
if ( this.closingActionsSubscription ) {
|
if (this.closingActionsSubscription) {
|
||||||
this.closingActionsSubscription.unsubscribe();
|
this.closingActionsSubscription.unsubscribe();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -112,10 +104,7 @@ export class SearchTriggerDirective implements ControlValueAccessor, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get panelClosingActions(): Observable<any> {
|
get panelClosingActions(): Observable<any> {
|
||||||
return merge(
|
return merge(this.escapeEventStream, this.outsideClickStream);
|
||||||
this.escapeEventStream,
|
|
||||||
this.outsideClickStream
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private get outsideClickStream(): Observable<any> {
|
private get outsideClickStream(): Observable<any> {
|
||||||
@@ -123,10 +112,7 @@ export class SearchTriggerDirective implements ControlValueAccessor, OnDestroy {
|
|||||||
return of(null);
|
return of(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
return merge(
|
return merge(fromEvent(this.document, 'click'), fromEvent(this.document, 'touchend')).pipe(
|
||||||
fromEvent(this.document, 'click'),
|
|
||||||
fromEvent(this.document, 'touchend')
|
|
||||||
).pipe(
|
|
||||||
filter((event: MouseEvent | TouchEvent) => {
|
filter((event: MouseEvent | TouchEvent) => {
|
||||||
const clickTarget = event.target as HTMLElement;
|
const clickTarget = event.target as HTMLElement;
|
||||||
return this._panelOpen && clickTarget !== this.element.nativeElement;
|
return this._panelOpen && clickTarget !== this.element.nativeElement;
|
||||||
@@ -157,11 +143,10 @@ export class SearchTriggerDirective implements ControlValueAccessor, OnDestroy {
|
|||||||
this.escapeEventStream.next();
|
this.escapeEventStream.next();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleInput(event: KeyboardEvent): void {
|
handleInput(event: KeyboardEvent): void {
|
||||||
if (document.activeElement === event.target ) {
|
if (document.activeElement === event.target) {
|
||||||
const inputValue: string = (event.target as HTMLInputElement).value;
|
const inputValue: string = (event.target as HTMLInputElement).value;
|
||||||
this.onChange(inputValue);
|
this.onChange(inputValue);
|
||||||
if (inputValue && this.searchPanel) {
|
if (inputValue && this.searchPanel) {
|
||||||
@@ -176,17 +161,15 @@ export class SearchTriggerDirective implements ControlValueAccessor, OnDestroy {
|
|||||||
|
|
||||||
private isPanelOptionClicked(event: MouseEvent) {
|
private isPanelOptionClicked(event: MouseEvent) {
|
||||||
let isPanelOption: boolean = false;
|
let isPanelOption: boolean = false;
|
||||||
if ( event && this.searchPanel ) {
|
if (event && this.searchPanel) {
|
||||||
const clickTarget = event.target as HTMLElement;
|
const clickTarget = event.target as HTMLElement;
|
||||||
isPanelOption = !this.isNoResultOption() &&
|
isPanelOption = !this.isNoResultOption() && !!this.searchPanel.panel && !!this.searchPanel.panel.nativeElement.contains(clickTarget);
|
||||||
!!this.searchPanel.panel &&
|
|
||||||
!!this.searchPanel.panel.nativeElement.contains(clickTarget);
|
|
||||||
}
|
}
|
||||||
return isPanelOption;
|
return isPanelOption;
|
||||||
}
|
}
|
||||||
|
|
||||||
private isNoResultOption(): boolean {
|
private isNoResultOption(): boolean {
|
||||||
return this.searchPanel && this.searchPanel.results.list ? this.searchPanel.results.list.entries.length === 0 : true;
|
return this.searchPanel?.results?.list ? this.searchPanel.results.list.entries.length === 0 : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private subscribeToClosingActions(): Subscription {
|
private subscribeToClosingActions(): Subscription {
|
||||||
@@ -205,8 +188,7 @@ export class SearchTriggerDirective implements ControlValueAccessor, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private setTriggerValue(value: any): void {
|
private setTriggerValue(value: any): void {
|
||||||
const toDisplay = this.searchPanel && this.searchPanel.displayWith ?
|
const toDisplay = this.searchPanel?.displayWith ? this.searchPanel.displayWith(value) : value;
|
||||||
this.searchPanel.displayWith(value) : value;
|
|
||||||
const inputValue = toDisplay != null ? toDisplay : '';
|
const inputValue = toDisplay != null ? toDisplay : '';
|
||||||
this.element.nativeElement.value = inputValue;
|
this.element.nativeElement.value = inputValue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,15 +27,13 @@ import { map, catchError, retry } from 'rxjs/operators';
|
|||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class TranslateLoaderService implements TranslateLoader {
|
export class TranslateLoaderService implements TranslateLoader {
|
||||||
|
|
||||||
private prefix: string = 'i18n';
|
private prefix: string = 'i18n';
|
||||||
private suffix: string = '.json';
|
private suffix: string = '.json';
|
||||||
private providers: ComponentTranslationModel[] = [];
|
private providers: ComponentTranslationModel[] = [];
|
||||||
private queue: string [][] = [];
|
private queue: string[][] = [];
|
||||||
private defaultLang: string = 'en';
|
private defaultLang: string = 'en';
|
||||||
|
|
||||||
constructor(private http: HttpClient) {
|
constructor(private http: HttpClient) {}
|
||||||
}
|
|
||||||
|
|
||||||
setDefaultLang(value: string) {
|
setDefaultLang(value: string) {
|
||||||
this.defaultLang = value || 'en';
|
this.defaultLang = value || 'en';
|
||||||
@@ -51,7 +49,7 @@ export class TranslateLoaderService implements TranslateLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
providerRegistered(name: string): boolean {
|
providerRegistered(name: string): boolean {
|
||||||
return this.providers.find((x) => x.name === name) ? true : false;
|
return !!this.providers.find((x) => x.name === name);
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchLanguageFile(lang: string, component: ComponentTranslationModel, fallbackUrl?: string): Observable<void> {
|
fetchLanguageFile(lang: string, component: ComponentTranslationModel, fallbackUrl?: string): Observable<void> {
|
||||||
@@ -86,9 +84,7 @@ export class TranslateLoaderService implements TranslateLoader {
|
|||||||
if (!this.isComponentInQueue(lang, component.name)) {
|
if (!this.isComponentInQueue(lang, component.name)) {
|
||||||
this.queue[lang].push(component.name);
|
this.queue[lang].push(component.name);
|
||||||
|
|
||||||
observableBatch.push(
|
observableBatch.push(this.fetchLanguageFile(lang, component));
|
||||||
this.fetchLanguageFile(lang, component)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -102,7 +98,7 @@ export class TranslateLoaderService implements TranslateLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
isComponentInQueue(lang: string, name: string) {
|
isComponentInQueue(lang: string, name: string) {
|
||||||
return (this.queue[lang] || []).find((x) => x === name) ? true : false;
|
return !!(this.queue[lang] || []).find((x) => x === name);
|
||||||
}
|
}
|
||||||
|
|
||||||
getFullTranslationJSON(lang: string): any {
|
getFullTranslationJSON(lang: string): any {
|
||||||
@@ -120,7 +116,7 @@ export class TranslateLoaderService implements TranslateLoader {
|
|||||||
return a.name.localeCompare(b.name);
|
return a.name.localeCompare(b.name);
|
||||||
})
|
})
|
||||||
.forEach((model) => {
|
.forEach((model) => {
|
||||||
if (model.json && model.json[lang]) {
|
if (model.json?.[lang]) {
|
||||||
result = ObjectUtils.merge(result, model.json[lang]);
|
result = ObjectUtils.merge(result, model.json[lang]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -131,16 +127,17 @@ export class TranslateLoaderService implements TranslateLoader {
|
|||||||
getTranslation(lang: string): Observable<any> {
|
getTranslation(lang: string): Observable<any> {
|
||||||
let hasFailures = false;
|
let hasFailures = false;
|
||||||
const batch = [
|
const batch = [
|
||||||
...this.getComponentToFetch(lang).map((observable) => observable.pipe(
|
...this.getComponentToFetch(lang).map((observable) =>
|
||||||
|
observable.pipe(
|
||||||
catchError((error) => {
|
catchError((error) => {
|
||||||
hasFailures = true;
|
hasFailures = true;
|
||||||
return of(error);
|
return of(error);
|
||||||
})
|
})
|
||||||
))
|
)
|
||||||
|
)
|
||||||
];
|
];
|
||||||
|
|
||||||
return new Observable((observer) => {
|
return new Observable((observer) => {
|
||||||
|
|
||||||
if (batch.length > 0) {
|
if (batch.length > 0) {
|
||||||
forkJoin(batch).subscribe(
|
forkJoin(batch).subscribe(
|
||||||
() => {
|
() => {
|
||||||
@@ -156,7 +153,8 @@ export class TranslateLoaderService implements TranslateLoader {
|
|||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
observer.error('Failed to load some resources');
|
observer.error('Failed to load some resources');
|
||||||
});
|
}
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
const fullTranslation = this.getFullTranslationJSON(lang);
|
const fullTranslation = this.getFullTranslationJSON(lang);
|
||||||
if (fullTranslation) {
|
if (fullTranslation) {
|
||||||
|
|||||||
@@ -23,7 +23,11 @@ import {
|
|||||||
ViewEncapsulation,
|
ViewEncapsulation,
|
||||||
ElementRef,
|
ElementRef,
|
||||||
Output,
|
Output,
|
||||||
EventEmitter, AfterViewInit, ViewChild, HostListener, OnDestroy
|
EventEmitter,
|
||||||
|
AfterViewInit,
|
||||||
|
ViewChild,
|
||||||
|
HostListener,
|
||||||
|
OnDestroy
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { AppConfigService } from '../../app-config/app-config.service';
|
import { AppConfigService } from '../../app-config/app-config.service';
|
||||||
import { UrlService } from '../../common/services/url.service';
|
import { UrlService } from '../../common/services/url.service';
|
||||||
@@ -37,7 +41,6 @@ import Cropper from 'cropperjs';
|
|||||||
encapsulation: ViewEncapsulation.None
|
encapsulation: ViewEncapsulation.None
|
||||||
})
|
})
|
||||||
export class ImgViewerComponent implements AfterViewInit, OnChanges, OnDestroy {
|
export class ImgViewerComponent implements AfterViewInit, OnChanges, OnDestroy {
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
showToolbar = true;
|
showToolbar = true;
|
||||||
|
|
||||||
@@ -64,7 +67,7 @@ export class ImgViewerComponent implements AfterViewInit, OnChanges, OnDestroy {
|
|||||||
@Output()
|
@Output()
|
||||||
isSaving = new EventEmitter<boolean>();
|
isSaving = new EventEmitter<boolean>();
|
||||||
|
|
||||||
@ViewChild('image', { static: false})
|
@ViewChild('image', { static: false })
|
||||||
public imageElement: ElementRef;
|
public imageElement: ElementRef;
|
||||||
|
|
||||||
public scale: number = 1.0;
|
public scale: number = 1.0;
|
||||||
@@ -75,10 +78,7 @@ export class ImgViewerComponent implements AfterViewInit, OnChanges, OnDestroy {
|
|||||||
return Math.round(this.scale * 100) + '%';
|
return Math.round(this.scale * 100) + '%';
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(private appConfigService: AppConfigService, private urlService: UrlService) {
|
||||||
private appConfigService: AppConfigService,
|
|
||||||
private urlService: UrlService
|
|
||||||
) {
|
|
||||||
this.initializeScaling();
|
this.initializeScaling();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,14 +143,14 @@ export class ImgViewerComponent implements AfterViewInit, OnChanges, OnDestroy {
|
|||||||
|
|
||||||
@HostListener('document:fullscreenchange')
|
@HostListener('document:fullscreenchange')
|
||||||
fullScreenChangeHandler() {
|
fullScreenChangeHandler() {
|
||||||
if(document.fullscreenElement) {
|
if (document.fullscreenElement) {
|
||||||
this.reset();
|
this.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges) {
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
const blobFile = changes['blobFile'];
|
const blobFile = changes['blobFile'];
|
||||||
if (blobFile && blobFile.currentValue) {
|
if (blobFile?.currentValue) {
|
||||||
this.urlFile = this.urlService.createTrustedUrl(this.blobFile);
|
this.urlFile = this.urlService.createTrustedUrl(this.blobFile);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -167,20 +167,20 @@ export class ImgViewerComponent implements AfterViewInit, OnChanges, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
zoomIn() {
|
zoomIn() {
|
||||||
this.cropper.zoom( 0.2);
|
this.cropper.zoom(0.2);
|
||||||
this.scale = +((this.scale + 0.2).toFixed(1));
|
this.scale = +(this.scale + 0.2).toFixed(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
zoomOut() {
|
zoomOut() {
|
||||||
if (this.scale > 0.2) {
|
if (this.scale > 0.2) {
|
||||||
this.cropper.zoom( -0.2 );
|
this.cropper.zoom(-0.2);
|
||||||
this.scale = +((this.scale - 0.2).toFixed(1));
|
this.scale = +(this.scale - 0.2).toFixed(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rotateImage() {
|
rotateImage() {
|
||||||
this.isEditing = true;
|
this.isEditing = true;
|
||||||
this.cropper.rotate( -90);
|
this.cropper.rotate(-90);
|
||||||
}
|
}
|
||||||
|
|
||||||
cropImage() {
|
cropImage() {
|
||||||
|
|||||||
@@ -23,11 +23,10 @@ import { UrlService } from '../../common/services/url.service';
|
|||||||
selector: 'adf-media-player',
|
selector: 'adf-media-player',
|
||||||
templateUrl: './media-player.component.html',
|
templateUrl: './media-player.component.html',
|
||||||
styleUrls: ['./media-player.component.scss'],
|
styleUrls: ['./media-player.component.scss'],
|
||||||
host: {class: 'adf-media-player'},
|
host: { class: 'adf-media-player' },
|
||||||
encapsulation: ViewEncapsulation.None
|
encapsulation: ViewEncapsulation.None
|
||||||
})
|
})
|
||||||
export class MediaPlayerComponent implements OnChanges {
|
export class MediaPlayerComponent implements OnChanges {
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
urlFile: string;
|
urlFile: string;
|
||||||
|
|
||||||
@@ -47,13 +46,12 @@ export class MediaPlayerComponent implements OnChanges {
|
|||||||
@Output()
|
@Output()
|
||||||
error = new EventEmitter<any>();
|
error = new EventEmitter<any>();
|
||||||
|
|
||||||
constructor(private urlService: UrlService) {
|
constructor(private urlService: UrlService) {}
|
||||||
}
|
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges) {
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
const blobFile = changes['blobFile'];
|
const blobFile = changes['blobFile'];
|
||||||
|
|
||||||
if (blobFile && blobFile.currentValue) {
|
if (blobFile?.currentValue) {
|
||||||
this.urlFile = this.urlService.createTrustedUrl(this.blobFile);
|
this.urlFile = this.urlService.createTrustedUrl(this.blobFile);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,11 +48,10 @@ declare const pdfjsViewer: any;
|
|||||||
templateUrl: './pdf-viewer.component.html',
|
templateUrl: './pdf-viewer.component.html',
|
||||||
styleUrls: ['./pdf-viewer-host.component.scss', './pdf-viewer.component.scss'],
|
styleUrls: ['./pdf-viewer-host.component.scss', './pdf-viewer.component.scss'],
|
||||||
providers: [RenderingQueueServices],
|
providers: [RenderingQueueServices],
|
||||||
host: {class: 'adf-pdf-viewer'},
|
host: { class: 'adf-pdf-viewer' },
|
||||||
encapsulation: ViewEncapsulation.None
|
encapsulation: ViewEncapsulation.None
|
||||||
})
|
})
|
||||||
export class PdfViewerComponent implements OnChanges, OnDestroy {
|
export class PdfViewerComponent implements OnChanges, OnDestroy {
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
urlFile: string;
|
urlFile: string;
|
||||||
|
|
||||||
@@ -98,7 +97,7 @@ export class PdfViewerComponent implements OnChanges, OnDestroy {
|
|||||||
loadingTask: any;
|
loadingTask: any;
|
||||||
isPanelDisabled = true;
|
isPanelDisabled = true;
|
||||||
showThumbnails: boolean = false;
|
showThumbnails: boolean = false;
|
||||||
pdfThumbnailsContext: { viewer: any } = {viewer: null};
|
pdfThumbnailsContext: { viewer: any } = { viewer: null };
|
||||||
randomPdfId: string;
|
randomPdfId: string;
|
||||||
|
|
||||||
get currentScaleText(): string {
|
get currentScaleText(): string {
|
||||||
@@ -119,13 +118,19 @@ export class PdfViewerComponent implements OnChanges, OnDestroy {
|
|||||||
private dialog: MatDialog,
|
private dialog: MatDialog,
|
||||||
private renderingQueueServices: RenderingQueueServices,
|
private renderingQueueServices: RenderingQueueServices,
|
||||||
private logService: LogService,
|
private logService: LogService,
|
||||||
private appConfigService: AppConfigService) {
|
private appConfigService: AppConfigService
|
||||||
|
) {
|
||||||
// needed to preserve "this" context
|
// needed to preserve "this" context
|
||||||
this.onPageChange = this.onPageChange.bind(this);
|
this.onPageChange = this.onPageChange.bind(this);
|
||||||
this.onPagesLoaded = this.onPagesLoaded.bind(this);
|
this.onPagesLoaded = this.onPagesLoaded.bind(this);
|
||||||
this.onPageRendered = this.onPageRendered.bind(this);
|
this.onPageRendered = this.onPageRendered.bind(this);
|
||||||
this.randomPdfId = this.generateUuid();
|
this.randomPdfId = window.crypto.randomUUID();
|
||||||
this.pdfjsWorkerDestroy$.pipe(catchError(() => null), delay(700)).subscribe(() => this.destroyPdJsWorker());
|
this.pdfjsWorkerDestroy$
|
||||||
|
.pipe(
|
||||||
|
catchError(() => null),
|
||||||
|
delay(700)
|
||||||
|
)
|
||||||
|
.subscribe(() => this.destroyPdJsWorker());
|
||||||
}
|
}
|
||||||
|
|
||||||
getUserScaling(): number {
|
getUserScaling(): number {
|
||||||
@@ -152,7 +157,7 @@ export class PdfViewerComponent implements OnChanges, OnDestroy {
|
|||||||
ngOnChanges(changes: SimpleChanges) {
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
const blobFile = changes['blobFile'];
|
const blobFile = changes['blobFile'];
|
||||||
|
|
||||||
if (blobFile && blobFile.currentValue) {
|
if (blobFile?.currentValue) {
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.onload = async () => {
|
reader.onload = async () => {
|
||||||
const pdfOptions = {
|
const pdfOptions = {
|
||||||
@@ -166,7 +171,7 @@ export class PdfViewerComponent implements OnChanges, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const urlFile = changes['urlFile'];
|
const urlFile = changes['urlFile'];
|
||||||
if (urlFile && urlFile.currentValue) {
|
if (urlFile?.currentValue) {
|
||||||
const pdfOptions = {
|
const pdfOptions = {
|
||||||
...this.pdfjsDefaultOptions,
|
...this.pdfjsDefaultOptions,
|
||||||
url: urlFile.currentValue,
|
url: urlFile.currentValue,
|
||||||
@@ -200,7 +205,8 @@ export class PdfViewerComponent implements OnChanges, OnDestroy {
|
|||||||
this.loadingPercent = Math.round(level * 100);
|
this.loadingPercent = Math.round(level * 100);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.loadingTask.promise.then((pdfDocument: PDFDocumentProxy) => {
|
this.loadingTask.promise
|
||||||
|
.then((pdfDocument: PDFDocumentProxy) => {
|
||||||
this.totalPages = pdfDocument.numPages;
|
this.totalPages = pdfDocument.numPages;
|
||||||
this.page = 1;
|
this.page = 1;
|
||||||
this.displayPage = 1;
|
this.displayPage = 1;
|
||||||
@@ -276,9 +282,8 @@ export class PdfViewerComponent implements OnChanges, OnDestroy {
|
|||||||
const documentContainer = this.getDocumentContainer();
|
const documentContainer = this.getDocumentContainer();
|
||||||
|
|
||||||
if (this.pdfViewer && documentContainer) {
|
if (this.pdfViewer && documentContainer) {
|
||||||
|
let widthContainer: number;
|
||||||
let widthContainer;
|
let heightContainer: number;
|
||||||
let heightContainer;
|
|
||||||
|
|
||||||
if (viewerContainer && viewerContainer.clientWidth <= documentContainer.clientWidth) {
|
if (viewerContainer && viewerContainer.clientWidth <= documentContainer.clientWidth) {
|
||||||
widthContainer = viewerContainer.clientWidth;
|
widthContainer = viewerContainer.clientWidth;
|
||||||
@@ -291,10 +296,10 @@ export class PdfViewerComponent implements OnChanges, OnDestroy {
|
|||||||
const currentPage = this.pdfViewer._pages[this.pdfViewer._currentPageNumber - 1];
|
const currentPage = this.pdfViewer._pages[this.pdfViewer._currentPageNumber - 1];
|
||||||
|
|
||||||
const padding = 20;
|
const padding = 20;
|
||||||
const pageWidthScale = (widthContainer - padding) / currentPage.width * currentPage.scale;
|
const pageWidthScale = ((widthContainer - padding) / currentPage.width) * currentPage.scale;
|
||||||
const pageHeightScale = (heightContainer - padding) / currentPage.width * currentPage.scale;
|
const pageHeightScale = ((heightContainer - padding) / currentPage.width) * currentPage.scale;
|
||||||
|
|
||||||
let scale;
|
let scale: number;
|
||||||
switch (this.currentScaleMode) {
|
switch (this.currentScaleMode) {
|
||||||
case 'init':
|
case 'init':
|
||||||
scale = this.getUserScaling();
|
scale = this.getUserScaling();
|
||||||
@@ -322,7 +327,7 @@ export class PdfViewerComponent implements OnChanges, OnDestroy {
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
this.logService.error('pdfViewSetScale: \'' + scaleMode + '\' is an unknown zoom value.');
|
this.logService.error(`pdfViewSetScale: '${scaleMode}' is an unknown zoom value.`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -331,7 +336,7 @@ export class PdfViewerComponent implements OnChanges, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private autoScaling(pageHeightScale: number, pageWidthScale: number) {
|
private autoScaling(pageHeightScale: number, pageWidthScale: number) {
|
||||||
let horizontalScale;
|
let horizontalScale: number;
|
||||||
if (this.isLandscape) {
|
if (this.isLandscape) {
|
||||||
horizontalScale = Math.min(pageHeightScale, pageWidthScale);
|
horizontalScale = Math.min(pageHeightScale, pageWidthScale);
|
||||||
} else {
|
} else {
|
||||||
@@ -387,7 +392,7 @@ export class PdfViewerComponent implements OnChanges, OnDestroy {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
isSameScale(oldScale: number, newScale: number): boolean {
|
isSameScale(oldScale: number, newScale: number): boolean {
|
||||||
return (newScale === oldScale);
|
return newScale === oldScale;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -397,7 +402,7 @@ export class PdfViewerComponent implements OnChanges, OnDestroy {
|
|||||||
* @param height
|
* @param height
|
||||||
*/
|
*/
|
||||||
isLandscape(width: number, height: number): boolean {
|
isLandscape(width: number, height: number): boolean {
|
||||||
return (width > height);
|
return width > height;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -507,9 +512,10 @@ export class PdfViewerComponent implements OnChanges, OnDestroy {
|
|||||||
this.dialog
|
this.dialog
|
||||||
.open(PdfPasswordDialogComponent, {
|
.open(PdfPasswordDialogComponent, {
|
||||||
width: '400px',
|
width: '400px',
|
||||||
data: {reason}
|
data: { reason }
|
||||||
})
|
})
|
||||||
.afterClosed().subscribe((password) => {
|
.afterClosed()
|
||||||
|
.subscribe((password) => {
|
||||||
if (password) {
|
if (password) {
|
||||||
callback(password);
|
callback(password);
|
||||||
} else {
|
} else {
|
||||||
@@ -528,7 +534,6 @@ export class PdfViewerComponent implements OnChanges, OnDestroy {
|
|||||||
/**
|
/**
|
||||||
* Pages Loaded Event
|
* Pages Loaded Event
|
||||||
*
|
*
|
||||||
* @param event
|
|
||||||
*/
|
*/
|
||||||
onPagesLoaded() {
|
onPagesLoaded() {
|
||||||
this.isPanelDisabled = false;
|
this.isPanelDisabled = false;
|
||||||
@@ -537,23 +542,17 @@ export class PdfViewerComponent implements OnChanges, OnDestroy {
|
|||||||
/**
|
/**
|
||||||
* Keyboard Event Listener
|
* Keyboard Event Listener
|
||||||
*
|
*
|
||||||
* @param KeyboardEvent event
|
* @param event KeyboardEvent
|
||||||
*/
|
*/
|
||||||
@HostListener('document:keydown', ['$event'])
|
@HostListener('document:keydown', ['$event'])
|
||||||
handleKeyboardEvent(event: KeyboardEvent) {
|
handleKeyboardEvent(event: KeyboardEvent) {
|
||||||
const key = event.keyCode;
|
const key = event.keyCode;
|
||||||
if (key === 39) { // right arrow
|
if (key === 39) {
|
||||||
|
// right arrow
|
||||||
this.nextPage();
|
this.nextPage();
|
||||||
} else if (key === 37) {// left arrow
|
} else if (key === 37) {
|
||||||
|
// left arrow
|
||||||
this.previousPage();
|
this.previousPage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private generateUuid() {
|
|
||||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
|
|
||||||
const r = Math.random() * 16 | 0;
|
|
||||||
const v = c === 'x' ? r : (r & 0x3 | 0x8);
|
|
||||||
return v.toString(16);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ import { AppConfigService } from '../../app-config/app-config.service';
|
|||||||
encapsulation: ViewEncapsulation.None
|
encapsulation: ViewEncapsulation.None
|
||||||
})
|
})
|
||||||
export class TxtViewerComponent implements OnChanges {
|
export class TxtViewerComponent implements OnChanges {
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
urlFile: any;
|
urlFile: any;
|
||||||
|
|
||||||
@@ -36,18 +35,16 @@ export class TxtViewerComponent implements OnChanges {
|
|||||||
|
|
||||||
content: string | ArrayBuffer;
|
content: string | ArrayBuffer;
|
||||||
|
|
||||||
constructor(private http: HttpClient, private appConfigService: AppConfigService) {
|
constructor(private http: HttpClient, private appConfigService: AppConfigService) {}
|
||||||
}
|
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges): Promise<void> {
|
ngOnChanges(changes: SimpleChanges): Promise<void> {
|
||||||
|
|
||||||
const blobFile = changes['blobFile'];
|
const blobFile = changes['blobFile'];
|
||||||
if (blobFile && blobFile.currentValue) {
|
if (blobFile?.currentValue) {
|
||||||
return this.readBlob(blobFile.currentValue);
|
return this.readBlob(blobFile.currentValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
const urlFile = changes['urlFile'];
|
const urlFile = changes['urlFile'];
|
||||||
if (urlFile && urlFile.currentValue) {
|
if (urlFile?.currentValue) {
|
||||||
return this.getUrlContent(urlFile.currentValue);
|
return this.getUrlContent(urlFile.currentValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,12 +59,15 @@ export class TxtViewerComponent implements OnChanges {
|
|||||||
const withCredentialsMode = this.appConfigService.get<boolean>('auth.withCredentials', false);
|
const withCredentialsMode = this.appConfigService.get<boolean>('auth.withCredentials', false);
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.http.get(url, { responseType: 'text', withCredentials: withCredentialsMode }).subscribe((res) => {
|
this.http.get(url, { responseType: 'text', withCredentials: withCredentialsMode }).subscribe(
|
||||||
|
(res) => {
|
||||||
this.content = res;
|
this.content = res;
|
||||||
resolve();
|
resolve();
|
||||||
}, (event) => {
|
},
|
||||||
|
(event) => {
|
||||||
reject(event);
|
reject(event);
|
||||||
});
|
}
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,12 +54,11 @@ const DEFAULT_NON_PREVIEW_CONFIG = {
|
|||||||
selector: 'adf-viewer',
|
selector: 'adf-viewer',
|
||||||
templateUrl: './viewer.component.html',
|
templateUrl: './viewer.component.html',
|
||||||
styleUrls: ['./viewer.component.scss'],
|
styleUrls: ['./viewer.component.scss'],
|
||||||
host: {class: 'adf-viewer'},
|
host: { class: 'adf-viewer' },
|
||||||
encapsulation: ViewEncapsulation.None,
|
encapsulation: ViewEncapsulation.None,
|
||||||
providers: [ViewUtilService]
|
providers: [ViewUtilService]
|
||||||
})
|
})
|
||||||
export class ViewerComponent<T> implements OnDestroy, OnInit, OnChanges {
|
export class ViewerComponent<T> implements OnDestroy, OnInit, OnChanges {
|
||||||
|
|
||||||
@ContentChild(ViewerToolbarComponent)
|
@ContentChild(ViewerToolbarComponent)
|
||||||
toolbar: ViewerToolbarComponent;
|
toolbar: ViewerToolbarComponent;
|
||||||
|
|
||||||
@@ -220,24 +219,23 @@ export class ViewerComponent<T> implements OnDestroy, OnInit, OnChanges {
|
|||||||
public downloadPromptTimer: number;
|
public downloadPromptTimer: number;
|
||||||
public downloadPromptReminderTimer: number;
|
public downloadPromptReminderTimer: number;
|
||||||
|
|
||||||
constructor(private el: ElementRef,
|
constructor(
|
||||||
|
private el: ElementRef,
|
||||||
public dialog: MatDialog,
|
public dialog: MatDialog,
|
||||||
private viewUtilsService: ViewUtilService,
|
private viewUtilsService: ViewUtilService,
|
||||||
private appConfigService: AppConfigService
|
private appConfigService: AppConfigService
|
||||||
) {
|
) {}
|
||||||
}
|
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges){
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
const { blobFile, urlFile } = changes;
|
const { blobFile, urlFile } = changes;
|
||||||
|
|
||||||
if(blobFile?.currentValue){
|
if (blobFile?.currentValue) {
|
||||||
this.mimeType = blobFile.currentValue.type;
|
this.mimeType = blobFile.currentValue.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(urlFile?.currentValue){
|
if (urlFile?.currentValue) {
|
||||||
this.fileName = this.fileName ? this.fileName : this.viewUtilsService.getFilenameFromUrl(urlFile.currentValue);
|
this.fileName = this.fileName ? this.fileName : this.viewUtilsService.getFilenameFromUrl(urlFile.currentValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
@@ -246,21 +244,27 @@ export class ViewerComponent<T> implements OnDestroy, OnInit, OnChanges {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private closeOverlayManager() {
|
private closeOverlayManager() {
|
||||||
this.dialog.afterOpened.pipe(
|
this.dialog.afterOpened
|
||||||
|
.pipe(
|
||||||
skipWhile(() => !this.overlayMode),
|
skipWhile(() => !this.overlayMode),
|
||||||
takeUntil(this.onDestroy$)
|
takeUntil(this.onDestroy$)
|
||||||
).subscribe(() => this.closeViewer = false);
|
)
|
||||||
|
.subscribe(() => (this.closeViewer = false));
|
||||||
|
|
||||||
this.dialog.afterAllClosed.pipe(
|
this.dialog.afterAllClosed
|
||||||
|
.pipe(
|
||||||
skipWhile(() => !this.overlayMode),
|
skipWhile(() => !this.overlayMode),
|
||||||
takeUntil(this.onDestroy$)
|
takeUntil(this.onDestroy$)
|
||||||
).subscribe(() => this.closeViewer = true);
|
)
|
||||||
|
.subscribe(() => (this.closeViewer = true));
|
||||||
|
|
||||||
this.keyDown$.pipe(
|
this.keyDown$
|
||||||
|
.pipe(
|
||||||
skipWhile(() => !this.overlayMode),
|
skipWhile(() => !this.overlayMode),
|
||||||
filter((e: KeyboardEvent) => e.keyCode === 27),
|
filter((e: KeyboardEvent) => e.keyCode === 27),
|
||||||
takeUntil(this.onDestroy$)
|
takeUntil(this.onDestroy$)
|
||||||
).subscribe((event: KeyboardEvent) => {
|
)
|
||||||
|
.subscribe((event: KeyboardEvent) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
if (this.closeViewer) {
|
if (this.closeViewer) {
|
||||||
@@ -295,7 +299,7 @@ export class ViewerComponent<T> implements OnDestroy, OnInit, OnChanges {
|
|||||||
|
|
||||||
@HostListener('document:keyup', ['$event'])
|
@HostListener('document:keyup', ['$event'])
|
||||||
handleKeyboardEvent(event: KeyboardEvent) {
|
handleKeyboardEvent(event: KeyboardEvent) {
|
||||||
if (event && event.defaultPrevented) {
|
if (event?.defaultPrevented) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -392,7 +396,11 @@ export class ViewerComponent<T> implements OnDestroy, OnInit, OnChanges {
|
|||||||
private showDownloadPrompt() {
|
private showDownloadPrompt() {
|
||||||
if (!this.isDialogVisible) {
|
if (!this.isDialogVisible) {
|
||||||
this.isDialogVisible = true;
|
this.isDialogVisible = true;
|
||||||
this.dialog.open(DownloadPromptDialogComponent, { disableClose: true }).afterClosed().pipe(first()).subscribe((result: DownloadPromptActions) => {
|
this.dialog
|
||||||
|
.open(DownloadPromptDialogComponent, { disableClose: true })
|
||||||
|
.afterClosed()
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe((result: DownloadPromptActions) => {
|
||||||
this.isDialogVisible = false;
|
this.isDialogVisible = false;
|
||||||
if (result === DownloadPromptActions.DOWNLOAD) {
|
if (result === DownloadPromptActions.DOWNLOAD) {
|
||||||
this.downloadFile.emit();
|
this.downloadFile.emit();
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
"extends": "./tsconfig.json",
|
"extends": "./tsconfig.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"outDir": "../../dist/out-tsc",
|
"outDir": "../../dist/out-tsc",
|
||||||
|
"declaration": true,
|
||||||
"declarationMap": true,
|
"declarationMap": true,
|
||||||
"paths": {
|
"paths": {
|
||||||
"@alfresco/adf-extensions": ["../../../dist/libs/extensions"],
|
"@alfresco/adf-extensions": ["../../../dist/libs/extensions"],
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user