mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2026-09-16 18:13:06 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fe9300c8e1 | ||
|
|
fc147074ce | ||
|
|
e42e0869ba | ||
|
|
93f45062fe | ||
|
|
ea65756660 | ||
|
|
ecbee581a7 | ||
|
|
93fe29503a | ||
|
|
441d8003af | ||
|
|
11b4f5186b | ||
|
|
c548fc7763 | ||
|
|
43242b1185 | ||
|
|
e638b54fcd | ||
|
|
0b1fc4faa4 | ||
|
|
fc8a443d32 | ||
|
|
8a6fe3071d | ||
|
|
0811525c95 | ||
|
|
a69c089f87 | ||
|
|
e76d2fb169 | ||
|
|
034e9574d0 | ||
|
|
94baaf7d33 | ||
|
|
e21ad3ca02 | ||
|
|
c2d45e10f8 | ||
|
|
21a029163a | ||
|
|
d72eb5ebd3 | ||
|
|
501516c8f5 | ||
|
|
d78dcd2156 | ||
|
|
a48438e1c1 | ||
|
|
b03011c3d2 | ||
|
|
016e5ec089 | ||
|
|
65d70bffb2 | ||
|
|
d7e0bb6cd3 | ||
|
|
a0c79e6c64 | ||
|
|
094acf77ce | ||
|
|
ed0dd094b4 | ||
|
|
a488a729eb | ||
|
|
44694c0ee1 | ||
|
|
06bfded238 | ||
|
|
4786a26320 | ||
|
|
8f684a9f6a | ||
|
|
6d8c513180 | ||
|
|
83b2d9f8bc | ||
|
|
0933e2dada | ||
|
|
926347b8fc | ||
|
|
3638ed06ef | ||
|
|
f488520752 | ||
|
|
ef551a9c71 | ||
|
|
8370a3de66 | ||
|
|
5345838744 | ||
|
|
919a8ba80c | ||
|
|
16ab6e3306 |
+21
-4
@@ -1,4 +1,3 @@
|
||||
path = require('path');
|
||||
module.exports = {
|
||||
root: true,
|
||||
ignorePatterns: [
|
||||
@@ -11,20 +10,38 @@ module.exports = {
|
||||
'**/scripts',
|
||||
'**/docs'
|
||||
],
|
||||
plugins: ['@nrwl/nx'],
|
||||
overrides: [
|
||||
{
|
||||
files: ['*.ts'],
|
||||
parserOptions: {
|
||||
project: [path.join(__dirname, 'tsconfig.json'), path.join(__dirname, 'e2e/tsconfig.e2e.json')],
|
||||
project: ['tsconfig.json', 'e2e/tsconfig.e2e.json'],
|
||||
createDefaultProgram: true
|
||||
},
|
||||
extends: [
|
||||
'plugin:@nrwl/nx/typescript',
|
||||
'plugin:@nrwl/nx/angular',
|
||||
'plugin:@cspell/recommended',
|
||||
'plugin:@angular-eslint/ng-cli-compat',
|
||||
'plugin:@angular-eslint/ng-cli-compat--formatting-add-on',
|
||||
'plugin:@angular-eslint/template/process-inline-templates'
|
||||
'plugin:@angular-eslint/template/process-inline-templates',
|
||||
'plugin:jsdoc/recommended-typescript-error'
|
||||
],
|
||||
plugins: [
|
||||
'eslint-plugin-unicorn',
|
||||
'eslint-plugin-rxjs',
|
||||
'prettier',
|
||||
'ban',
|
||||
'license-header',
|
||||
'@cspell',
|
||||
'eslint-plugin-import',
|
||||
'@angular-eslint/eslint-plugin',
|
||||
'@typescript-eslint',
|
||||
'jsdoc'
|
||||
],
|
||||
plugins: ['eslint-plugin-unicorn', 'eslint-plugin-rxjs', 'ban', 'license-header'],
|
||||
rules: {
|
||||
// Uncomment this to enable prettier checks as part of the ESLint
|
||||
// 'prettier/prettier': 'error',
|
||||
'ban/ban': [
|
||||
'error',
|
||||
{ name: 'eval', message: 'Calls to eval is not allowed.' },
|
||||
|
||||
@@ -210,16 +210,6 @@
|
||||
"demo-shell/**/*.html"
|
||||
]
|
||||
}
|
||||
},
|
||||
"spellcheck": {
|
||||
"executor": "nx:run-commands",
|
||||
"options": {
|
||||
"commands": [
|
||||
{
|
||||
"command": "npx cspell 'demo-shell/**/*.ts'"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -346,16 +336,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"spellcheck": {
|
||||
"executor": "nx:run-commands",
|
||||
"options": {
|
||||
"commands": [
|
||||
{
|
||||
"command": "npx cspell 'lib/core/**/*.ts'"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"stylelint": {
|
||||
"executor": "nx:run-commands",
|
||||
"options": {
|
||||
@@ -484,16 +464,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"spellcheck": {
|
||||
"executor": "nx:run-commands",
|
||||
"options": {
|
||||
"commands": [
|
||||
{
|
||||
"command": "npx cspell 'lib/content-services/**/*.ts'"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"stylelint": {
|
||||
"executor": "nx:run-commands",
|
||||
"options": {
|
||||
@@ -560,26 +530,6 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"spellcheck": {
|
||||
"executor": "nx:run-commands",
|
||||
"options": {
|
||||
"commands": [
|
||||
{
|
||||
"command": "npx cspell 'lib/process-services/**/*.ts'"
|
||||
}
|
||||
]
|
||||
},
|
||||
"stylelint": {
|
||||
"executor": "nx:run-commands",
|
||||
"options": {
|
||||
"commands": [
|
||||
{
|
||||
"command": "npx stylelint lib/process-services/**/*.scss --config stylelint-config.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"stylelint": {
|
||||
"executor": "nx:run-commands",
|
||||
"options": {
|
||||
@@ -699,16 +649,6 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"spellcheck": {
|
||||
"executor": "nx:run-commands",
|
||||
"options": {
|
||||
"commands": [
|
||||
{
|
||||
"command": "npx cspell 'lib/process-services-cloud/**/*.ts'"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"stylelint": {
|
||||
"executor": "nx:run-commands",
|
||||
"options": {
|
||||
@@ -775,16 +715,6 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"spellcheck": {
|
||||
"executor": "nx:run-commands",
|
||||
"options": {
|
||||
"commands": [
|
||||
{
|
||||
"command": "npx cspell 'lib/insights/**/*.ts'"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"stylelint": {
|
||||
"executor": "nx:run-commands",
|
||||
"options": {
|
||||
@@ -848,17 +778,6 @@
|
||||
"lib/extensions/**/*.ts",
|
||||
"lib/extensions/**/*.html"
|
||||
]
|
||||
},
|
||||
"dependsOn": ["spellcheck"]
|
||||
},
|
||||
"spellcheck": {
|
||||
"executor": "nx:run-commands",
|
||||
"options": {
|
||||
"commands": [
|
||||
{
|
||||
"command": "npx cspell 'lib/extensions/**/*.ts'"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"npm-publish": {
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
"docx",
|
||||
"dropdownrestprocess",
|
||||
"Droppable",
|
||||
"dryrun",
|
||||
"ECMBPM",
|
||||
"ECMHOST",
|
||||
"Examinate",
|
||||
@@ -125,6 +126,7 @@
|
||||
"typeahed",
|
||||
"uncheck",
|
||||
"Unclaim",
|
||||
"Undeployed",
|
||||
"unfavorite",
|
||||
"unlisten",
|
||||
"unshare",
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
var port = process.env.PORT || 3000,
|
||||
http = require('http'),
|
||||
fs = require('fs'),
|
||||
url = require('url'),
|
||||
mime = require('mime'),
|
||||
html = fs.readFileSync('index.html');
|
||||
|
||||
var log = function(entry) {
|
||||
fs.appendFileSync('/tmp/sample-app.log', new Date().toISOString() + ' - ' + entry + '\n');
|
||||
};
|
||||
|
||||
var server = http.createServer(function (req, res) {
|
||||
|
||||
// Parse the request containing file name
|
||||
var pathname = url.parse(req.url).pathname;
|
||||
|
||||
// Print the name of the file for which request is made.
|
||||
console.log("Request for " + pathname + " received.");
|
||||
|
||||
if (req.method === 'POST') {
|
||||
var body = '';
|
||||
|
||||
req.on('data', function(chunk) {
|
||||
body += chunk;
|
||||
});
|
||||
|
||||
req.on('end', function() {
|
||||
if (req.url === '/') {
|
||||
log('Received message: ' + body);
|
||||
} else if (req.url === '/scheduled') {
|
||||
log('Received task ' + req.headers['x-aws-sqsd-taskname'] + ' scheduled at ' + req.headers['x-aws-sqsd-scheduled-at']);
|
||||
}
|
||||
|
||||
res.writeHead(200, 'OK', {'Content-Type': 'text/plain'});
|
||||
res.end();
|
||||
});
|
||||
} else {
|
||||
var filename = pathname.substr(1);
|
||||
if(filename === '' || filename.indexOf('.') === -1){
|
||||
filename = 'index.html';
|
||||
}
|
||||
// Read the requested file content from file system
|
||||
fs.readFile(filename, function (err, data) {
|
||||
if (err) {
|
||||
console.log(err, filename);
|
||||
// HTTP Status: 404 : NOT FOUND
|
||||
// Content Type: text/plain
|
||||
res.writeHead(404, {'Content-Type': 'text/html'});
|
||||
}else{
|
||||
//Page found
|
||||
// HTTP Status: 200 : OK
|
||||
// Content Type: text/plain
|
||||
var type = mime.lookup(filename);
|
||||
console.log('type',type);
|
||||
if (!res.getHeader('content-type')) {
|
||||
var charset = mime.charsets.lookup(type);
|
||||
res.setHeader('Content-Type', type + (charset ? '; charset=' + charset : ''));
|
||||
}
|
||||
if(type.indexOf('image') > -1 || type.indexOf('font') > -1){
|
||||
var img = fs.readFileSync(pathname.substr(1));
|
||||
res.end(img, 'binary');
|
||||
}else{
|
||||
res.write(data.toString());
|
||||
}
|
||||
// Write the content of the file to response body
|
||||
}
|
||||
// Send the response body
|
||||
res.end();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Listen on port 3000, IP defaults to 127.0.0.1
|
||||
server.listen(port);
|
||||
|
||||
// Put a friendly message on the terminal
|
||||
console.log('Server running at http://127.0.0.1:' + port + '/');
|
||||
@@ -53,7 +53,7 @@ export class CloudFiltersDemoComponent implements OnInit {
|
||||
this.currentProcessFilter$ = this.cloudLayoutService.processFilter$;
|
||||
|
||||
let root = '';
|
||||
if (this.route.snapshot && this.route.snapshot.firstChild) {
|
||||
if (this.route.snapshot?.firstChild) {
|
||||
root = this.route.snapshot.firstChild.url[0].path;
|
||||
if (root === 'tasks') {
|
||||
this.expandTaskFilter = true;
|
||||
|
||||
@@ -41,7 +41,7 @@ export class CloudLayoutComponent implements OnInit {
|
||||
this.appName = params.appName;
|
||||
});
|
||||
|
||||
if (this.route.snapshot && this.route.snapshot.firstChild) {
|
||||
if (this.route.snapshot?.firstChild) {
|
||||
root = this.route.snapshot.firstChild.url[0].path;
|
||||
}
|
||||
|
||||
|
||||
@@ -185,7 +185,7 @@ export class ProcessesCloudDemoComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
private loadFilter(model: ProcessFilterCloudModel) {
|
||||
if (model && model.appName && model.id) {
|
||||
if (model?.appName && model.id) {
|
||||
this.editedFilter = model;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ export class FileViewComponent implements OnInit {
|
||||
if (id) {
|
||||
this.nodeApiService.getNode(id).subscribe(
|
||||
(node) => {
|
||||
if (node && node.isFile) {
|
||||
if (node?.isFile) {
|
||||
this.isCommentEnabled = this.contentServices.hasPermissions(node, PermissionsEnum.NOT_CONSUMER) ||
|
||||
this.contentServices.hasAllowableOperations(node, AllowableOperationsEnum.UPDATE);
|
||||
this.nodeId = id;
|
||||
|
||||
@@ -231,7 +231,7 @@ export class FilesComponent implements OnInit, OnChanges, OnDestroy {
|
||||
|
||||
showFile(event) {
|
||||
const entry = event.value.entry;
|
||||
if (entry && entry.isFile) {
|
||||
if (entry?.isFile) {
|
||||
this.preview.showResource(entry.id);
|
||||
}
|
||||
}
|
||||
@@ -296,7 +296,7 @@ export class FilesComponent implements OnInit, OnChanges, OnDestroy {
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (changes.nodeResult && changes.nodeResult.currentValue) {
|
||||
if (changes.nodeResult?.currentValue) {
|
||||
this.nodeResult = changes.nodeResult.currentValue;
|
||||
this.pagination = this.nodeResult.list.pagination;
|
||||
}
|
||||
@@ -468,7 +468,7 @@ export class FilesComponent implements OnInit, OnChanges, OnDestroy {
|
||||
if (selection && selection.length === 1) {
|
||||
const entry = selection[0].entry;
|
||||
|
||||
if (entry && entry.isFolder) {
|
||||
if (entry?.isFolder) {
|
||||
return this.contentService.hasAllowableOperations(entry, 'update');
|
||||
}
|
||||
}
|
||||
@@ -570,7 +570,7 @@ export class FilesComponent implements OnInit, OnChanges, OnDestroy {
|
||||
}
|
||||
|
||||
searchResultsHighlight(search: SearchEntry): string {
|
||||
if (search && search.highlight) {
|
||||
if (search?.highlight) {
|
||||
return search.highlight.map((currentHighlight) => currentHighlight.snippets).join(', ');
|
||||
}
|
||||
return '';
|
||||
@@ -588,7 +588,7 @@ export class FilesComponent implements OnInit, OnChanges, OnDestroy {
|
||||
const objectFromMap = {};
|
||||
activeFilters.forEach((filter: FilterSearch) => {
|
||||
let paramValue = null;
|
||||
if (filter.value && filter.value.from && filter.value.to) {
|
||||
if (filter.value?.from && filter.value.to) {
|
||||
paramValue = `${filter.value.from}||${filter.value.to}`;
|
||||
} else {
|
||||
paramValue = filter.value;
|
||||
|
||||
@@ -41,9 +41,9 @@ export class VersionManagerDialogAdapterComponent {
|
||||
private containingDialog?: MatDialogRef<VersionManagerDialogAdapterComponent>
|
||||
) {
|
||||
this.contentEntry = data.contentEntry;
|
||||
this.newFileVersion = data.hasOwnProperty('newFileVersion') ? data.newFileVersion : this.newFileVersion;
|
||||
this.showComments = data.hasOwnProperty('showComments') ? data.showComments : this.showComments;
|
||||
this.allowDownload = data.hasOwnProperty('allowDownload') ? data.allowDownload : this.allowDownload;
|
||||
this.newFileVersion = Object.prototype.hasOwnProperty.call(data, 'newFileVersion') ? data.newFileVersion : this.newFileVersion;
|
||||
this.showComments = Object.prototype.hasOwnProperty.call(data, 'showComments') ? data.showComments : this.showComments;
|
||||
this.allowDownload = Object.prototype.hasOwnProperty.call(data, 'allowDownload') ? data.allowDownload : this.allowDownload;
|
||||
}
|
||||
|
||||
uploadError(event: FileUploadErrorEvent) {
|
||||
|
||||
@@ -124,7 +124,7 @@ export class ProcessListDemoComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
isFormValid() {
|
||||
return this.processListForm && this.processListForm.dirty && this.processListForm.valid;
|
||||
return this.processListForm?.dirty && this.processListForm.valid;
|
||||
}
|
||||
|
||||
resetProcessForm() {
|
||||
|
||||
@@ -28,6 +28,14 @@ import { PreviewService } from '../../services/preview.service';
|
||||
import { Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
|
||||
/**
|
||||
* Provide a factory for process upload service
|
||||
*
|
||||
* @param api api client
|
||||
* @param config config service
|
||||
* @param discoveryApiService discovery service
|
||||
* @returns factory function
|
||||
*/
|
||||
export function processUploadServiceFactory(api: AlfrescoApiService, config: AppConfigService, discoveryApiService: DiscoveryApiService) {
|
||||
return new ProcessUploadService(api, config, discoveryApiService);
|
||||
}
|
||||
@@ -93,7 +101,7 @@ export class ProcessAttachmentsComponent implements OnInit, OnChanges, OnDestroy
|
||||
}
|
||||
|
||||
isCompletedProcess(): boolean {
|
||||
return this.processInstance && this.processInstance.ended !== undefined && this.processInstance.ended !== null;
|
||||
return this.processInstance?.ended != null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -180,7 +180,7 @@ export class ProcessServiceComponent implements AfterViewInit, OnDestroy, OnInit
|
||||
.subscribe(
|
||||
(validateDynamicTableRowEvent: ValidateDynamicTableRowEvent) => {
|
||||
const row: DynamicTableRow = validateDynamicTableRowEvent.row;
|
||||
if (row && row.value && row.value.name === 'admin') {
|
||||
if (row?.value && row.value.name === 'admin') {
|
||||
validateDynamicTableRowEvent.summary.isValid = false;
|
||||
validateDynamicTableRowEvent.summary.message = 'Sorry, wrong value. You cannot use "admin".';
|
||||
validateDynamicTableRowEvent.preventDefault();
|
||||
|
||||
@@ -28,6 +28,14 @@ import { PreviewService } from '../../services/preview.service';
|
||||
import { Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
|
||||
/**
|
||||
* Provide a task upload service factory
|
||||
*
|
||||
* @param api api client
|
||||
* @param config config service
|
||||
* @param discoveryApiService discovery service
|
||||
* @returns factory function
|
||||
*/
|
||||
export function taskUploadServiceFactory(api: AlfrescoApiService, config: AppConfigService, discoveryApiService: DiscoveryApiService) {
|
||||
return new TaskUploadService(api, config, discoveryApiService);
|
||||
}
|
||||
@@ -92,7 +100,7 @@ export class TaskAttachmentsComponent implements OnInit, OnChanges, OnDestroy {
|
||||
}
|
||||
|
||||
isCompletedTask(): boolean {
|
||||
return this.taskDetails && this.taskDetails.endDate !== undefined && this.taskDetails.endDate !== null;
|
||||
return this.taskDetails?.endDate != null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ export class SearchFilterChipsComponent implements OnInit, OnDestroy {
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.subscribe(([params, searchConfig]) => {
|
||||
this.updateSearchSetting(searchConfig);
|
||||
this.searchedWord = params.hasOwnProperty(this.queryParamName) ? params[this.queryParamName] : null;
|
||||
this.searchedWord = Object.prototype.hasOwnProperty.call(params, this.queryParamName) ? params[this.queryParamName] : null;
|
||||
const query = this.formatSearchQuery(this.searchedWord, searchConfig['app:fields']);
|
||||
if (query) {
|
||||
this.queryBuilder.userQuery = query;
|
||||
@@ -87,7 +87,7 @@ export class SearchFilterChipsComponent implements OnInit, OnDestroy {
|
||||
|
||||
if (this.route) {
|
||||
this.route.params.forEach((params: Params) => {
|
||||
this.searchedWord = params.hasOwnProperty(this.queryParamName) ? params[this.queryParamName] : null;
|
||||
this.searchedWord = Object.prototype.hasOwnProperty.call(params, this.queryParamName) ? params[this.queryParamName] : null;
|
||||
if (this.searchedWord) {
|
||||
this.queryBuilder.update();
|
||||
} else {
|
||||
|
||||
@@ -50,7 +50,7 @@ export class SearchResultComponent implements OnInit, OnDestroy {
|
||||
combineLatest([this.route.params, this.queryBuilder.configUpdated])
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.subscribe(([params, searchConfig]) => {
|
||||
this.searchedWord = params.hasOwnProperty(this.queryParamName) ? params[this.queryParamName] : null;
|
||||
this.searchedWord = Object.prototype.hasOwnProperty.call(params, this.queryParamName) ? params[this.queryParamName] : null;
|
||||
const query = this.formatSearchQuery(this.searchedWord, searchConfig['app:fields']);
|
||||
if (query) {
|
||||
this.queryBuilder.userQuery = query;
|
||||
@@ -86,7 +86,7 @@ export class SearchResultComponent implements OnInit, OnDestroy {
|
||||
|
||||
if (this.route) {
|
||||
this.route.params.forEach((params: Params) => {
|
||||
this.searchedWord = params.hasOwnProperty(this.queryParamName) ? params[this.queryParamName] : null;
|
||||
this.searchedWord = Object.prototype.hasOwnProperty.call(params, this.queryParamName) ? params[this.queryParamName] : null;
|
||||
if (this.searchedWord) {
|
||||
this.queryBuilder.update();
|
||||
} else {
|
||||
|
||||
@@ -21,7 +21,7 @@ import { AppConfigService, AppConfigValues, StorageService, AlfrescoApiService,
|
||||
import { ENTER } from '@angular/cdk/keycodes';
|
||||
import { MAT_FORM_FIELD_DEFAULT_OPTIONS } from '@angular/material/form-field';
|
||||
|
||||
export const HOST_REGEX = '^(http|https):\/\/.*[^/]$';
|
||||
export const HOST_REGEX = '^(http|https)://.*[^/]$';
|
||||
|
||||
@Component({
|
||||
providers: [{ provide: MAT_FORM_FIELD_DEFAULT_OPTIONS, useValue: { floatLabel: 'always' } }],
|
||||
|
||||
@@ -190,7 +190,7 @@ export class TaskListDemoComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
isFormValid() {
|
||||
return this.taskListForm && this.taskListForm.dirty && this.taskListForm.valid;
|
||||
return this.taskListForm?.dirty && this.taskListForm.valid;
|
||||
}
|
||||
|
||||
private getControl<T extends AbstractControl>(key: string): T {
|
||||
|
||||
@@ -60,6 +60,7 @@ Defines column properties for DataTable, Tasklist, Document List and other compo
|
||||
| srTitle | `string` | | Title to be used for screen readers. |
|
||||
| title | `string` | "" | Display title of the column, typically used for column headers. You can use the i18n resource key to get it translated automatically. |
|
||||
| type | `string` | "text" | Value type for the column. Possible settings are 'text', 'image', 'date', 'fileSize', 'location', and 'json'. |
|
||||
| order | `number` | | Sets position of column. |
|
||||
|
||||
## Details
|
||||
|
||||
|
||||
@@ -62,6 +62,12 @@ Manipulates content related to a Process Instance or Task Instance in APS.
|
||||
- _taskId:_ `string` - ID of the target task
|
||||
- _opts:_ `any` - (Optional) Options supported by JS-API
|
||||
- **Returns** [`Observable`](http://reactivex.io/documentation/observable.html)`<any>` - Metadata for the content
|
||||
- **getProcessesAndTasksOnContent**(sourceId: `string`, source: `string`, size?: `number`, page?: `number`): [`Observable`](http://reactivex.io/documentation/observable.html)<[`ResultListDataRepresentationRelatedProcessTask`](https://github.com/Alfresco/alfresco-js-api/blob/develop/src/api/activiti-rest-api/docs/ResultListDataRepresentation%C2%ABRelatedContentRepresentation%C2%BB.md)><br/>
|
||||
Lists processes and tasks on workflow started with provided document
|
||||
- _sourceId:_ `string` - id of the document that workflow or task has been started with
|
||||
- _source:_ `string` - source of the document that workflow or task has been started with
|
||||
- _size:_ `number` - size of the entries to get
|
||||
- _page:_ `number` - page number
|
||||
- **handleError**(error: `any`): [`Observable`](http://reactivex.io/documentation/observable.html)`<any>`<br/>
|
||||
Reports an error message.
|
||||
- _error:_ `any` - Data object with optional `message` and `status` fields for the error
|
||||
@@ -377,6 +383,21 @@ this.contentService.getTaskRelatedContent(taskId).subscribe(
|
||||
|
||||
The response format is the same as for the `getProcessRelatedContent` method, see its docs.
|
||||
|
||||
#### getProcessesAndTasksOnContent(sourceId: string, source: string, size?: number, page?: number): Observable`<ResultListDataRepresentationRelatedProcessTask>`
|
||||
|
||||
Lists processes and tasks on workflow started with provided document.
|
||||
|
||||
```ts
|
||||
const sourceId = 'sourceId';
|
||||
const source = 'source';
|
||||
this.contentService.getProcessesAndTasksOnContent(sourceId, source).subscribe(
|
||||
res => {
|
||||
console.log('Response: ', res);
|
||||
}, error => {
|
||||
console.log('Error: ', error);
|
||||
});
|
||||
```
|
||||
|
||||
## Details
|
||||
|
||||
## Importing
|
||||
|
||||
@@ -17,11 +17,11 @@
|
||||
|
||||
import { ContentServicesPage } from '../../core/pages/content-services.page';
|
||||
import { browser } from 'protractor';
|
||||
import { createApiService, LoginPage, StringUtil, UploadActions, UsersActions, ViewerPage } from '@alfresco/adf-testing';
|
||||
import { createApiService, LoginPage, StringUtil, UploadActions, UserModel, UsersActions, ViewerPage } from '@alfresco/adf-testing';
|
||||
import { FileModel } from '../../models/ACS/file.model';
|
||||
import * as moment from 'moment';
|
||||
import { NavigationBarPage } from '../../core/pages/navigation-bar.page';
|
||||
import { NodeEntry } from '@alfresco/js-api';
|
||||
import { DateFnsUtils } from '../../../lib/core/src/lib/common/utils/date-fns-utils';
|
||||
|
||||
describe('Document List Component', () => {
|
||||
let uploadedFolder: NodeEntry;
|
||||
@@ -35,9 +35,9 @@ describe('Document List Component', () => {
|
||||
const usersActions = new UsersActions(apiService);
|
||||
|
||||
const uploadActions = new UploadActions(apiService);
|
||||
let acsUser = null;
|
||||
let testFileNode: any;
|
||||
let pdfBFileNode: any;
|
||||
let acsUser: UserModel = null;
|
||||
let testFileNode: NodeEntry;
|
||||
let pdfBFileNode: NodeEntry;
|
||||
|
||||
afterEach(async () => {
|
||||
await apiService.loginWithProfile('admin');
|
||||
@@ -78,7 +78,10 @@ describe('Document List Component', () => {
|
||||
location: browser.params.resources.Files.ADF_DOCUMENTS.PDF_B.file_path
|
||||
});
|
||||
|
||||
let pdfUploadedNode; let docxUploadedNode; let timeAgoUploadedNode; let mediumDateUploadedNode;
|
||||
let pdfUploadedNode: NodeEntry;
|
||||
let docxUploadedNode: NodeEntry;
|
||||
let timeAgoUploadedNode: NodeEntry;
|
||||
let mediumDateUploadedNode: NodeEntry;
|
||||
|
||||
beforeAll(async () => {
|
||||
/* cspell:disable-next-line */
|
||||
@@ -146,7 +149,7 @@ describe('Document List Component', () => {
|
||||
it('[C279929] Should be able to display the date with date type', async () => {
|
||||
await apiService.login(acsUser.username, acsUser.password);
|
||||
mediumDateUploadedNode = await uploadActions.uploadFile(mediumFileModel.location, mediumFileModel.name, '-my-');
|
||||
const createdDate = moment(mediumDateUploadedNode.createdAt).format('ll');
|
||||
const createdDate = DateFnsUtils.formatDate(mediumDateUploadedNode.entry.createdAt, 'll');
|
||||
await contentServicesPage.goToDocumentList();
|
||||
await contentServicesPage.enableMediumTimeFormat();
|
||||
const dateValue = await contentServicesPage.getColumnValueForRow(mediumFileModel.name, 'Created');
|
||||
|
||||
@@ -35,7 +35,8 @@ import { NavigationBarPage } from '../../core/pages/navigation-bar.page';
|
||||
import { ProcessListPage } from '../../process-services/pages/process-list.page';
|
||||
import { EditProcessFilterConfiguration } from './../config/edit-process-filter.config';
|
||||
import { ProcessListCloudConfiguration } from './../config/process-list-cloud.config';
|
||||
import * as moment from 'moment';
|
||||
import { addDays, format, subDays } from 'date-fns';
|
||||
|
||||
|
||||
describe('Process filters cloud', () => {
|
||||
|
||||
@@ -66,9 +67,9 @@ describe('Process filters cloud', () => {
|
||||
const queryService = new QueryService(apiService);
|
||||
const tasksService = new TasksService(apiService);
|
||||
|
||||
const beforeDate = moment().add(-1, 'days').format('DD/MM/YYYY');
|
||||
const beforeDate = format(subDays(new Date(), 1), 'dd/MM/yyyy');
|
||||
const currentDate = DateUtil.formatDate('DD/MM/YYYY');
|
||||
const afterDate = moment().add(1, 'days').format('DD/MM/YYYY');
|
||||
const afterDate = format(addDays(new Date(), 1), 'dd/MM/yyyy');
|
||||
const processListCloudConfiguration = new ProcessListCloudConfiguration();
|
||||
const editProcessFilterConfiguration = new EditProcessFilterConfiguration();
|
||||
const processListCloudConfigFile = processListCloudConfiguration.getConfiguration();
|
||||
|
||||
@@ -21,8 +21,8 @@ import { ProcessCloudDemoPage } from './../pages/process-cloud-demo.page';
|
||||
import { TasksCloudDemoPage } from './../pages/tasks-cloud-demo.page';
|
||||
import { NavigationBarPage } from '../../core/pages/navigation-bar.page';
|
||||
import CONSTANTS = require('../../util/constants');
|
||||
import * as moment from 'moment';
|
||||
import { EditProcessFilterConfiguration } from './../config/edit-process-filter.config';
|
||||
import { DateFnsUtils } from '../../../lib/core/src/lib/common/utils/date-fns-utils';
|
||||
|
||||
describe('Process Header cloud component', () => {
|
||||
|
||||
@@ -76,7 +76,7 @@ describe('Process Header cloud component', () => {
|
||||
runningProcess = await processInstancesService.createProcessInstance(simpleProcess.entry.key,
|
||||
simpleApp, { name: StringUtil.generateRandomString(), businessKey: 'test' });
|
||||
|
||||
runningCreatedDate = moment(runningProcess.entry.startDate).format(formatDate);
|
||||
runningCreatedDate = DateFnsUtils.formatDate(new Date(runningProcess.entry.startDate), formatDate);
|
||||
|
||||
parentCompleteProcess = await processInstancesService.createProcessInstance(processparent.entry.key,
|
||||
subProcessApp);
|
||||
@@ -86,7 +86,7 @@ describe('Process Header cloud component', () => {
|
||||
|
||||
childCompleteProcess = parentProcessInstance.list.entries[0];
|
||||
|
||||
completedCreatedDate = moment(childCompleteProcess.entry.startDate).format(formatDate);
|
||||
completedCreatedDate = DateFnsUtils.formatDate(new Date(childCompleteProcess.entry.startDate), formatDate);
|
||||
|
||||
await loginSSOPage.login(testUser.username, testUser.password);
|
||||
await LocalStorageUtil.setConfigField('adf-edit-process-filter', JSON.stringify(editProcessFilterConfigFile));
|
||||
|
||||
@@ -29,7 +29,7 @@ import { createApiService,
|
||||
import { browser } from 'protractor';
|
||||
import { TasksCloudDemoPage } from './../pages/tasks-cloud-demo.page';
|
||||
import { NavigationBarPage } from '../../core/pages/navigation-bar.page';
|
||||
import * as moment from 'moment';
|
||||
import { DateFnsUtils } from '../../../lib/core/src/lib/common/utils/date-fns-utils';
|
||||
|
||||
const isValueInvalid = (value: any): boolean => value === null || value === undefined;
|
||||
|
||||
@@ -91,7 +91,7 @@ describe('Task Header cloud component', () => {
|
||||
const createdTaskId = await tasksService.createStandaloneTask(basicCreatedTaskName, simpleApp);
|
||||
await tasksService.claimTask(createdTaskId.entry.id, simpleApp);
|
||||
basicCreatedTask = await tasksService.getTask(createdTaskId.entry.id, simpleApp);
|
||||
basicCreatedDate = moment(basicCreatedTask.entry.createdDate).format(formatDate);
|
||||
basicCreatedDate = DateFnsUtils.formatDate(new Date(basicCreatedTask.entry.createdDate), formatDate);
|
||||
return createdTaskId;
|
||||
};
|
||||
|
||||
@@ -109,12 +109,12 @@ describe('Task Header cloud component', () => {
|
||||
|
||||
completedTask = await createCompletedTask();
|
||||
|
||||
completedCreatedDate = moment(completedTask.entry.createdDate).format(formatDate);
|
||||
dueDate = moment(completedTask.entry.dueDate).format(dateTimeFormat);
|
||||
completedEndDate = moment(completedTask.entry.endDate).format(formatDate);
|
||||
completedCreatedDate = DateFnsUtils.formatDate(new Date(completedTask.entry.createdDate), formatDate);
|
||||
dueDate = DateFnsUtils.formatDate(new Date(completedTask.entry.dueDate), dateTimeFormat);
|
||||
completedEndDate = DateFnsUtils.formatDate(new Date(completedTask.entry.completedDate), formatDate);
|
||||
|
||||
subTask = await createSubTask(createdTaskId);
|
||||
subTaskCreatedDate = moment(subTask.entry.createdDate).format(formatDate);
|
||||
subTaskCreatedDate = DateFnsUtils.formatDate(new Date(subTask.entry.createdDate), formatDate);
|
||||
|
||||
await browser.sleep(3000);
|
||||
await loginSSOPage.login(testUser.username, testUser.password);
|
||||
|
||||
@@ -25,8 +25,8 @@ import {
|
||||
import { NavigationBarPage } from '../../core/pages/navigation-bar.page';
|
||||
import { TasksCloudDemoPage } from './../pages/tasks-cloud-demo.page';
|
||||
import { TaskListCloudConfiguration } from './../config/task-list-cloud.config';
|
||||
import * as moment from 'moment';
|
||||
import { taskFilterConfiguration } from './../config/task-filter.config';
|
||||
import { addDays, format, subDays } from 'date-fns';
|
||||
|
||||
describe('Edit task filters and task list properties', () => {
|
||||
|
||||
@@ -54,9 +54,9 @@ describe('Edit task filters and task list properties', () => {
|
||||
let otherOwnerTask; let testUser; let groupInfo; let simpleTask;
|
||||
const priority = 1;
|
||||
|
||||
const beforeDate = moment().add(-1, 'days').format('DD/MM/YYYY');
|
||||
const beforeDate = format(subDays(new Date(), 1), 'dd/MM/yyyy');
|
||||
const currentDate = DateUtil.formatDate('DD/MM/YYYY');
|
||||
const afterDate = moment().add(1, 'days').format('DD/MM/YYYY');
|
||||
const afterDate = format(addDays(new Date(), 1), 'dd/MM/yyyy');
|
||||
|
||||
beforeAll(async () => {
|
||||
await apiService.loginWithProfile('identityAdmin');
|
||||
|
||||
@@ -39,7 +39,7 @@ export class FiltersPage {
|
||||
}
|
||||
|
||||
async getAllRowsNameColumn(): Promise<string[]> {
|
||||
return this.dataTable.getAllRowsColumnValues('Name');
|
||||
return this.dataTable.getAllRowsColumnValues('Task Name');
|
||||
}
|
||||
|
||||
async checkFilterIsHighlighted(filterName: string): Promise<void> {
|
||||
|
||||
@@ -28,29 +28,29 @@ export class TasksListPage {
|
||||
return this.dataTable;
|
||||
}
|
||||
|
||||
getRowsDisplayedWithSameName(taskName: string): Promise<string> {
|
||||
return this.dataTable.getRowsWithSameColumnValues('Name', taskName);
|
||||
getRowsDisplayedWithSameName(taskName: string, column = 'Task Name'): Promise<string> {
|
||||
return this.dataTable.getRowsWithSameColumnValues(column, taskName);
|
||||
}
|
||||
|
||||
async checkContentIsDisplayed(taskName: string): Promise<void> {
|
||||
await this.dataTable.checkContentIsDisplayed('Name', taskName);
|
||||
async checkContentIsDisplayed(taskName: string, column = 'Task Name'): Promise<void> {
|
||||
await this.dataTable.checkContentIsDisplayed(column, taskName);
|
||||
}
|
||||
|
||||
async checkContentIsNotDisplayed(taskName: string): Promise<void> {
|
||||
await this.dataTable.checkContentIsNotDisplayed('Name', taskName);
|
||||
async checkContentIsNotDisplayed(taskName: string, column = 'Task Name'): Promise<void> {
|
||||
await this.dataTable.checkContentIsNotDisplayed(column, taskName);
|
||||
}
|
||||
|
||||
async checkRowIsSelected(taskName: string): Promise<void> {
|
||||
await this.dataTable.checkRowIsSelected('Name', taskName);
|
||||
await this.dataTable.checkRowIsSelected('Task Name', taskName);
|
||||
}
|
||||
|
||||
async selectRow(taskName: string): Promise<void> {
|
||||
await this.dataTable.selectRow('Name', taskName);
|
||||
await this.dataTable.selectRow('Task Name', taskName);
|
||||
await browser.sleep(1000);
|
||||
}
|
||||
|
||||
getAllRowsNameColumn(): Promise<string[]> {
|
||||
return this.dataTable.getAllRowsColumnValues('Name');
|
||||
getAllRowsNameColumn(column = 'Task Name'): Promise<string[]> {
|
||||
return this.dataTable.getAllRowsColumnValues(column);
|
||||
}
|
||||
|
||||
async checkTaskListIsLoaded(): Promise<void> {
|
||||
|
||||
@@ -22,8 +22,8 @@ import { NavigationBarPage } from '../../core/pages/navigation-bar.page';
|
||||
import { ProcessServiceTabBarPage } from '../pages/process-service-tab-bar.page';
|
||||
import { ProcessListPage } from '../pages/process-list.page';
|
||||
import { ProcessDetailsPage } from '../pages/process-details.page';
|
||||
import * as moment from 'moment';
|
||||
import { AppDefinitionRepresentation, ProcessInstanceRepresentation, ProcessInstancesApi } from '@alfresco/js-api';
|
||||
import { DateFnsUtils } from '../../../lib/core/src/lib/common/utils/date-fns-utils';
|
||||
|
||||
describe('Process Instance Details', () => {
|
||||
const app = browser.params.resources.Files.SIMPLE_APP_WITH_USER_FORM;
|
||||
@@ -76,6 +76,6 @@ describe('Process Instance Details', () => {
|
||||
|
||||
it('[C307031] Should display the created date in the default format', async () => {
|
||||
await processDetailsPage.checkProcessHeaderDetailsAreVisible();
|
||||
await expect(await processDetailsPage.getCreated()).toEqual(moment(process.started).format(PROCESS_DATE_FORMAT));
|
||||
await expect(await processDetailsPage.getCreated()).toEqual(DateFnsUtils.formatDate(process.started, PROCESS_DATE_FORMAT));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -132,7 +132,7 @@ describe('Start Task - Custom App', () => {
|
||||
await expect(await paginationPage.getPaginationRange()).toEqual('Showing 1-' + nrOfTasks + ' of ' + nrOfTasks);
|
||||
await expect(await taskListSinglePage.taskList().getDataTable().numberOfRows()).toBe(nrOfTasks);
|
||||
|
||||
await taskListSinglePage.taskList().getAllRowsNameColumn().then(async (list) => {
|
||||
await taskListSinglePage.taskList().getAllRowsNameColumn('Name').then(async (list) => {
|
||||
await expect(ArrayUtil.arrayContainsArray(list, allTasksName)).toEqual(true);
|
||||
});
|
||||
|
||||
@@ -150,7 +150,7 @@ describe('Start Task - Custom App', () => {
|
||||
await expect(await paginationPage.getPaginationRange()).toEqual('Showing 1-' + nrOfTasks + ' of ' + nrOfTasks);
|
||||
await expect(await taskListSinglePage.taskList().getDataTable().numberOfRows()).toBe(nrOfTasks);
|
||||
|
||||
await taskListSinglePage.taskList().getAllRowsNameColumn().then(async (list) => {
|
||||
await taskListSinglePage.taskList().getAllRowsNameColumn('Name').then(async (list) => {
|
||||
await expect(ArrayUtil.arrayContainsArray(list, allTasksName)).toEqual(true);
|
||||
});
|
||||
await paginationPage.checkNextPageButtonIsDisabled();
|
||||
@@ -164,7 +164,7 @@ describe('Start Task - Custom App', () => {
|
||||
await expect(await paginationPage.getPaginationRange()).toEqual('Showing 1-' + itemsPerPage.fiveValue * currentPage + ' of ' + nrOfTasks);
|
||||
await expect(await taskListSinglePage.taskList().getDataTable().numberOfRows()).toBe(itemsPerPage.fiveValue);
|
||||
|
||||
await taskListSinglePage.taskList().getAllRowsNameColumn().then(async (list) => {
|
||||
await taskListSinglePage.taskList().getAllRowsNameColumn('Name').then(async (list) => {
|
||||
await expect(ArrayUtil.arrayContainsArray(list, allTasksName.slice(0, 5))).toEqual(true);
|
||||
});
|
||||
|
||||
@@ -176,7 +176,7 @@ describe('Start Task - Custom App', () => {
|
||||
await expect(await paginationPage.getPaginationRange()).toEqual('Showing 6-' + itemsPerPage.fiveValue * currentPage + ' of ' + nrOfTasks);
|
||||
await expect(await taskListSinglePage.taskList().getDataTable().numberOfRows()).toBe(itemsPerPage.fiveValue);
|
||||
|
||||
await taskListSinglePage.taskList().getAllRowsNameColumn().then(async (list) => {
|
||||
await taskListSinglePage.taskList().getAllRowsNameColumn('Name').then(async (list) => {
|
||||
await expect(ArrayUtil.arrayContainsArray(list, allTasksName.slice(5, 10))).toEqual(true);
|
||||
});
|
||||
|
||||
@@ -187,7 +187,7 @@ describe('Start Task - Custom App', () => {
|
||||
await expect(await paginationPage.getPaginationRange()).toEqual('Showing 11-' + itemsPerPage.fiveValue * currentPage + ' of ' + nrOfTasks);
|
||||
await expect(await taskListSinglePage.taskList().getDataTable().numberOfRows()).toBe(itemsPerPage.fiveValue);
|
||||
|
||||
await taskListSinglePage.taskList().getAllRowsNameColumn().then(async (list) => {
|
||||
await taskListSinglePage.taskList().getAllRowsNameColumn('Name').then(async (list) => {
|
||||
await expect(ArrayUtil.arrayContainsArray(list, allTasksName.slice(10, 15))).toEqual(true);
|
||||
});
|
||||
|
||||
@@ -197,7 +197,7 @@ describe('Start Task - Custom App', () => {
|
||||
await expect(await paginationPage.getCurrentItemsPerPage()).toEqual(itemsPerPage.five);
|
||||
await expect(await paginationPage.getPaginationRange()).toEqual('Showing 16-' + itemsPerPage.fiveValue * currentPage + ' of ' + nrOfTasks);
|
||||
await expect(await taskListSinglePage.taskList().getDataTable().numberOfRows()).toBe(itemsPerPage.fiveValue);
|
||||
await taskListSinglePage.taskList().getAllRowsNameColumn().then(async (list) => {
|
||||
await taskListSinglePage.taskList().getAllRowsNameColumn('Name').then(async (list) => {
|
||||
await expect(ArrayUtil.arrayContainsArray(list, allTasksName.slice(15, 20))).toEqual(true);
|
||||
});
|
||||
});
|
||||
@@ -209,7 +209,7 @@ describe('Start Task - Custom App', () => {
|
||||
await expect(await paginationPage.getCurrentItemsPerPage()).toEqual(itemsPerPage.ten);
|
||||
await expect(await paginationPage.getPaginationRange()).toEqual('Showing 1-' + itemsPerPage.tenValue * currentPage + ' of ' + nrOfTasks);
|
||||
await expect(await taskListSinglePage.taskList().getDataTable().numberOfRows()).toBe(itemsPerPage.tenValue);
|
||||
await taskListSinglePage.taskList().getAllRowsNameColumn().then(async (list) => {
|
||||
await taskListSinglePage.taskList().getAllRowsNameColumn('Name').then(async (list) => {
|
||||
await expect(ArrayUtil.arrayContainsArray(list, allTasksName.slice(0, 10))).toEqual(true);
|
||||
});
|
||||
await paginationPage.clickOnNextPage();
|
||||
@@ -218,7 +218,7 @@ describe('Start Task - Custom App', () => {
|
||||
await expect(await paginationPage.getCurrentItemsPerPage()).toEqual(itemsPerPage.ten);
|
||||
await expect(await paginationPage.getPaginationRange()).toEqual('Showing 11-' + itemsPerPage.tenValue * currentPage + ' of ' + nrOfTasks);
|
||||
await expect(await taskListSinglePage.taskList().getDataTable().numberOfRows()).toBe(itemsPerPage.tenValue);
|
||||
await taskListSinglePage.taskList().getAllRowsNameColumn().then(async (list) => {
|
||||
await taskListSinglePage.taskList().getAllRowsNameColumn('Name').then(async (list) => {
|
||||
await expect(ArrayUtil.arrayContainsArray(list, allTasksName.slice(10, 20))).toEqual(true);
|
||||
});
|
||||
});
|
||||
@@ -230,7 +230,7 @@ describe('Start Task - Custom App', () => {
|
||||
await expect(await paginationPage.getCurrentItemsPerPage()).toEqual(itemsPerPage.fifteen);
|
||||
await expect(await paginationPage.getPaginationRange()).toEqual('Showing 1-' + itemsPerPage.fifteenValue * currentPage + ' of ' + nrOfTasks);
|
||||
await expect(await taskListSinglePage.taskList().getDataTable().numberOfRows()).toBe(itemsPerPage.fifteenValue);
|
||||
await taskListSinglePage.taskList().getAllRowsNameColumn().then(async (list) => {
|
||||
await taskListSinglePage.taskList().getAllRowsNameColumn('Name').then(async (list) => {
|
||||
await expect(ArrayUtil.arrayContainsArray(list, allTasksName.slice(0, 15))).toEqual(true);
|
||||
});
|
||||
currentPage++;
|
||||
@@ -239,7 +239,7 @@ describe('Start Task - Custom App', () => {
|
||||
await expect(await paginationPage.getCurrentItemsPerPage()).toEqual(itemsPerPage.fifteen);
|
||||
await expect(await paginationPage.getPaginationRange()).toEqual('Showing 16-' + nrOfTasks + ' of ' + nrOfTasks);
|
||||
await expect(await taskListSinglePage.taskList().getDataTable().numberOfRows()).toBe(nrOfTasks - itemsPerPage.fifteenValue);
|
||||
await taskListSinglePage.taskList().getAllRowsNameColumn().then(async (list) => {
|
||||
await taskListSinglePage.taskList().getAllRowsNameColumn('Name').then(async (list) => {
|
||||
await expect(ArrayUtil.arrayContainsArray(list, allTasksName.slice(15, 20))).toEqual(true);
|
||||
});
|
||||
});
|
||||
@@ -272,7 +272,7 @@ describe('Start Task - Custom App', () => {
|
||||
|
||||
await expect(await taskListSinglePage.taskList().getDataTable().numberOfRows()).toBe(itemsPerPage.fiveValue);
|
||||
|
||||
await taskListSinglePage.taskList().getAllRowsNameColumn().then(async (list) => {
|
||||
await taskListSinglePage.taskList().getAllRowsNameColumn('Name').then(async (list) => {
|
||||
await expect(ArrayUtil.arrayContainsArray(list, allTasksName.slice(0, 5))).toEqual(true);
|
||||
});
|
||||
|
||||
@@ -288,7 +288,7 @@ describe('Start Task - Custom App', () => {
|
||||
|
||||
await expect(await taskListSinglePage.taskList().getDataTable().numberOfRows()).toBe(itemsPerPage.fiveValue);
|
||||
|
||||
await taskListSinglePage.taskList().getAllRowsNameColumn().then(async (list) => {
|
||||
await taskListSinglePage.taskList().getAllRowsNameColumn('Name').then(async (list) => {
|
||||
await expect(ArrayUtil.arrayContainsArray(list, allTasksName.slice(5, 10))).toEqual(true);
|
||||
});
|
||||
|
||||
@@ -302,7 +302,7 @@ describe('Start Task - Custom App', () => {
|
||||
await paginationPage.checkPageSelectorIsDisplayed();
|
||||
|
||||
await expect(await taskListSinglePage.taskList().getDataTable().numberOfRows()).toBe(itemsPerPage.fiveValue);
|
||||
await taskListSinglePage.taskList().getAllRowsNameColumn().then(async (list) => {
|
||||
await taskListSinglePage.taskList().getAllRowsNameColumn('Name').then(async (list) => {
|
||||
await expect(ArrayUtil.arrayContainsArray(list, allTasksName.slice(10, 15))).toEqual(true);
|
||||
});
|
||||
|
||||
@@ -317,7 +317,7 @@ describe('Start Task - Custom App', () => {
|
||||
|
||||
await expect(await taskListSinglePage.taskList().getDataTable().numberOfRows()).toBe(itemsPerPage.fiveValue);
|
||||
|
||||
await taskListSinglePage.taskList().getAllRowsNameColumn().then(async (list) => {
|
||||
await taskListSinglePage.taskList().getAllRowsNameColumn('Name').then(async (list) => {
|
||||
await expect(ArrayUtil.arrayContainsArray(list, allTasksName.slice(15, 20))).toEqual(true);
|
||||
});
|
||||
});
|
||||
@@ -388,9 +388,9 @@ describe('Start Task - Custom App', () => {
|
||||
await taskListSinglePage.typeAppId(appRuntime.id);
|
||||
await expect(await taskListSinglePage.getAppId()).toEqual(appRuntime.id.toString());
|
||||
|
||||
await taskListSinglePage.taskList().checkContentIsDisplayed(app.taskName);
|
||||
await taskListSinglePage.taskList().checkContentIsDisplayed(app.taskName);
|
||||
await taskListSinglePage.taskList().checkContentIsNotDisplayed(paginationTasksName[13]);
|
||||
await taskListSinglePage.taskList().checkContentIsDisplayed(app.taskName, 'Name');
|
||||
await taskListSinglePage.taskList().checkContentIsDisplayed(app.taskName, 'Name');
|
||||
await taskListSinglePage.taskList().checkContentIsNotDisplayed(paginationTasksName[13], 'Name');
|
||||
});
|
||||
|
||||
it('[C280569] Should be able to see No tasks found when typing an invalid appId', async () => {
|
||||
@@ -404,8 +404,8 @@ describe('Start Task - Custom App', () => {
|
||||
await taskListSinglePage.typeTaskName(paginationTasksName[13]);
|
||||
await expect(await taskListSinglePage.getTaskName()).toEqual(paginationTasksName[13]);
|
||||
|
||||
await taskListSinglePage.taskList().checkContentIsDisplayed(paginationTasksName[13]);
|
||||
await expect((await taskListSinglePage.taskList().getRowsDisplayedWithSameName(paginationTasksName[13])).length).toBe(2);
|
||||
await taskListSinglePage.taskList().checkContentIsDisplayed(paginationTasksName[13], 'Name');
|
||||
await expect((await taskListSinglePage.taskList().getRowsDisplayedWithSameName(paginationTasksName[13], 'Name')).length).toBe(2);
|
||||
});
|
||||
|
||||
it('[C280571] Should be able to see No tasks found when typing a task name that does not exist', async () => {
|
||||
@@ -420,7 +420,7 @@ describe('Start Task - Custom App', () => {
|
||||
await taskListSinglePage.taskList().getDataTable().waitTillContentLoaded();
|
||||
await expect(await taskListSinglePage.getTaskId()).toEqual(taskWithDueDate.id);
|
||||
|
||||
await taskListSinglePage.taskList().checkContentIsDisplayed(taskWithDueDate.name);
|
||||
await taskListSinglePage.taskList().checkContentIsDisplayed(taskWithDueDate.name, 'Name');
|
||||
await expect(await taskListSinglePage.taskList().getDataTable().numberOfRows()).toBe(1);
|
||||
});
|
||||
|
||||
@@ -436,9 +436,9 @@ describe('Start Task - Custom App', () => {
|
||||
await taskListSinglePage.selectState('Completed');
|
||||
await taskListSinglePage.taskList().getDataTable().waitTillContentLoaded();
|
||||
|
||||
await taskListSinglePage.taskList().checkContentIsDisplayed(completedTasks[0].name);
|
||||
await taskListSinglePage.taskList().checkContentIsDisplayed(completedTasks[1].name);
|
||||
await taskListSinglePage.taskList().checkContentIsDisplayed(completedTasks[2].name);
|
||||
await taskListSinglePage.taskList().checkContentIsDisplayed(completedTasks[0].name, 'Name');
|
||||
await taskListSinglePage.taskList().checkContentIsDisplayed(completedTasks[1].name, 'Name');
|
||||
await taskListSinglePage.taskList().checkContentIsDisplayed(completedTasks[2].name, 'Name');
|
||||
await expect(await taskListSinglePage.taskList().getDataTable().numberOfRows()).toBe(3);
|
||||
});
|
||||
|
||||
@@ -446,11 +446,11 @@ describe('Start Task - Custom App', () => {
|
||||
await taskListSinglePage.selectState('Active');
|
||||
await taskListSinglePage.taskList().getDataTable().waitTillContentLoaded();
|
||||
|
||||
await taskListSinglePage.taskList().checkContentIsNotDisplayed(completedTasks[0].name);
|
||||
await taskListSinglePage.taskList().checkContentIsNotDisplayed(completedTasks[1].name);
|
||||
await taskListSinglePage.taskList().checkContentIsNotDisplayed(completedTasks[2].name);
|
||||
await taskListSinglePage.taskList().checkContentIsNotDisplayed(completedTasks[0].name, 'Name');
|
||||
await taskListSinglePage.taskList().checkContentIsNotDisplayed(completedTasks[1].name, 'Name');
|
||||
await taskListSinglePage.taskList().checkContentIsNotDisplayed(completedTasks[2].name, 'Name');
|
||||
|
||||
const list = await taskListSinglePage.taskList().getAllRowsNameColumn();
|
||||
const list = await taskListSinglePage.taskList().getAllRowsNameColumn('Name');
|
||||
|
||||
await expect(ArrayUtil.arrayContainsArray(list, allTasksName)).toEqual(true);
|
||||
await expect(await taskListSinglePage.taskList().getDataTable().numberOfRows()).toBe(20);
|
||||
@@ -460,11 +460,11 @@ describe('Start Task - Custom App', () => {
|
||||
await taskListSinglePage.selectState('All');
|
||||
await taskListSinglePage.taskList().getDataTable().waitTillContentLoaded();
|
||||
|
||||
await taskListSinglePage.taskList().checkContentIsDisplayed(completedTasks[0].name);
|
||||
await taskListSinglePage.taskList().checkContentIsDisplayed(completedTasks[1].name);
|
||||
await taskListSinglePage.taskList().checkContentIsDisplayed(completedTasks[2].name);
|
||||
await taskListSinglePage.taskList().checkContentIsDisplayed(completedTasks[0].name, 'Name');
|
||||
await taskListSinglePage.taskList().checkContentIsDisplayed(completedTasks[1].name, 'Name');
|
||||
await taskListSinglePage.taskList().checkContentIsDisplayed(completedTasks[2].name, 'Name');
|
||||
|
||||
const list = await taskListSinglePage.taskList().getAllRowsNameColumn();
|
||||
const list = await taskListSinglePage.taskList().getAllRowsNameColumn('Name');
|
||||
await expect(ArrayUtil.arrayContainsArray(list, allTasksName)).toEqual(true);
|
||||
|
||||
await expect(await taskListSinglePage.taskList().getDataTable().numberOfRows()).toBe(23);
|
||||
|
||||
@@ -33,7 +33,7 @@ import { ProcessServiceTabBarPage } from './../pages/process-service-tab-bar.pag
|
||||
import { ProcessFiltersPage } from './../pages/process-filters.page';
|
||||
import { infoDrawerConfiguration } from './../config/task.config';
|
||||
import CONSTANTS = require('../../util/constants');
|
||||
import * as moment from 'moment';
|
||||
import { DateFnsUtils } from '../../../lib/core/src/lib/common/utils/date-fns-utils';
|
||||
|
||||
describe('Info Drawer', () => {
|
||||
|
||||
@@ -161,7 +161,7 @@ describe('Info Drawer', () => {
|
||||
});
|
||||
|
||||
await taskPage.taskDetails().updateDueDate();
|
||||
await expect(await taskPage.taskDetails().getDueDate()).toEqual(moment('Aug 1, 2017').format(taskDetails.dateFormat));
|
||||
await expect(await taskPage.taskDetails().getDueDate()).toEqual(DateFnsUtils.formatDate(new Date('Aug 1, 2017'), taskDetails.dateFormat));
|
||||
|
||||
await taskPage.taskDetails().clickCompleteFormTask();
|
||||
|
||||
@@ -187,7 +187,7 @@ describe('Info Drawer', () => {
|
||||
|
||||
it('[C260329] Task with no form', async () => {
|
||||
const name = StringUtil.generateRandomString(5);
|
||||
await taskPage.createTask(<any> { ...taskDetails, formName: '', name });
|
||||
await taskPage.createTask({ ...taskDetails, formName: '', name });
|
||||
await taskPage.tasksListPage().getDataTable().waitTillContentLoaded();
|
||||
await taskPage.filtersPage().goToFilter(CONSTANTS.TASK_FILTERS.INV_TASKS);
|
||||
await taskPage.tasksListPage().checkContentIsDisplayed(name);
|
||||
@@ -204,7 +204,7 @@ describe('Info Drawer', () => {
|
||||
|
||||
it('[C260320] Assign user to the task', async () => {
|
||||
const name = StringUtil.generateRandomString(5);
|
||||
await taskPage.createTask(<any> { ...taskDetails, formName: app.formName, name });
|
||||
await taskPage.createTask({ ...taskDetails, formName: app.formName, name });
|
||||
await taskPage.tasksListPage().getDataTable().waitTillContentLoaded();
|
||||
await taskPage.filtersPage().goToFilter(CONSTANTS.TASK_FILTERS.MY_TASKS);
|
||||
await taskPage.tasksListPage().checkContentIsDisplayed(name);
|
||||
@@ -337,15 +337,32 @@ describe('Info Drawer', () => {
|
||||
await taskPage.taskDetails().clickCompleteFormTask();
|
||||
});
|
||||
|
||||
async function shouldHaveInfoDrawerDetails({ description, status, priority, category, parentName, dateFormat, formName, fullName, dueDate }) {
|
||||
await expect(await taskPage.taskDetails().getAssignee()).toEqual(fullName);
|
||||
await expect(await taskPage.taskDetails().getDescription()).toEqual(description);
|
||||
await expect(await taskPage.taskDetails().getStatus()).toEqual(status);
|
||||
await expect(await taskPage.taskDetails().getPriority()).toEqual(priority);
|
||||
await expect(await taskPage.taskDetails().getDueDate()).toEqual(dueDate !== 'No date' ? moment(dueDate).format(dateFormat) : 'No date');
|
||||
await expect(await taskPage.taskDetails().getCategory()).toEqual(category);
|
||||
await expect(await taskPage.taskDetails().getParentName()).toEqual(parentName);
|
||||
await expect(await taskPage.taskDetails().getCreated()).toEqual(moment(Date.now()).format(dateFormat));
|
||||
await taskPage.taskDetails().waitFormNameEqual(formName);
|
||||
interface TaskDetailsProps {
|
||||
description: string;
|
||||
status: string;
|
||||
priority: string;
|
||||
category: string;
|
||||
parentName: string;
|
||||
dateFormat: string;
|
||||
formName: string;
|
||||
fullName: string;
|
||||
dueDate: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the info drawer has expected values for the task details
|
||||
*
|
||||
* @param props task details properties to validate
|
||||
*/
|
||||
async function shouldHaveInfoDrawerDetails(props: TaskDetailsProps) {
|
||||
await expect(await taskPage.taskDetails().getAssignee()).toEqual(props.fullName);
|
||||
await expect(await taskPage.taskDetails().getDescription()).toEqual(props.description);
|
||||
await expect(await taskPage.taskDetails().getStatus()).toEqual(props.status);
|
||||
await expect(await taskPage.taskDetails().getPriority()).toEqual(props.priority);
|
||||
await expect(await taskPage.taskDetails().getDueDate()).toEqual(props.dueDate !== 'No date' ? DateFnsUtils.formatDate(new Date(props.dueDate), props.dateFormat) : 'No date');
|
||||
await expect(await taskPage.taskDetails().getCategory()).toEqual(props.category);
|
||||
await expect(await taskPage.taskDetails().getParentName()).toEqual(props.parentName);
|
||||
await expect(await taskPage.taskDetails().getCreated()).toEqual(DateFnsUtils.formatDate(new Date().getTime(), props.dateFormat));
|
||||
await taskPage.taskDetails().waitFormNameEqual(props.formName);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -35,7 +35,7 @@ import Task = require('../../models/APS/Task');
|
||||
import TaskModel = require('../../models/APS/TaskModel');
|
||||
import FormModel = require('../../models/APS/FormModel');
|
||||
import CONSTANTS = require('../../util/constants');
|
||||
import * as moment from 'moment';
|
||||
import { format } from 'date-fns';
|
||||
|
||||
describe('Task Details component', () => {
|
||||
const app = browser.params.resources.Files.SIMPLE_APP_WITH_USER_FORM;
|
||||
@@ -55,7 +55,7 @@ describe('Task Details component', () => {
|
||||
let processUserModel: UserModel;
|
||||
let appModel: AppDefinitionRepresentation;
|
||||
const tasks = ['Modifying task', 'Information box', 'No form', 'Not Created', 'Refreshing form', 'Assignee task', 'Attach File'];
|
||||
const TASK_DATE_FORMAT = 'll';
|
||||
const TASK_DATE_FORMAT = 'PP';
|
||||
let formModel: any;
|
||||
|
||||
const taskFormModel = {
|
||||
@@ -96,7 +96,7 @@ describe('Task Details component', () => {
|
||||
|
||||
const taskModel = new TaskModel(allTasks.data[0]);
|
||||
await taskPage.tasksListPage().checkContentIsDisplayed(taskModel.getName());
|
||||
await expect(await taskPage.taskDetails().getCreated()).toEqual(moment(taskModel.getCreated()).format(TASK_DATE_FORMAT));
|
||||
await expect(await taskPage.taskDetails().getCreated()).toEqual(format(new Date(taskModel.getCreated()), TASK_DATE_FORMAT));
|
||||
await expect(await taskPage.taskDetails().getId()).toEqual(taskModel.getId());
|
||||
await expect(await taskPage.taskDetails().getDescription()).toEqual(taskModel.getDescription());
|
||||
await expect(await taskPage.taskDetails().getAssignee()).toEqual(taskModel.getAssignee().getEntireName());
|
||||
@@ -126,7 +126,7 @@ describe('Task Details component', () => {
|
||||
const taskModel = new TaskModel(allTasks.data[0]);
|
||||
await taskPage.tasksListPage().checkContentIsDisplayed(taskModel.getName());
|
||||
|
||||
await expect(await taskPage.taskDetails().getCreated()).toEqual(moment(taskModel.getCreated()).format(TASK_DATE_FORMAT));
|
||||
await expect(await taskPage.taskDetails().getCreated()).toEqual(format(new Date(taskModel.getCreated()), TASK_DATE_FORMAT));
|
||||
await expect(await taskPage.taskDetails().getId()).toEqual(taskModel.getId());
|
||||
await expect(await taskPage.taskDetails().getDescription()).toEqual(taskModel.getDescription());
|
||||
await expect(await taskPage.taskDetails().getAssignee()).toEqual(taskModel.getAssignee().getEntireName());
|
||||
@@ -160,7 +160,7 @@ describe('Task Details component', () => {
|
||||
const taskModel = new TaskModel(allTasks.data[0]);
|
||||
|
||||
await taskPage.tasksListPage().checkContentIsDisplayed(taskModel.getName());
|
||||
await expect(await taskPage.taskDetails().getCreated()).toEqual(moment(taskModel.getCreated()).format(TASK_DATE_FORMAT));
|
||||
await expect(await taskPage.taskDetails().getCreated()).toEqual(format(new Date(taskModel.getCreated()), TASK_DATE_FORMAT));
|
||||
await expect(await taskPage.taskDetails().getId()).toEqual(taskModel.getId());
|
||||
await expect(await taskPage.taskDetails().getDescription()).toEqual(CONSTANTS.TASK_DETAILS.NO_DESCRIPTION);
|
||||
await expect(await taskPage.taskDetails().getAssignee()).toEqual(taskModel.getAssignee().getEntireName());
|
||||
@@ -191,7 +191,7 @@ describe('Task Details component', () => {
|
||||
const taskModel = new TaskModel(allTasks.data[0]);
|
||||
|
||||
await taskPage.tasksListPage().checkContentIsDisplayed(taskModel.getName());
|
||||
await expect(await taskPage.taskDetails().getCreated()).toEqual(moment(taskModel.getCreated()).format(TASK_DATE_FORMAT));
|
||||
await expect(await taskPage.taskDetails().getCreated()).toEqual(format(new Date(taskModel.getCreated()), TASK_DATE_FORMAT));
|
||||
await expect(await taskPage.taskDetails().getId()).toEqual(taskModel.getId());
|
||||
await expect(await taskPage.taskDetails().getDescription()).toEqual(CONSTANTS.TASK_DETAILS.NO_DESCRIPTION);
|
||||
await expect(await taskPage.taskDetails().getAssignee()).toEqual(taskModel.getAssignee().getEntireName());
|
||||
@@ -233,7 +233,7 @@ describe('Task Details component', () => {
|
||||
|
||||
const taskModel = new TaskModel(allTasks.data[0]);
|
||||
await taskPage.tasksListPage().checkContentIsDisplayed(taskModel.getName());
|
||||
await expect(await taskPage.taskDetails().getCreated()).toEqual(moment(taskModel.getCreated()).format(TASK_DATE_FORMAT));
|
||||
await expect(await taskPage.taskDetails().getCreated()).toEqual(format(new Date(taskModel.getCreated()), TASK_DATE_FORMAT));
|
||||
await expect(await taskPage.taskDetails().getId()).toEqual(taskModel.getId());
|
||||
await expect(await taskPage.taskDetails().getDescription()).toEqual(CONSTANTS.TASK_DETAILS.NO_DESCRIPTION);
|
||||
await expect(await taskPage.taskDetails().getAssignee()).toEqual(taskModel.getAssignee().getEntireName());
|
||||
@@ -270,7 +270,7 @@ describe('Task Details component', () => {
|
||||
|
||||
const taskModel = new TaskModel(allTasks.data[0]);
|
||||
await taskPage.tasksListPage().checkContentIsDisplayed(taskModel.getName());
|
||||
await expect(await taskPage.taskDetails().getCreated()).toEqual(moment(taskModel.getCreated()).format(TASK_DATE_FORMAT));
|
||||
await expect(await taskPage.taskDetails().getCreated()).toEqual(format(new Date(taskModel.getCreated()), TASK_DATE_FORMAT));
|
||||
await expect(await taskPage.taskDetails().getId()).toEqual(taskModel.getId());
|
||||
await expect(await taskPage.taskDetails().getDescription()).toEqual(CONSTANTS.TASK_DETAILS.NO_DESCRIPTION);
|
||||
await expect(await taskPage.taskDetails().getAssignee()).toEqual(taskModel.getAssignee().getEntireName());
|
||||
@@ -301,7 +301,7 @@ describe('Task Details component', () => {
|
||||
|
||||
const taskModel = new TaskModel(getTaskResponse);
|
||||
await taskPage.tasksListPage().checkContentIsDisplayed(taskModel.getName());
|
||||
await expect(await taskPage.taskDetails().getCreated()).toEqual(moment(taskModel.getCreated()).format(TASK_DATE_FORMAT));
|
||||
await expect(await taskPage.taskDetails().getCreated()).toEqual(format(new Date(taskModel.getCreated()), TASK_DATE_FORMAT));
|
||||
await expect(await taskPage.taskDetails().getId()).toEqual(taskModel.getId());
|
||||
await expect(await taskPage.taskDetails().getDescription()).toEqual(CONSTANTS.TASK_DETAILS.NO_DESCRIPTION);
|
||||
await expect(await taskPage.taskDetails().getAssignee()).toEqual(taskModel.getAssignee().getEntireName());
|
||||
|
||||
@@ -4,10 +4,7 @@
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.ts"],
|
||||
"extends": [
|
||||
"plugin:@nrwl/nx/angular",
|
||||
"plugin:@angular-eslint/template/process-inline-templates"
|
||||
],
|
||||
"extends": ["plugin:@nrwl/nx/angular", "plugin:@angular-eslint/template/process-inline-templates"],
|
||||
"rules": {
|
||||
"prefer-arrow/prefer-arrow-functions": "off",
|
||||
"@typescript-eslint/no-var-requires": "off",
|
||||
@@ -41,8 +38,7 @@
|
||||
{
|
||||
"files": ["*.html"],
|
||||
"extends": ["plugin:@nrwl/nx/angular-template"],
|
||||
"rules": {
|
||||
}
|
||||
"rules": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
+16
-15
@@ -1,44 +1,45 @@
|
||||
#!/usr/bin/env node
|
||||
const minimist = require('minimist');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const { resolve, join } = require('node:path');
|
||||
const { readFileSync, existsSync } = require('node:fs');
|
||||
const { argv, exit, env, cwd } = require('node:process');
|
||||
|
||||
function printHelp() {
|
||||
const pkgData = fs.readFileSync(path.resolve(__dirname, '..', 'package.json'));
|
||||
const pkgData = readFileSync(resolve(__dirname, '..', 'package.json')).toString();
|
||||
const { name, version } = JSON.parse(pkgData);
|
||||
console.log(`${name} v${version}`);
|
||||
}
|
||||
|
||||
const args = minimist(process.argv.slice(2), {
|
||||
const args = minimist(argv.slice(2), {
|
||||
boolean: ['verbose']
|
||||
});
|
||||
|
||||
if (args._.length === 0) {
|
||||
printHelp();
|
||||
process.exit(1);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
const scriptName = args._.shift();
|
||||
const scriptPath = process.env.DEVELOP
|
||||
? path.resolve(path.join(__dirname, '../dist/scripts', scriptName))
|
||||
: path.resolve(path.join(__dirname, '../scripts', scriptName));
|
||||
const scriptPath = env.DEVELOP
|
||||
? resolve(join(__dirname, '../dist/scripts', scriptName))
|
||||
: resolve(join(__dirname, '../scripts', scriptName));
|
||||
|
||||
if (!fs.existsSync(`${scriptPath}.js`)) {
|
||||
if (!existsSync(`${scriptPath}.js`)) {
|
||||
console.error(`Error: command ${scriptName} not found.`);
|
||||
process.exit(1);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
const cwd = process.cwd();
|
||||
const workingDir = cwd();
|
||||
|
||||
try {
|
||||
Promise.resolve()
|
||||
.then(() => require(scriptPath).default(args, cwd))
|
||||
.then(exitCode => process.exit(exitCode || 0))
|
||||
.then(() => require(scriptPath).default(args, workingDir))
|
||||
.then(exitCode => exit(exitCode || 0))
|
||||
.catch(err => {
|
||||
console.error(err && err.stack);
|
||||
process.exit(99);
|
||||
exit(99);
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err.stack);
|
||||
process.exit(99);
|
||||
exit(99);
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
"dist": "rm -rf ../../dist/libs/cli && npm run build && cp -R ./bin ../../dist/libs/cli && cp -R ./resources ../../dist/libs/cli && cp -R ./templates ../../dist/libs/cli && cp ./package.json ../../dist/libs/cli"
|
||||
},
|
||||
"dependencies": {
|
||||
"@alfresco/js-api": ">=7.0.0",
|
||||
"@alfresco/js-api": ">=7.1.0-1372",
|
||||
"commander": "^6.2.1",
|
||||
"ejs": "^3.1.9",
|
||||
"license-checker": "^25.0.1",
|
||||
|
||||
@@ -17,46 +17,60 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { argv, exit } from 'node:process';
|
||||
import { exec } from './exec';
|
||||
import { logger } from './logger';
|
||||
import program from 'commander';
|
||||
|
||||
/**
|
||||
* Perform a test
|
||||
*
|
||||
* @param output output path
|
||||
*/
|
||||
function test(output: string) {
|
||||
const response = exec('test !', [`-d ${output} && mkdir ${output}`], {});
|
||||
logger.info(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy AWS S3
|
||||
*
|
||||
* @param artifact artifact name
|
||||
*/
|
||||
function awsCp(artifact: string) {
|
||||
logger.info(`aws s3 cp ${artifact}`);
|
||||
const response = exec(`aws s3 cp ${artifact}`, [`./s3-artifact.tmp ${artifact}`], {});
|
||||
logger.info(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Zip artifact
|
||||
*
|
||||
* @param output output name
|
||||
*/
|
||||
function zipArtifact(output: string) {
|
||||
logger.info(`Perform zip artifact ${output}`);
|
||||
const response = exec('tar', ['-xvf', `./s3-artifact.tmp`, '-C ' + program.output], {});
|
||||
logger.info(response);
|
||||
}
|
||||
|
||||
export default function() {
|
||||
main();
|
||||
}
|
||||
|
||||
function main() {
|
||||
|
||||
/**
|
||||
* Artifact from S3 command
|
||||
*/
|
||||
export default function main() {
|
||||
program
|
||||
.version('0.1.0')
|
||||
.requiredOption('-a, --artifact [type]', ' path to the s3 artifact (tar.bz2) to download and extract')
|
||||
.requiredOption('-o, --output [type]', 'directory to extract the archive to')
|
||||
.parse(process.argv);
|
||||
.parse(argv);
|
||||
|
||||
if (process.argv.includes('-h') || process.argv.includes('--help')) {
|
||||
if (argv.includes('-h') || argv.includes('--help')) {
|
||||
program.outputHelp();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!program.artifact || program.artifact === '' || !program.output || program.output === '') {
|
||||
process.exit(1);
|
||||
exit(1);
|
||||
} else if (program.artifact !== '' || program.output !== '') {
|
||||
zipArtifact(program.artifact);
|
||||
awsCp(program.output);
|
||||
|
||||
@@ -17,42 +17,52 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { argv, exit } from 'node:process';
|
||||
import { exec } from './exec';
|
||||
import { logger } from './logger';
|
||||
import program from 'commander';
|
||||
|
||||
/**
|
||||
* Zip artifact
|
||||
*
|
||||
* @param artifact artifact name
|
||||
*/
|
||||
function zipArtifact(artifact: string) {
|
||||
logger.info(`Perform zip artifact ${artifact}`);
|
||||
|
||||
const response = exec(`tar cvfj ./s3-artifact.tmp -C ${program.artifact} ls ${program.artifact}`, [] , {});
|
||||
const response = exec(`tar cvfj ./s3-artifact.tmp -C ${program.artifact} ls ${program.artifact}`, [], {});
|
||||
logger.info(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy to AWS S3
|
||||
*
|
||||
* @param output output path
|
||||
*/
|
||||
function awsCp(output: string) {
|
||||
logger.info(`aws s3 cp ${output}`);
|
||||
const response = exec('aws s3 cp', [`./s3-artifact.tmp ${output}`], {});
|
||||
logger.info(response);
|
||||
}
|
||||
|
||||
export default function() {
|
||||
main();
|
||||
}
|
||||
|
||||
function main() {
|
||||
|
||||
/**
|
||||
* Artifact to S3 command
|
||||
*/
|
||||
export default function main() {
|
||||
program
|
||||
.version('0.1.0')
|
||||
.option('-a, --artifact [type]', ' path to the artifact to archieve (tar.bz2) and upload (like ./dist)')
|
||||
.option('-o, --output [type]', ' the S3 object to copy it to, like: s3://bucket-name/folder/whatever.tar.bz2')
|
||||
.parse(process.argv);
|
||||
.parse(argv);
|
||||
|
||||
if (process.argv.includes('-h') || process.argv.includes('--help')) {
|
||||
if (argv.includes('-h') || argv.includes('--help')) {
|
||||
program.outputHelp();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!program.artifact || program.artifact === '' || !program.output || program.output === '') {
|
||||
process.exit(1);
|
||||
exit(1);
|
||||
} else if (program.artifact !== '' || program.output !== '') {
|
||||
zipArtifact(program.artifact);
|
||||
awsCp(program.output);
|
||||
|
||||
+33
-20
@@ -21,17 +21,25 @@ import * as shell from 'shelljs';
|
||||
import * as ejs from 'ejs';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
import { argv, exit } from 'node:process';
|
||||
import program from 'commander';
|
||||
|
||||
/**
|
||||
* Audit report command
|
||||
*
|
||||
* @param _args (unused)
|
||||
* @param workingDir working directory
|
||||
* @returns void
|
||||
*/
|
||||
export default function main(_args: string[], workingDir: string) {
|
||||
program
|
||||
.description('Generate an audit report')
|
||||
.usage('audit [options]')
|
||||
.option('-p, --package <path>', 'Path to package file (default: package.json in working directory)')
|
||||
.option('-d, --outDir <dir>', 'Ouput directory (default: working directory)')
|
||||
.parse(process.argv);
|
||||
.parse(argv);
|
||||
|
||||
if (process.argv.includes('-h') || process.argv.includes('--help')) {
|
||||
if (argv.includes('-h') || argv.includes('--help')) {
|
||||
program.outputHelp();
|
||||
return;
|
||||
}
|
||||
@@ -44,13 +52,13 @@ export default function main(_args: string[], workingDir: string) {
|
||||
|
||||
if (!fs.existsSync(packagePath)) {
|
||||
console.error('The package.json file was not found');
|
||||
process.exit(1);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
const templatePath = path.resolve(__dirname, '../templates/auditPage.ejs');
|
||||
if (!fs.existsSync(templatePath)) {
|
||||
console.error(`Cannot find the report template: ${templatePath}`);
|
||||
process.exit(1);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
@@ -61,24 +69,29 @@ export default function main(_args: string[], workingDir: string) {
|
||||
const cmd = 'npm audit --json --prod';
|
||||
const jsonAudit = JSON.parse(shell.exec(cmd, { silent: true }));
|
||||
|
||||
ejs.renderFile(templatePath, {
|
||||
jsonAudit,
|
||||
projVersion: packageJson.version,
|
||||
projName: packageJson.name
|
||||
}, {}, (err: any, mdText: string) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
reject(1);
|
||||
} else {
|
||||
const outputPath = path.resolve(program.outDir || workingDir);
|
||||
const outputFile = path.join(outputPath, `audit-info-${packageJson.version}.md`);
|
||||
ejs.renderFile(
|
||||
templatePath,
|
||||
{
|
||||
jsonAudit,
|
||||
projVersion: packageJson.version,
|
||||
projName: packageJson.name
|
||||
},
|
||||
{},
|
||||
(err: any, mdText: string) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
reject(err);
|
||||
} else {
|
||||
const outputPath = path.resolve(program.outDir || workingDir);
|
||||
const outputFile = path.join(outputPath, `audit-info-${packageJson.version}.md`);
|
||||
|
||||
fs.writeFileSync(outputFile, mdText);
|
||||
fs.writeFileSync(outputFile, mdText);
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(`Report saved as ${outputFile}`);
|
||||
resolve(0);
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(`Report saved as ${outputFile}`);
|
||||
resolve(0);
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
|
||||
import { argv, exit } from 'node:process';
|
||||
import * as shell from 'shelljs';
|
||||
import * as path from 'path';
|
||||
import program from 'commander';
|
||||
@@ -78,14 +79,13 @@ function getRemote(workingDir: string): string {
|
||||
function getCommits(options: DiffOptions): Array<Commit> {
|
||||
let authorFilter = (options.exclude || '')
|
||||
.split(',')
|
||||
.map(str => str.trim().replace(/\\/g, ''))
|
||||
.map((str) => str.trim().replace(/\\/g, ''))
|
||||
.join('|');
|
||||
|
||||
if (!authorFilter) {
|
||||
authorFilter = `bot|Alfresco Build User`;
|
||||
}
|
||||
|
||||
|
||||
const args = [
|
||||
`git`,
|
||||
`log`,
|
||||
@@ -114,14 +114,31 @@ function getCommits(options: DiffOptions): Array<Commit> {
|
||||
log = log.substring(0, log.length - 1);
|
||||
}
|
||||
|
||||
return log.split('\\n').map(str => JSON.parse(str) as Commit).filter(commit => commitAuthorAllowed(commit, authorFilter));
|
||||
return log
|
||||
.split('\\n')
|
||||
.map((str: string) => JSON.parse(str) as Commit)
|
||||
.filter((commit: Commit) => commitAuthorAllowed(commit, authorFilter));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if commit author is allowed
|
||||
*
|
||||
* @param commit git commit
|
||||
* @param authorFilter filter
|
||||
* @returns `true` if author is allowed, otherwise `false`
|
||||
*/
|
||||
function commitAuthorAllowed(commit: Commit, authorFilter: string): boolean {
|
||||
const filterRegex = RegExp(authorFilter);
|
||||
return !(filterRegex.test(commit.author) || filterRegex.test(commit.author_email));
|
||||
}
|
||||
|
||||
/**
|
||||
* Changelog command
|
||||
*
|
||||
* @param _args (unused)
|
||||
* @param workingDir working directory
|
||||
* @returns void
|
||||
*/
|
||||
export default function main(_args: string[], workingDir: string) {
|
||||
program
|
||||
.description('Generate changelog report for two branches of git repository')
|
||||
@@ -134,9 +151,9 @@ export default function main(_args: string[], workingDir: string) {
|
||||
.option('--skip <number>', 'Skip number commits before starting to show the commit output')
|
||||
.option('-f, --format <format>', 'Output format (md, html)', 'md')
|
||||
.option('-e --exclude <string>', 'Exclude authors from the output, comma-delimited list')
|
||||
.parse(process.argv);
|
||||
.parse(argv);
|
||||
|
||||
if (process.argv.includes('-h') || process.argv.includes('--help')) {
|
||||
if (argv.includes('-h') || argv.includes('--help')) {
|
||||
program.outputHelp();
|
||||
return;
|
||||
}
|
||||
@@ -162,40 +179,45 @@ export default function main(_args: string[], workingDir: string) {
|
||||
const packagePath = path.resolve(dir, 'package.json');
|
||||
if (!fs.existsSync(packagePath)) {
|
||||
console.error('The package.json file was not found');
|
||||
process.exit(1);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
const templatePath = path.resolve(__dirname, `../templates/changelog-${format}.ejs`);
|
||||
if (!fs.existsSync(templatePath)) {
|
||||
console.error(`Cannot find the report template: ${templatePath}`);
|
||||
process.exit(1);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const packageJson = JSON.parse(fs.readFileSync(packagePath).toString());
|
||||
|
||||
ejs.renderFile(templatePath, {
|
||||
remote,
|
||||
repo_url,
|
||||
commits,
|
||||
projVersion: packageJson.version,
|
||||
projName: packageJson.name
|
||||
}, {}, (err: any, text: string) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
reject(1);
|
||||
} else {
|
||||
if (output) {
|
||||
const outputDir = path.resolve(output);
|
||||
const outputFile = path.join(outputDir, `changelog-${packageJson.version}.${format}`);
|
||||
console.log('Writing changelog to', outputFile);
|
||||
|
||||
fs.writeFileSync(outputFile, text);
|
||||
ejs.renderFile(
|
||||
templatePath,
|
||||
{
|
||||
remote,
|
||||
repo_url,
|
||||
commits,
|
||||
projVersion: packageJson.version,
|
||||
projName: packageJson.name
|
||||
},
|
||||
{},
|
||||
(err: any, text: string) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
reject(err);
|
||||
} else {
|
||||
console.log(text);
|
||||
if (output) {
|
||||
const outputDir = path.resolve(output);
|
||||
const outputFile = path.join(outputDir, `changelog-${packageJson.version}.${format}`);
|
||||
console.log('Writing changelog to', outputFile);
|
||||
|
||||
fs.writeFileSync(outputFile, text);
|
||||
} else {
|
||||
console.log(text);
|
||||
}
|
||||
resolve(0);
|
||||
}
|
||||
resolve(0);
|
||||
}
|
||||
});
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { AlfrescoApi, NodesApi, UploadApi } from '@alfresco/js-api';
|
||||
import { AlfrescoApi /*, NodesApi, UploadApi*/ } from '@alfresco/js-api';
|
||||
import { argv, exit } from 'node:process';
|
||||
import { Buffer } from 'node:buffer';
|
||||
// import { Buffer } from 'node:buffer';
|
||||
const program = require('commander');
|
||||
import { logger } from './logger';
|
||||
const MAX_RETRY = 3;
|
||||
@@ -25,7 +25,10 @@ const TIMEOUT = 20000;
|
||||
let counter = 0;
|
||||
let alfrescoJsApi: AlfrescoApi;
|
||||
|
||||
export default async function main(_args: string[]) {
|
||||
/**
|
||||
* Check CS environment command
|
||||
*/
|
||||
export default async function main() {
|
||||
program
|
||||
.version('0.1.0')
|
||||
.description('Check Content service is up ')
|
||||
@@ -42,6 +45,9 @@ export default async function main(_args: string[]) {
|
||||
// await checkDiskSpaceFullEnv();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check environment
|
||||
*/
|
||||
async function checkEnv() {
|
||||
try {
|
||||
alfrescoJsApi = new AlfrescoApi({
|
||||
@@ -71,7 +77,8 @@ async function checkEnv() {
|
||||
}
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
// TODO: https://alfresco.atlassian.net/browse/ACS-5873
|
||||
/*
|
||||
async function checkDiskSpaceFullEnv() {
|
||||
logger.info(`Start Check disk full space`);
|
||||
|
||||
@@ -108,7 +115,13 @@ async function checkDiskSpaceFullEnv() {
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Perform a delay
|
||||
*
|
||||
* @param delay timeout in milliseconds
|
||||
*/
|
||||
function sleep(delay: number) {
|
||||
const start = new Date().getTime();
|
||||
while (new Date().getTime() < start + delay) {}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { argv } from 'node:process';
|
||||
import { PluginTarget } from './plugins/plugin-model';
|
||||
import { CheckEnv } from './plugins/check-env';
|
||||
import program = require('commander');
|
||||
@@ -22,9 +23,12 @@ import { ProcessServiceCheckPlugin } from './plugins/process-service-check-plugi
|
||||
import { ProcessAutomationCheckPlugin } from './plugins/process-automation-check-plugin';
|
||||
import { GovernanceCheckPlugin } from './plugins/governance-check-plugin';
|
||||
|
||||
let pluginEnv;
|
||||
let pluginEnv: CheckEnv;
|
||||
|
||||
export default async function main(_args: string[]) {
|
||||
/**
|
||||
* Check environment plugin
|
||||
*/
|
||||
export default async function main() {
|
||||
program
|
||||
.version('0.1.0')
|
||||
.option('--host [type]', 'Remote environment host')
|
||||
@@ -34,7 +38,7 @@ export default async function main(_args: string[]) {
|
||||
.option('-p, --password [type]', 'password ')
|
||||
.option('-u, --username [type]', 'username ')
|
||||
.option('--ui, --uiName [type]', 'uiName', 'Deployed app UI type on activiti-cloud')
|
||||
.parse(process.argv);
|
||||
.parse(argv);
|
||||
|
||||
pluginEnv = new CheckEnv(program.host, program.username, program.password, program.clientId);
|
||||
await pluginEnv.checkEnv();
|
||||
@@ -52,6 +56,9 @@ export default async function main(_args: string[]) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check PS plugin
|
||||
*/
|
||||
async function checkProcessServicesPlugin() {
|
||||
const processServiceCheckPlugin = new ProcessServiceCheckPlugin(
|
||||
{
|
||||
@@ -63,6 +70,9 @@ async function checkProcessServicesPlugin() {
|
||||
await processServiceCheckPlugin.checkProcessServicesPlugin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check APA plugin
|
||||
*/
|
||||
async function checkProcessAutomationPlugin() {
|
||||
const processAutomationCheckPlugin = new ProcessAutomationCheckPlugin(
|
||||
{
|
||||
@@ -76,6 +86,9 @@ async function checkProcessAutomationPlugin() {
|
||||
await processAutomationCheckPlugin.checkProcessAutomationPlugin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check AGS plugin
|
||||
*/
|
||||
async function checkGovernancePlugin() {
|
||||
const governancePluginCheck = new GovernanceCheckPlugin(
|
||||
{
|
||||
|
||||
@@ -23,7 +23,10 @@ const MAX_RETRY = 10;
|
||||
const TIMEOUT = 60000;
|
||||
let counter = 0;
|
||||
|
||||
export default async function main(_args: string[]) {
|
||||
/**
|
||||
* Check PS environment command
|
||||
*/
|
||||
export default async function main() {
|
||||
program
|
||||
.version('0.1.0')
|
||||
.description('Check Process service is up ')
|
||||
@@ -36,6 +39,9 @@ export default async function main(_args: string[]) {
|
||||
await checkEnv();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check environment
|
||||
*/
|
||||
async function checkEnv() {
|
||||
try {
|
||||
const alfrescoJsApi = new AlfrescoApi({
|
||||
@@ -63,6 +69,11 @@ async function checkEnv() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a delay
|
||||
*
|
||||
* @param delay timeout in milliseconds
|
||||
*/
|
||||
function sleep(delay: number) {
|
||||
const start = new Date().getTime();
|
||||
while (new Date().getTime() < start + delay) {}
|
||||
|
||||
@@ -19,6 +19,11 @@
|
||||
|
||||
import * as docker from './docker';
|
||||
|
||||
/**
|
||||
* Docker publish command
|
||||
*
|
||||
* @param args command arguments
|
||||
*/
|
||||
export default function(args: any) {
|
||||
docker.default(args);
|
||||
}
|
||||
|
||||
+68
-27
@@ -17,6 +17,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { argv, exit } from 'node:process';
|
||||
import { exec } from './exec';
|
||||
import program from 'commander';
|
||||
import { logger } from './logger';
|
||||
@@ -42,15 +43,27 @@ export interface PublishArgs {
|
||||
dockerTags?: string;
|
||||
pathProject: string;
|
||||
fileName: string;
|
||||
sourceTag?: string;
|
||||
}
|
||||
|
||||
function loginPerform(args: PublishArgs) {
|
||||
/**
|
||||
* Perform a login
|
||||
*
|
||||
* @param args arguments
|
||||
*/
|
||||
function login(args: PublishArgs) {
|
||||
logger.info(`Perform docker login...${args.loginRepo}`);
|
||||
const loginDockerRes = exec('docker', ['login', `-u=${args.loginUsername}`, `-p=${args.loginPassword}`, `${args.loginRepo}`]);
|
||||
logger.info(loginDockerRes);
|
||||
}
|
||||
|
||||
function buildImagePerform(args: PublishArgs, tag: string) {
|
||||
/**
|
||||
* Build Docker image
|
||||
*
|
||||
* @param args command arguments
|
||||
* @param tag tag
|
||||
*/
|
||||
function buildImage(args: PublishArgs, tag: string) {
|
||||
logger.info(`Perform docker build...${args.dockerRepo}:${tag}`);
|
||||
|
||||
const buildArgs = [];
|
||||
@@ -69,19 +82,38 @@ function buildImagePerform(args: PublishArgs, tag: string) {
|
||||
logger.info(response);
|
||||
}
|
||||
|
||||
function tagImagePerform(args: PublishArgs, tagImage: string, newTag: string) {
|
||||
logger.info(`Perform docker tag... ${args.dockerRepo}:${tagImage} on ${args.dockerRepo}:${newTag}`);
|
||||
const response = exec('docker', ['tag', `${args.dockerRepo}:${tagImage}`, `${args.dockerRepo}:${newTag}`], {});
|
||||
/**
|
||||
* Tag Docker image
|
||||
*
|
||||
* @param args command arguments
|
||||
* @param imageTag image tag
|
||||
* @param newTag new image tag
|
||||
*/
|
||||
function tagImage(args: PublishArgs, imageTag: string, newTag: string) {
|
||||
logger.info(`Perform docker tag... ${args.dockerRepo}:${imageTag} on ${args.dockerRepo}:${newTag}`);
|
||||
const response = exec('docker', ['tag', `${args.dockerRepo}:${imageTag}`, `${args.dockerRepo}:${newTag}`], {});
|
||||
logger.info(response);
|
||||
}
|
||||
|
||||
function pullImagePerform(dockerRepo: string, sourceTag: string) {
|
||||
/**
|
||||
* Pull Docker image
|
||||
*
|
||||
* @param dockerRepo repository
|
||||
* @param sourceTag tag
|
||||
*/
|
||||
function pullImage(dockerRepo: string, sourceTag: string) {
|
||||
logger.info(`Perform docker pull... ${dockerRepo}:${sourceTag}`);
|
||||
const response = exec('docker', ['pull', `${dockerRepo}:${sourceTag}`], {});
|
||||
logger.info(response);
|
||||
}
|
||||
|
||||
function pushImagePerform(args: PublishArgs, tag: string) {
|
||||
/**
|
||||
* Push Docker image
|
||||
*
|
||||
* @param args command arguments
|
||||
* @param tag tag
|
||||
*/
|
||||
function pushImage(args: PublishArgs, tag: string) {
|
||||
if (args.dryrun) {
|
||||
logger.info(`Dry-run Perform docker push... ${args.dockerRepo}:${tag}`);
|
||||
} else {
|
||||
@@ -91,21 +123,30 @@ function pushImagePerform(args: PublishArgs, tag: string) {
|
||||
}
|
||||
}
|
||||
|
||||
function cleanImagePerform(args: PublishArgs, tag: string) {
|
||||
/**
|
||||
* Clean Docker image
|
||||
*
|
||||
* @param args command arguments
|
||||
* @param tag tag
|
||||
*/
|
||||
function cleanImage(args: PublishArgs, tag: string) {
|
||||
logger.info(`Perform docker clean on tag:${tag}...`);
|
||||
const response = exec('docker', ['rmi', `-f`, `${args.dockerRepo}:${tag}`], {});
|
||||
logger.info(response);
|
||||
}
|
||||
|
||||
export default function(args: PublishArgs) {
|
||||
main(args);
|
||||
}
|
||||
|
||||
function main(args) {
|
||||
/**
|
||||
* Publish to Docker command
|
||||
*
|
||||
* @param args command arguments
|
||||
*/
|
||||
export default function main(args: PublishArgs) {
|
||||
program
|
||||
.version('0.1.0')
|
||||
.description('Move in the folder where you have your Dockerfile and run the command:\n\n' +
|
||||
'adf-cli docker-publish --dockerRepo "${docker_repository}" --dockerTags "${TAGS}"')
|
||||
.description(
|
||||
'Move in the folder where you have your Dockerfile and run the command:\n\n' +
|
||||
'adf-cli docker-publish --dockerRepo "${docker_repository}" --dockerTags "${TAGS}"'
|
||||
)
|
||||
.option('--loginRepo [type]', 'URL registry')
|
||||
.option('--loginPassword [type]', ' password')
|
||||
.option('--loginUsername [type]', ' username')
|
||||
@@ -119,26 +160,26 @@ function main(args) {
|
||||
.option('--target [type]', 'target: publish or link', TARGETS.publish)
|
||||
.requiredOption('--dockerRepo [type]', 'docker repo')
|
||||
.requiredOption('--dockerTags [type]', ' tags')
|
||||
.parse(process.argv);
|
||||
.parse(argv);
|
||||
|
||||
if (process.argv.includes('-h') || process.argv.includes('--help')) {
|
||||
if (argv.includes('-h') || argv.includes('--help')) {
|
||||
program.outputHelp();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Object.values(TARGETS).includes(program.opts().target)) {
|
||||
logger.error(`error: invalid --target value. It can be ${Object.values(TARGETS)}`);
|
||||
process.exit(1);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (program.opts().target === TARGETS.publish && args.buildArgs === undefined) {
|
||||
logger.error(`error: required option --buildArgs [type] in case the target is ${TARGETS.publish}`);
|
||||
process.exit(1);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (program.opts().target === TARGETS.link && args.sourceTag === undefined) {
|
||||
logger.error(`error: required option --sourceTag [type] in case the target is ${TARGETS.link}`);
|
||||
process.exit(1);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (args.pathProject === undefined) {
|
||||
@@ -150,10 +191,10 @@ function main(args) {
|
||||
}
|
||||
|
||||
if (args.loginCheck === true) {
|
||||
loginPerform(args);
|
||||
login(args);
|
||||
}
|
||||
|
||||
let mainTag;
|
||||
let mainTag: string;
|
||||
if (args.dockerTags !== '') {
|
||||
args.dockerTags.split(',').forEach((tag, index) => {
|
||||
if (tag) {
|
||||
@@ -162,17 +203,17 @@ function main(args) {
|
||||
if (index === 0) {
|
||||
logger.info(`Build only once`);
|
||||
mainTag = tag;
|
||||
buildImagePerform(args, mainTag);
|
||||
buildImage(args, mainTag);
|
||||
}
|
||||
} else {
|
||||
mainTag = args.sourceTag;
|
||||
pullImagePerform(args.dockerRepo, mainTag);
|
||||
pullImage(args.dockerRepo, mainTag);
|
||||
}
|
||||
tagImagePerform(args, mainTag, tag);
|
||||
pushImagePerform(args, tag);
|
||||
tagImage(args, mainTag, tag);
|
||||
pushImage(args, tag);
|
||||
}
|
||||
});
|
||||
cleanImagePerform(args, mainTag);
|
||||
cleanImage(args, mainTag);
|
||||
} else {
|
||||
logger.error(`dockerTags cannot be empty ...`);
|
||||
}
|
||||
|
||||
+13
-1
@@ -20,7 +20,19 @@
|
||||
import { spawnSync } from 'child_process';
|
||||
import { logger } from './logger';
|
||||
|
||||
export function exec(command: string, args?: string[], opts?: { cwd?: string }) {
|
||||
export interface ExecOptions {
|
||||
cwd?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exec function
|
||||
*
|
||||
* @param command command to execute
|
||||
* @param args command arguments
|
||||
* @param opts optional settings
|
||||
* @returns void function
|
||||
*/
|
||||
export function exec(command: string, args?: string[], opts?: ExecOptions) {
|
||||
if (process.platform.startsWith('win')) {
|
||||
args.unshift('/c', command);
|
||||
command = 'cmd.exe';
|
||||
|
||||
+154
-23
@@ -29,8 +29,6 @@ let alfrescoJsApiModeler: AlfrescoApi;
|
||||
let alfrescoJsApiDevops: AlfrescoApi;
|
||||
let args: ConfigArgs;
|
||||
let isValid = true;
|
||||
const absentApps: any[] = [];
|
||||
const failingApps: any[] = [];
|
||||
export interface ConfigArgs {
|
||||
modelerUsername: string;
|
||||
modelerPassword: string;
|
||||
@@ -48,6 +46,11 @@ export interface ConfigArgs {
|
||||
|
||||
export const AAE_MICROSERVICES = ['deployment-service', 'modeling-service', 'dmn-service'];
|
||||
|
||||
/**
|
||||
* Perform a health check
|
||||
*
|
||||
* @param nameService service name
|
||||
*/
|
||||
async function healthCheck(nameService: string) {
|
||||
const url = `${args.host}/${nameService}/actuator/health`;
|
||||
|
||||
@@ -85,11 +88,15 @@ async function healthCheck(nameService: string) {
|
||||
}
|
||||
}
|
||||
|
||||
async function getApplicationByStatus(status: string) {
|
||||
/**
|
||||
* Get deployed application
|
||||
*
|
||||
*/
|
||||
async function getApplications(): Promise<{ list: { entries: any[] } }> {
|
||||
const url = `${args.host}/deployment-service/v1/applications`;
|
||||
|
||||
const pathParams = {};
|
||||
const queryParams = { status };
|
||||
const queryParams = {};
|
||||
const headerParams = {};
|
||||
const formParams = {};
|
||||
const bodyParam = {};
|
||||
@@ -120,6 +127,11 @@ async function getApplicationByStatus(status: string) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get descriptors
|
||||
*
|
||||
* @returns deployment service descriptors
|
||||
*/
|
||||
function getDescriptors() {
|
||||
const url = `${args.host}/deployment-service/v1/descriptors`;
|
||||
|
||||
@@ -149,6 +161,11 @@ function getDescriptors() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get projects
|
||||
*
|
||||
* @returns deployment service projects
|
||||
*/
|
||||
function getProjects() {
|
||||
const url = `${args.host}/modeling-service/v1/projects`;
|
||||
|
||||
@@ -178,6 +195,12 @@ function getProjects() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get project release
|
||||
*
|
||||
* @param projectId project id
|
||||
* @returns project release
|
||||
*/
|
||||
function getProjectRelease(projectId: string) {
|
||||
const url = `${args.host}/modeling-service/v1/projects/${projectId}/releases`;
|
||||
|
||||
@@ -207,6 +230,11 @@ function getProjectRelease(projectId: string) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Release project
|
||||
*
|
||||
* @param projectId project id
|
||||
*/
|
||||
async function releaseProject(projectId: string) {
|
||||
const url = `${args.host}/modeling-service/v1/projects/${projectId}/releases`;
|
||||
|
||||
@@ -237,6 +265,12 @@ async function releaseProject(projectId: string) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete project
|
||||
*
|
||||
* @param projectId project id
|
||||
* @returns response payload
|
||||
*/
|
||||
function deleteProject(projectId: string) {
|
||||
const url = `${args.host}/modeling-service/v1/projects/${projectId}`;
|
||||
|
||||
@@ -266,6 +300,11 @@ function deleteProject(projectId: string) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Import and release project
|
||||
*
|
||||
* @param absoluteFilePath path to project file
|
||||
*/
|
||||
async function importAndReleaseProject(absoluteFilePath: string) {
|
||||
const fileContent = fs.createReadStream(absoluteFilePath);
|
||||
|
||||
@@ -302,6 +341,12 @@ async function importAndReleaseProject(absoluteFilePath: string) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes descriptor
|
||||
*
|
||||
* @param name descriptor name
|
||||
* @returns response payload
|
||||
*/
|
||||
function deleteDescriptor(name: string) {
|
||||
const url = `${args.host}/deployment-service/v1/descriptors/${name}`;
|
||||
|
||||
@@ -331,6 +376,12 @@ function deleteDescriptor(name: string) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deploys a model
|
||||
*
|
||||
* @param model model object
|
||||
* @returns response payload
|
||||
*/
|
||||
function deploy(model: any) {
|
||||
const url = `${args.host}/deployment-service/v1/applications`;
|
||||
|
||||
@@ -360,11 +411,23 @@ function deploy(model: any) {
|
||||
}
|
||||
}
|
||||
|
||||
function initializeDefaultToken(options) {
|
||||
/**
|
||||
* Initialise default endpoint token
|
||||
*
|
||||
* @param options token options
|
||||
* @returns options
|
||||
*/
|
||||
function initializeDefaultToken(options: any): any {
|
||||
options.tokenEndpoint = options.tokenEndpoint.replace('${clientId}', options.clientId);
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a new Alfresco Api instance
|
||||
*
|
||||
* @param configArgs command params
|
||||
* @returns a new instance of Alfresco Api client
|
||||
*/
|
||||
function getAlfrescoJsApiInstance(configArgs: ConfigArgs): AlfrescoApi {
|
||||
let ssoHost = configArgs.oauth;
|
||||
ssoHost = ssoHost ?? configArgs.host;
|
||||
@@ -388,10 +451,16 @@ function getAlfrescoJsApiInstance(configArgs: ConfigArgs): AlfrescoApi {
|
||||
return new AlfrescoApi(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deploy missing applications
|
||||
*
|
||||
* @param tag tag
|
||||
* @param envs environments
|
||||
*/
|
||||
async function deployMissingApps(tag?: string, envs?: string[]) {
|
||||
const deployedApps = await getApplicationByStatus('');
|
||||
findMissingApps(deployedApps.list.entries);
|
||||
findFailingApps(deployedApps.list.entries);
|
||||
const deployedApps = await getApplications();
|
||||
const failingApps = findFailingApps(deployedApps.list.entries);
|
||||
const missingApps = findMissingApps(deployedApps.list.entries);
|
||||
|
||||
if (failingApps.length > 0) {
|
||||
failingApps.forEach((app) => {
|
||||
@@ -401,9 +470,9 @@ async function deployMissingApps(tag?: string, envs?: string[]) {
|
||||
logger.error(`${red}${bright}ERROR: App ${app.entry.name} down or inaccessible ${reset}${red} with status ${app.entry.status}${reset}`);
|
||||
});
|
||||
exit(1);
|
||||
} else if (absentApps.length > 0) {
|
||||
logger.warn(`Missing apps: ${JSON.stringify(absentApps)}`);
|
||||
await checkIfAppIsReleased(absentApps, tag, envs);
|
||||
} else if (missingApps.length > 0) {
|
||||
logger.warn(`Missing apps: ${JSON.stringify(missingApps)}`);
|
||||
await checkIfAppIsReleased(missingApps, tag, envs);
|
||||
} else {
|
||||
const reset = '\x1b[0m';
|
||||
const green = '\x1b[32m';
|
||||
@@ -411,6 +480,13 @@ async function deployMissingApps(tag?: string, envs?: string[]) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if application is released
|
||||
*
|
||||
* @param missingApps applications
|
||||
* @param tag tag
|
||||
* @param envs environments
|
||||
*/
|
||||
async function checkIfAppIsReleased(missingApps: any[], tag?: string, envs?: string[]) {
|
||||
const projectList = await getProjects();
|
||||
let TIME = 5000;
|
||||
@@ -478,7 +554,14 @@ async function checkIfAppIsReleased(missingApps: any[], tag?: string, envs?: str
|
||||
}
|
||||
}
|
||||
|
||||
async function deployWithPayload(currentAbsentApp: any, projectRelease: any, envId?: string) {
|
||||
/**
|
||||
* Deploy with a payload
|
||||
*
|
||||
* @param currentAbsentApp current application
|
||||
* @param projectRelease project release
|
||||
* @param envId environment id
|
||||
*/
|
||||
async function deployWithPayload(currentAbsentApp: any, projectRelease: any, envId?: string): Promise<void> {
|
||||
const deployPayload = {
|
||||
name: currentAbsentApp.name,
|
||||
releaseId: projectRelease.entry.id,
|
||||
@@ -493,11 +576,16 @@ async function deployWithPayload(currentAbsentApp: any, projectRelease: any, env
|
||||
logger.info(`Deployed ${currentAbsentApp.name} ${envId ? 'on env: ' + envId : ''}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if descriptor exists
|
||||
*
|
||||
* @param name descriptor name
|
||||
*/
|
||||
async function checkDescriptorExist(name: string): Promise<boolean> {
|
||||
logger.info(`Check descriptor ${name} exist in the list `);
|
||||
const descriptorList = await getDescriptors();
|
||||
|
||||
if (descriptorList && descriptorList.list && descriptorList.entries) {
|
||||
if (descriptorList?.list && descriptorList.entries) {
|
||||
for (const descriptor of descriptorList.list.entries) {
|
||||
if (descriptor.entry.name === name) {
|
||||
if (descriptor.entry.deployed === false) {
|
||||
@@ -509,38 +597,73 @@ async function checkDescriptorExist(name: string): Promise<boolean> {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Import and release project
|
||||
*
|
||||
* @param app application
|
||||
* @param tag tag
|
||||
*/
|
||||
async function importProjectAndRelease(app: any, tag?: string) {
|
||||
const appLocationReplaced = app.file_location(tag);
|
||||
|
||||
logger.warn('App fileLocation ' + appLocationReplaced);
|
||||
await getFileFromRemote(appLocationReplaced, app.name);
|
||||
|
||||
logger.warn('Project imported ' + app.name);
|
||||
const projectRelease = await importAndReleaseProject(`${app.name}.zip`);
|
||||
|
||||
await deleteLocalFile(`${app.name}`);
|
||||
return projectRelease;
|
||||
}
|
||||
|
||||
function findMissingApps(deployedApps: any[]) {
|
||||
/**
|
||||
* Find missing applications
|
||||
*
|
||||
* @param deployedApps applications
|
||||
* @returns list of missing apps
|
||||
*/
|
||||
function findMissingApps(deployedApps: any[]): any[] {
|
||||
const result = [];
|
||||
|
||||
Object.keys(ACTIVITI_CLOUD_APPS).forEach((key) => {
|
||||
const isPresent = deployedApps.find((currentApp: any) => ACTIVITI_CLOUD_APPS[key].name === currentApp.entry.name);
|
||||
|
||||
if (!isPresent) {
|
||||
absentApps.push(ACTIVITI_CLOUD_APPS[key]);
|
||||
result.push(ACTIVITI_CLOUD_APPS[key]);
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function findFailingApps(deployedApps: any[]) {
|
||||
/**
|
||||
* Find failing applications
|
||||
*
|
||||
* @param deployedApps applications
|
||||
* @returns list of failing apps
|
||||
*/
|
||||
function findFailingApps(deployedApps: any[]): any[] {
|
||||
const result = [];
|
||||
|
||||
Object.keys(ACTIVITI_CLOUD_APPS).forEach((key) => {
|
||||
const failingApp = deployedApps.filter(
|
||||
(currentApp: any) => ACTIVITI_CLOUD_APPS[key].name === currentApp.entry.name && 'Running' !== currentApp.entry.status
|
||||
);
|
||||
|
||||
if (failingApp?.length > 0) {
|
||||
failingApps.push(...failingApp);
|
||||
result.push(...failingApp);
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file from the remote
|
||||
*
|
||||
* @param url url to file
|
||||
* @param name name
|
||||
*/
|
||||
async function getFileFromRemote(url: string, name: string) {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
request(url)
|
||||
@@ -556,11 +679,21 @@ async function getFileFromRemote(url: string, name: string) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes local file
|
||||
*
|
||||
* @param name file name
|
||||
*/
|
||||
async function deleteLocalFile(name: string) {
|
||||
logger.info(`Deleting local file ${name}.zip`);
|
||||
fs.unlinkSync(`${name}.zip`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a timeout
|
||||
*
|
||||
* @param time delay in milliseconds
|
||||
*/
|
||||
async function sleep(time: number) {
|
||||
logger.info(`Waiting for ${time} sec...`);
|
||||
await new Promise((done) => setTimeout(done, time));
|
||||
@@ -568,12 +701,10 @@ async function sleep(time: number) {
|
||||
return;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line space-before-function-paren
|
||||
export default async function () {
|
||||
await main();
|
||||
}
|
||||
|
||||
async function main() {
|
||||
/**
|
||||
* Init AAE environment command
|
||||
*/
|
||||
export default async function main() {
|
||||
program
|
||||
.version('0.1.0')
|
||||
.description(
|
||||
|
||||
@@ -28,12 +28,10 @@ const ACS_DEFAULT = require('./resources').ACS_DEFAULT;
|
||||
|
||||
let alfrescoJsApi: AlfrescoApi;
|
||||
|
||||
// eslint-disable-next-line space-before-function-paren
|
||||
export default async function () {
|
||||
await main();
|
||||
}
|
||||
|
||||
async function main() {
|
||||
/**
|
||||
* Init ACS environment command
|
||||
*/
|
||||
export default async function main() {
|
||||
program
|
||||
.version('0.1.0')
|
||||
.option('--host [type]', 'Remote environment host')
|
||||
@@ -48,6 +46,9 @@ async function main() {
|
||||
await initializeDefaultFiles();
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup default files
|
||||
*/
|
||||
async function initializeDefaultFiles() {
|
||||
const e2eFolder = ACS_DEFAULT.e2eFolder;
|
||||
const parentFolder = await createFolder(e2eFolder.name, '-my-');
|
||||
@@ -56,28 +57,39 @@ async function initializeDefaultFiles() {
|
||||
for (let j = 0; j < ACS_DEFAULT.files.length; j++) {
|
||||
const fileInfo = ACS_DEFAULT.files[j];
|
||||
switch (fileInfo.action) {
|
||||
case 'UPLOAD':
|
||||
case 'UPLOAD': {
|
||||
await uploadFile(fileInfo.name, parentFolderId);
|
||||
break;
|
||||
case 'LOCK':
|
||||
}
|
||||
case 'LOCK': {
|
||||
const fileToLock = await uploadFile(fileInfo.name, parentFolderId);
|
||||
await lockFile(fileToLock.entry.id);
|
||||
break;
|
||||
case 'SHARE':
|
||||
}
|
||||
case 'SHARE': {
|
||||
const fileToShare = await uploadFile(fileInfo.name, parentFolderId);
|
||||
await shareFile(fileToShare.entry.id);
|
||||
break;
|
||||
case 'FAVORITE':
|
||||
}
|
||||
case 'FAVORITE': {
|
||||
const fileToFav = await uploadFile(fileInfo.name, parentFolderId);
|
||||
await favoriteFile(fileToFav.entry.id);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
default: {
|
||||
logger.error('No action found for file ', fileInfo.name, parentFolderId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create folder
|
||||
*
|
||||
* @param folderName folder name
|
||||
* @param parentId parent folder id
|
||||
*/
|
||||
async function createFolder(folderName: string, parentId: string) {
|
||||
let createdFolder: NodeEntry;
|
||||
const body = {
|
||||
@@ -97,6 +109,12 @@ async function createFolder(folderName: string, parentId: string) {
|
||||
return createdFolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload file
|
||||
*
|
||||
* @param fileName file name
|
||||
* @param fileDestination destination path
|
||||
*/
|
||||
async function uploadFile(fileName: string, fileDestination: string): Promise<NodeEntry> {
|
||||
const filePath = `../resources/content/${fileName}`;
|
||||
const file = fs.createReadStream(path.join(__dirname, filePath));
|
||||
@@ -115,6 +133,11 @@ async function uploadFile(fileName: string, fileDestination: string): Promise<No
|
||||
return uploadedFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lock file node
|
||||
*
|
||||
* @param nodeId node id
|
||||
*/
|
||||
async function lockFile(nodeId: string): Promise<NodeEntry> {
|
||||
const data = {
|
||||
type: 'ALLOW_OWNER_CHANGES'
|
||||
@@ -128,6 +151,11 @@ async function lockFile(nodeId: string): Promise<NodeEntry> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Share file node
|
||||
*
|
||||
* @param nodeId node id
|
||||
*/
|
||||
async function shareFile(nodeId: string) {
|
||||
const data = {
|
||||
nodeId
|
||||
@@ -140,6 +168,11 @@ async function shareFile(nodeId: string) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Favorite file node
|
||||
*
|
||||
* @param nodeId node id
|
||||
*/
|
||||
async function favoriteFile(nodeId: string) {
|
||||
const data = {
|
||||
target: {
|
||||
@@ -156,6 +189,9 @@ async function favoriteFile(nodeId: string) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check environment state
|
||||
*/
|
||||
async function checkEnv() {
|
||||
try {
|
||||
alfrescoJsApi = new AlfrescoApi({
|
||||
@@ -190,8 +226,12 @@ async function checkEnv() {
|
||||
}
|
||||
}
|
||||
|
||||
/* eslint-enable */
|
||||
|
||||
/**
|
||||
* Perform a delay
|
||||
*
|
||||
* @param delay timeout in milliseconds
|
||||
*/
|
||||
function sleep(delay: number) {
|
||||
const start = new Date().getTime();
|
||||
while (new Date().getTime() < start + delay) {}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { AdminTenantsApi, AdminUsersApi, AlfrescoApi, TenantRepresentation, AppDefinitionsApi, RuntimeAppDefinitionsApi, UserRepresentation } from '@alfresco/js-api';
|
||||
import { AdminTenantsApi, AdminUsersApi, AlfrescoApi, TenantRepresentation, AppDefinitionsApi, RuntimeAppDefinitionsApi, UserRepresentation, AppDefinitionUpdateResultRepresentation } from '@alfresco/js-api';
|
||||
import { argv, exit } from 'node:process';
|
||||
import { spawnSync } from 'node:child_process';
|
||||
import { createReadStream } from 'node:fs';
|
||||
@@ -33,11 +33,10 @@ const ACTIVITI_APPS = require('./resources').ACTIVITI_APPS;
|
||||
|
||||
let alfrescoJsApi: AlfrescoApi;
|
||||
|
||||
export default async function() {
|
||||
await main();
|
||||
}
|
||||
|
||||
async function main() {
|
||||
/**
|
||||
* Init APS command
|
||||
*/
|
||||
export default async function main() {
|
||||
|
||||
program
|
||||
.version('0.1.0')
|
||||
@@ -114,11 +113,14 @@ async function main() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise default applications
|
||||
*/
|
||||
async function initializeDefaultApps() {
|
||||
for (let x = 0; x < ACTIVITI_APPS.apps.length; x++) {
|
||||
const appInfo = ACTIVITI_APPS.apps[x];
|
||||
const isDefaultAppDepl = await isDefaultAppDeployed(appInfo.name);
|
||||
if (isDefaultAppDepl !== undefined && !isDefaultAppDepl) {
|
||||
const isDeployed = await isDefaultAppDeployed(appInfo.name);
|
||||
if (isDeployed !== undefined && !isDeployed) {
|
||||
const appDefinition = await importPublishApp(`${appInfo.name}`);
|
||||
await deployApp(appDefinition.appDefinition.id);
|
||||
} else {
|
||||
@@ -126,6 +128,10 @@ async function initializeDefaultApps() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check environment
|
||||
*/
|
||||
async function checkEnv() {
|
||||
try {
|
||||
alfrescoJsApi = new AlfrescoApi({
|
||||
@@ -160,7 +166,14 @@ async function checkEnv() {
|
||||
}
|
||||
}
|
||||
|
||||
async function hasDefaultTenant(tenantId: number, tenantName: string) {
|
||||
/**
|
||||
* Check if the default tenant is present
|
||||
*
|
||||
* @param tenantId tenant id
|
||||
* @param tenantName tenant name
|
||||
* @returns `true` if tenant is found, otherwise `false`
|
||||
*/
|
||||
async function hasDefaultTenant(tenantId: number, tenantName: string): Promise<boolean> {
|
||||
let tenant: TenantRepresentation;
|
||||
|
||||
try {
|
||||
@@ -180,6 +193,11 @@ async function hasDefaultTenant(tenantId: number, tenantName: string) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create default tenant
|
||||
*
|
||||
* @param tenantName tenant name
|
||||
*/
|
||||
async function createDefaultTenant(tenantName: string) {
|
||||
const tenantPost = {
|
||||
active: true,
|
||||
@@ -197,6 +215,12 @@ async function createDefaultTenant(tenantName: string) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create users
|
||||
*
|
||||
* @param tenantId tenant id
|
||||
* @param user user object
|
||||
*/
|
||||
async function createUsers(tenantId: number, user: any) {
|
||||
logger.info(`Create user ${user.email} on tenant: ${tenantId}`);
|
||||
const passwordCamelCase = 'Password';
|
||||
@@ -220,6 +244,9 @@ async function createUsers(tenantId: number, user: any) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update Activiti license
|
||||
*/
|
||||
async function updateLicense() {
|
||||
const fileContent = createReadStream(path.join(__dirname, '/activiti.lic'));
|
||||
|
||||
@@ -243,27 +270,38 @@ async function updateLicense() {
|
||||
}
|
||||
}
|
||||
|
||||
async function isDefaultAppDeployed(appName: string) {
|
||||
/**
|
||||
* Check if default application is deployed
|
||||
*
|
||||
* @param appName application name
|
||||
* @returns `true` if application is deployed, otherwise `false`
|
||||
*/
|
||||
async function isDefaultAppDeployed(appName: string): Promise<boolean> {
|
||||
logger.info(`Verify ${appName} already deployed`);
|
||||
try {
|
||||
const runtimeAppDefinitionsApi = new RuntimeAppDefinitionsApi(alfrescoJsApi);
|
||||
const availableApps = await runtimeAppDefinitionsApi.getAppDefinitions();
|
||||
const defaultApp = availableApps.data && availableApps.data.filter(app => app.name && app.name.includes(appName));
|
||||
const defaultApp = availableApps.data?.filter(app => app.name?.includes(appName));
|
||||
return defaultApp && defaultApp.length > 0;
|
||||
} catch (error) {
|
||||
logger.error(`Aps app failed to import/Publish!`);
|
||||
}
|
||||
}
|
||||
|
||||
async function importPublishApp(appName: string) {
|
||||
/**
|
||||
* Import and publish the application
|
||||
*
|
||||
* @param appName application name
|
||||
*/
|
||||
async function importPublishApp(appName: string): Promise<AppDefinitionUpdateResultRepresentation> {
|
||||
const appNameExtension = `../resources/${appName}.zip`;
|
||||
logger.info(`Import app ${appNameExtension}`);
|
||||
const pathFile = path.join(__dirname, appNameExtension);
|
||||
const fileContent = createReadStream(pathFile);
|
||||
|
||||
try {
|
||||
const appdefinitionsApi = new AppDefinitionsApi(alfrescoJsApi);
|
||||
const result = await appdefinitionsApi.importAndPublishApp(fileContent, {renewIdmEntries: true});
|
||||
const appDefinitionsApi = new AppDefinitionsApi(alfrescoJsApi);
|
||||
const result = await appDefinitionsApi.importAndPublishApp(fileContent, {renewIdmEntries: true});
|
||||
logger.info(`Aps app imported and published!`);
|
||||
return result;
|
||||
} catch (error) {
|
||||
@@ -271,6 +309,11 @@ async function importPublishApp(appName: string) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deploy application
|
||||
*
|
||||
* @param appDefinitionId app definition id
|
||||
*/
|
||||
async function deployApp(appDefinitionId: number) {
|
||||
logger.info(`Deploy app with id ${appDefinitionId}`);
|
||||
const body = {
|
||||
@@ -286,6 +329,9 @@ async function deployApp(appDefinitionId: number) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if Activiti app has license
|
||||
*/
|
||||
async function hasLicense(): Promise<boolean> {
|
||||
try {
|
||||
const license = await alfrescoJsApi.oauth2Auth.callCustomApi(
|
||||
@@ -310,6 +356,9 @@ async function hasLicense(): Promise<boolean> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default users from the realm
|
||||
*/
|
||||
async function getDefaultApsUsersFromRealm() {
|
||||
try {
|
||||
const users: any[] = await alfrescoJsApi.oauth2Auth.callCustomApi(
|
||||
@@ -332,6 +381,12 @@ async function getDefaultApsUsersFromRealm() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that ACS repo for Activiti is present
|
||||
*
|
||||
* @param tenantId tenant id
|
||||
* @param contentName content service name
|
||||
*/
|
||||
async function isContentRepoPresent(tenantId: number, contentName: string): Promise<boolean> {
|
||||
try {
|
||||
const contentRepos = await alfrescoJsApi.oauth2Auth.callCustomApi(
|
||||
@@ -351,6 +406,12 @@ async function isContentRepoPresent(tenantId: number, contentName: string): Prom
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add content service with basic auth
|
||||
*
|
||||
* @param tenantId tenant id
|
||||
* @param name content name
|
||||
*/
|
||||
async function addContentRepoWithBasic(tenantId: number, name: string) {
|
||||
logger.info(`Create Content with name ${name} and basic auth`);
|
||||
|
||||
@@ -384,6 +445,11 @@ async function addContentRepoWithBasic(tenantId: number, name: string) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Authorize activiti user to ACS repo
|
||||
*
|
||||
* @param user user object
|
||||
*/
|
||||
async function authorizeUserToContentRepo(user: any) {
|
||||
logger.info(`Authorize user ${user.email}`);
|
||||
try {
|
||||
@@ -398,7 +464,7 @@ async function authorizeUserToContentRepo(user: any) {
|
||||
['application/json'],
|
||||
['application/json']
|
||||
);
|
||||
logger.info(`Found ${content.data && content.data.length} contents`);
|
||||
logger.info(`Found ${content.data?.length} contents`);
|
||||
if (content.data) {
|
||||
for (let i = 0; i < content.data.length; i++) {
|
||||
if (content.data[i].authenticationType === 'basic') {
|
||||
@@ -412,6 +478,12 @@ async function authorizeUserToContentRepo(user: any) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Authorize user with content using basic auth
|
||||
*
|
||||
* @param username username
|
||||
* @param contentId content id
|
||||
*/
|
||||
async function authorizeUserToContentWithBasic(username: string, contentId: string) {
|
||||
logger.info(`Authorize ${username} on contentId: ${contentId} in basic auth`);
|
||||
try {
|
||||
@@ -434,6 +506,11 @@ async function authorizeUserToContentWithBasic(username: string, contentId: stri
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Download APS license file
|
||||
*
|
||||
* @param apsLicensePath path to license file
|
||||
*/
|
||||
async function downloadLicenseFile(apsLicensePath: string) {
|
||||
const args = [
|
||||
`s3`,
|
||||
@@ -454,6 +531,11 @@ async function downloadLicenseFile(apsLicensePath: string) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a delay
|
||||
*
|
||||
* @param delay timeout in milliseconds
|
||||
*/
|
||||
function sleep(delay: number) {
|
||||
const start = new Date().getTime();
|
||||
while (new Date().getTime() < start + delay) { }
|
||||
|
||||
@@ -63,6 +63,7 @@ export const deletePod = (args: KubeArgs) => {
|
||||
export const getNamespaces = (): string[] => {
|
||||
logger.info('Perform get namespaces name...');
|
||||
const result = exec('kubectl', [`get`, `namespaces`, `-l`, `type=application`, `-o`, `name`], {});
|
||||
// eslint-disable-next-line no-useless-escape
|
||||
const namespaces = result.replace(/namespace[\/]+/g, '').split(/\r?\n/);
|
||||
logger.info(`namespaces found: ${namespaces}`);
|
||||
return namespaces;
|
||||
|
||||
@@ -41,6 +41,12 @@ export interface ConfigArgs {
|
||||
intervalTime: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Alfresco Api instance
|
||||
*
|
||||
* @param args command parameters
|
||||
* @returns Alfresco Api instance
|
||||
*/
|
||||
function getAlfrescoJsApiInstance(args: ConfigArgs): AlfrescoApi {
|
||||
const config: AlfrescoApiConfig = {
|
||||
provider: 'BPM',
|
||||
@@ -60,6 +66,13 @@ function getAlfrescoJsApiInstance(args: ConfigArgs): AlfrescoApi {
|
||||
return new AlfrescoApi(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform login
|
||||
*
|
||||
* @param username username
|
||||
* @param password password
|
||||
* @param alfrescoJsApi api client
|
||||
*/
|
||||
async function login(username: string, password: string, alfrescoJsApi: AlfrescoApi) {
|
||||
logger.info(`Perform login...`);
|
||||
try {
|
||||
@@ -71,6 +84,13 @@ async function login(username: string, password: string, alfrescoJsApi: Alfresco
|
||||
logger.info(`Perform done...`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes deployment descriptor
|
||||
*
|
||||
* @param args command arguments
|
||||
* @param apiService api client
|
||||
* @param name descriptor name
|
||||
*/
|
||||
async function deleteDescriptor(args: ConfigArgs, apiService: AlfrescoApi, name: string) {
|
||||
logger.warn(`Delete the descriptor ${name}`);
|
||||
|
||||
@@ -104,6 +124,13 @@ async function deleteDescriptor(args: ConfigArgs, apiService: AlfrescoApi, name:
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes modeling project
|
||||
*
|
||||
* @param args arguments
|
||||
* @param apiService api client
|
||||
* @param projectId project id
|
||||
*/
|
||||
async function deleteProject(args: ConfigArgs, apiService: AlfrescoApi, projectId: string) {
|
||||
logger.warn(`Delete the project ${projectId}`);
|
||||
|
||||
@@ -137,6 +164,13 @@ async function deleteProject(args: ConfigArgs, apiService: AlfrescoApi, projectI
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes modeling project by name
|
||||
*
|
||||
* @param args arguments
|
||||
* @param apiService api client
|
||||
* @param name project name
|
||||
*/
|
||||
async function deleteProjectByName(args: ConfigArgs, apiService: AlfrescoApi, name: string) {
|
||||
logger.warn(`Get the project by name ${name}`);
|
||||
const url = `${args.host}/modeling-service/v1/projects?name=${name}`;
|
||||
@@ -172,6 +206,13 @@ async function deleteProjectByName(args: ConfigArgs, apiService: AlfrescoApi, na
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get applications by name
|
||||
*
|
||||
* @param args command arguments
|
||||
* @param apiService api client
|
||||
* @param name application name
|
||||
*/
|
||||
async function getApplicationsByName(args: ConfigArgs, apiService: AlfrescoApi, name: string) {
|
||||
logger.warn(`Get the applications by name ${name}`);
|
||||
const url = `${args.host}/deployment-service/v1/applications?name=${name}`;
|
||||
@@ -199,10 +240,17 @@ async function getApplicationsByName(args: ConfigArgs, apiService: AlfrescoApi,
|
||||
return apps ? apps.list.entries : [];
|
||||
} catch (error) {
|
||||
logger.error(`Not possible to get the applications with name ${name} ` + JSON.stringify(error));
|
||||
process.exit(1);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Undeploy applications by name
|
||||
*
|
||||
* @param args command arguments
|
||||
* @param apiService api client
|
||||
* @param name application name
|
||||
*/
|
||||
async function undeployApplication(args: ConfigArgs, apiService: AlfrescoApi, name: string) {
|
||||
logger.warn(`Undeploy the application ${name}`);
|
||||
|
||||
@@ -236,11 +284,6 @@ async function undeployApplication(args: ConfigArgs, apiService: AlfrescoApi, na
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line prefer-arrow/prefer-arrow-functions,space-before-function-paren
|
||||
export default async function (args: ConfigArgs) {
|
||||
await main(args);
|
||||
}
|
||||
|
||||
const main = async (args: ConfigArgs) => {
|
||||
program
|
||||
.version('0.1.0')
|
||||
@@ -330,3 +373,5 @@ const main = async (args: ConfigArgs) => {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default main;
|
||||
|
||||
@@ -17,14 +17,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { argv } from 'node:process';
|
||||
import program from 'commander';
|
||||
import * as kube from './kube-utils';
|
||||
|
||||
// eslint-disable-next-line prefer-arrow/prefer-arrow-functions
|
||||
export default function(args: kube.KubeArgs) {
|
||||
main(args);
|
||||
}
|
||||
|
||||
const main = (args: kube.KubeArgs) => {
|
||||
program
|
||||
.version('0.1.0')
|
||||
@@ -34,9 +30,9 @@ const main = (args: kube.KubeArgs) => {
|
||||
.option('--clusterEnv [type]', 'cluster Env')
|
||||
.option('--clusterUrl [type]', 'cluster Url')
|
||||
.option('--label [type]', 'label cluster')
|
||||
.parse(process.argv);
|
||||
.parse(argv);
|
||||
|
||||
if (process.argv.includes('-h') || process.argv.includes('--help')) {
|
||||
if (argv.includes('-h') || argv.includes('--help')) {
|
||||
program.outputHelp();
|
||||
return;
|
||||
}
|
||||
@@ -49,3 +45,5 @@ const main = (args: kube.KubeArgs) => {
|
||||
kube.deletePod(args);
|
||||
}
|
||||
};
|
||||
|
||||
export default main;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { argv } from 'node:process';
|
||||
import { exec } from './exec';
|
||||
import program from 'commander';
|
||||
import { logger } from './logger';
|
||||
@@ -29,16 +30,14 @@ const installPerform = () => {
|
||||
exec('curl', [`LO`, `${k8sRelease}`], {});
|
||||
};
|
||||
|
||||
// eslint-disable-next-line prefer-arrow/prefer-arrow-functions
|
||||
export default function(args: kube.KubeArgs) {
|
||||
main(args);
|
||||
}
|
||||
|
||||
const main = (args: kube.KubeArgs) => {
|
||||
program
|
||||
.version('0.1.0')
|
||||
.description('his command allows you to update a specific service on the rancher env with a specific tag \n\n' +
|
||||
'adf-cli kubectl-image --clusterEnv ${clusterEnv} --clusterUrl ${clusterUrl} --username ${username} --token ${token} --label ${label} --namespaces ${namespaces} --dockerRepo ${dockerRepo} --tag ${tag}')
|
||||
.description(
|
||||
'This command allows you to update a specific service on the rancher env with a specific tag \n\n' +
|
||||
'adf-cli kubectl-image --clusterEnv ${clusterEnv} --clusterUrl ${clusterUrl} --username ${username} --token ${token} --label ${label} --namespaces ${namespaces} --dockerRepo ${dockerRepo} --tag ${tag}'
|
||||
)
|
||||
.option('--tag [type]', 'tag')
|
||||
.option('--installCheck [type]', 'install kube ctl')
|
||||
.option('--username [type]', 'username')
|
||||
@@ -47,9 +46,9 @@ const main = (args: kube.KubeArgs) => {
|
||||
.option('--dockerRepo [type]', 'docker Repo')
|
||||
.option('--label [type]', 'pod label')
|
||||
.option('--namespaces [type]', 'list of namespaces')
|
||||
.parse(process.argv);
|
||||
.parse(argv);
|
||||
|
||||
if (process.argv.includes('-h') || process.argv.includes('--help')) {
|
||||
if (argv.includes('-h') || argv.includes('--help')) {
|
||||
program.outputHelp();
|
||||
return;
|
||||
}
|
||||
@@ -64,7 +63,7 @@ const main = (args: kube.KubeArgs) => {
|
||||
kube.setContext(args.clusterEnv, args.username);
|
||||
kube.useContext(args.clusterEnv);
|
||||
|
||||
let namespaces: string [];
|
||||
let namespaces: string[];
|
||||
if (args.namespaces === null || args.namespaces === 'default') {
|
||||
logger.info(`No namespaces provided. Fetch all of them`);
|
||||
namespaces = kube.getNamespaces();
|
||||
@@ -84,3 +83,5 @@ const main = (args: kube.KubeArgs) => {
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default main;
|
||||
|
||||
+86
-57
@@ -17,6 +17,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { argv, exit } from 'node:process';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
import * as checker from 'license-checker';
|
||||
@@ -48,15 +49,21 @@ const missingRepositories = {
|
||||
'rxjs-compat': 'https://github.com/ReactiveX/rxjs/tree/master/compat'
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a license with MD link
|
||||
*
|
||||
* @param licenseExp license expression
|
||||
* @returns license
|
||||
*/
|
||||
function licenseWithMDLinks(licenseExp: string): string {
|
||||
let licenseUrl = '';
|
||||
|
||||
if (licenseList[licenseExp] && licenseList[licenseExp]['url']) {
|
||||
if (licenseList[licenseExp]?.['url']) {
|
||||
licenseUrl = licenseList[licenseExp]['url'];
|
||||
} else {
|
||||
const substituteLicString = nonStandardLicenses[licenseExp.toLowerCase()];
|
||||
|
||||
if (licenseList[substituteLicString] && licenseList[substituteLicString]['url']) {
|
||||
if (licenseList[substituteLicString]?.['url']) {
|
||||
licenseUrl = licenseList[substituteLicString]['url'];
|
||||
}
|
||||
}
|
||||
@@ -68,24 +75,37 @@ function licenseWithMDLinks(licenseExp: string): string {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get package file
|
||||
*
|
||||
* @param packagePath package.json path
|
||||
* @returns package model
|
||||
*/
|
||||
function getPackageFile(packagePath: string): PackageInfo {
|
||||
try {
|
||||
return JSON.parse(fs.readFileSync(packagePath).toString());
|
||||
} catch {
|
||||
console.error('Error parsing package.json file');
|
||||
process.exit(1);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Licenses command
|
||||
*
|
||||
* @param _args (not used)
|
||||
* @param workingDir working directory
|
||||
* @returns void function
|
||||
*/
|
||||
export default function main(_args: string[], workingDir: string) {
|
||||
program
|
||||
.description('Generate a licences report')
|
||||
.usage('licenses [options]')
|
||||
.option('-p, --package <path>', 'Path to package file (default: package.json in working directory)')
|
||||
.option('-d, --outDir <dir>', 'Ouput directory (default: working directory)')
|
||||
.parse(process.argv);
|
||||
.parse(argv);
|
||||
|
||||
if (process.argv.includes('-h') || process.argv.includes('--help')) {
|
||||
if (argv.includes('-h') || argv.includes('--help')) {
|
||||
program.outputHelp();
|
||||
return;
|
||||
}
|
||||
@@ -98,74 +118,83 @@ export default function main(_args: string[], workingDir: string) {
|
||||
|
||||
if (!fs.existsSync(packagePath)) {
|
||||
console.error('The package.json file was not found');
|
||||
process.exit(1);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
const templatePath = path.resolve(__dirname, '../templates/licensePage.ejs');
|
||||
if (!fs.existsSync(templatePath)) {
|
||||
console.error(`Cannot find the report template: ${templatePath}`);
|
||||
process.exit(1);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.info(`Checking ${packagePath}`);
|
||||
|
||||
checker.init({
|
||||
start: workingDir,
|
||||
production: true,
|
||||
failOn: 'GPL'
|
||||
}, function(err: any, packages: any[]) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
reject(err);
|
||||
} else {
|
||||
// eslint-disable-next-line guard-for-in
|
||||
for (const packageName in packages) {
|
||||
const pack = packages[packageName];
|
||||
pack['licenseExp'] = pack['licenses'].toString()
|
||||
.replace(/\*/, '')
|
||||
.replace(/[a-zA-Z0-9\-\.]+/g, (match: string) => {
|
||||
const lowerMatch = match.toLowerCase();
|
||||
checker.init(
|
||||
{
|
||||
start: workingDir,
|
||||
production: true,
|
||||
failOn: 'GPL'
|
||||
},
|
||||
(err: any, packages: any[]) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
reject(err);
|
||||
} else {
|
||||
// eslint-disable-next-line guard-for-in
|
||||
for (const packageName in packages) {
|
||||
const pack = packages[packageName];
|
||||
pack['licenseExp'] = pack['licenses']
|
||||
.toString()
|
||||
.replace(/\*/g, '')
|
||||
.replace(/[a-zA-Z0-9\-.]+/g, (match: string) => {
|
||||
const lowerMatch = match.toLowerCase();
|
||||
|
||||
if ((lowerMatch !== 'and') && (lowerMatch !== 'or') && (lowerMatch !== 'with')) {
|
||||
return licenseWithMDLinks(match);
|
||||
} else {
|
||||
return match;
|
||||
if (lowerMatch !== 'and' && lowerMatch !== 'or' && lowerMatch !== 'with') {
|
||||
return licenseWithMDLinks(match);
|
||||
} else {
|
||||
return match;
|
||||
}
|
||||
});
|
||||
|
||||
if (!pack['repository']) {
|
||||
const lastAtSignPos = packageName.lastIndexOf('@');
|
||||
const mainName = packageName.substring(0, lastAtSignPos);
|
||||
|
||||
if (missingRepositories[mainName]) {
|
||||
pack['repository'] = missingRepositories[mainName];
|
||||
}
|
||||
});
|
||||
|
||||
if (!pack['repository']) {
|
||||
const lastAtSignPos = packageName.lastIndexOf('@');
|
||||
const mainName = packageName.substring(0, lastAtSignPos);
|
||||
|
||||
if (missingRepositories[mainName]) {
|
||||
pack['repository'] = missingRepositories[mainName];
|
||||
}
|
||||
}
|
||||
|
||||
const packageJson: PackageInfo = getPackageFile(packagePath);
|
||||
|
||||
ejs.renderFile(
|
||||
templatePath,
|
||||
{
|
||||
packages,
|
||||
projVersion: packageJson.version,
|
||||
projName: packageJson.name
|
||||
},
|
||||
{},
|
||||
(ejsError: any, mdText: string) => {
|
||||
if (ejsError) {
|
||||
console.error(ejsError);
|
||||
reject(ejsError);
|
||||
} else {
|
||||
const outputPath = path.resolve(program.outDir || workingDir);
|
||||
const outputFile = path.join(outputPath, `license-info-${packageJson.version}.md`);
|
||||
|
||||
fs.writeFileSync(outputFile, mdText);
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(`Report saved as ${outputFile}`);
|
||||
resolve(0);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const packageJson: PackageInfo = getPackageFile(packagePath);
|
||||
|
||||
ejs.renderFile(templatePath, {
|
||||
packages,
|
||||
projVersion: packageJson.version,
|
||||
projName: packageJson.name
|
||||
}, {}, (ejsError: any, mdText: string) => {
|
||||
if (ejsError) {
|
||||
console.error(ejsError);
|
||||
reject(ejsError);
|
||||
} else {
|
||||
const outputPath = path.resolve(program.outDir || workingDir);
|
||||
const outputFile = path.join(outputPath, `license-info-${packageJson.version}.md`);
|
||||
|
||||
fs.writeFileSync(outputFile, mdText);
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(`Report saved as ${outputFile}`);
|
||||
resolve(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { exit } from 'node:process';
|
||||
|
||||
/* eslint-disable */
|
||||
let log = null;
|
||||
|
||||
@@ -23,9 +25,9 @@ log = {
|
||||
info: console.log.bind(console),
|
||||
warn: console.warn.bind(console),
|
||||
error: console.error.bind(console),
|
||||
fatal: x => {
|
||||
console.error(x);
|
||||
process.exit(100);
|
||||
fatal: (err) => {
|
||||
console.error(err);
|
||||
exit(100);
|
||||
},
|
||||
createChild: () => log
|
||||
};
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { argv } from 'node:process';
|
||||
import * as path from 'path';
|
||||
import fs = require('fs');
|
||||
import { exec } from './exec';
|
||||
@@ -31,17 +32,14 @@ export interface PublishArgs {
|
||||
dryrun?: boolean;
|
||||
}
|
||||
|
||||
const projects = [
|
||||
'cli',
|
||||
'core',
|
||||
'insights',
|
||||
'testing',
|
||||
'content-services',
|
||||
'process-services',
|
||||
'process-services-cloud',
|
||||
'extensions'
|
||||
];
|
||||
const projects = ['cli', 'core', 'insights', 'testing', 'content-services', 'process-services', 'process-services-cloud', 'extensions'];
|
||||
|
||||
/**
|
||||
* Publish to NPM command
|
||||
*
|
||||
* @param args command arguments
|
||||
* @param project project name
|
||||
*/
|
||||
async function npmPublish(args: PublishArgs, project: string) {
|
||||
if (args.dryrun) {
|
||||
logger.info(`Dry run mode, no publish will be done`);
|
||||
@@ -75,11 +73,17 @@ async function npmPublish(args: PublishArgs, project: string) {
|
||||
await sleep(30000);
|
||||
} else {
|
||||
logger.info(`@alfresco/adf-${project}@${version} already exist`);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function npmCheckExist(project: string, version: string) {
|
||||
/**
|
||||
* Checks the library exists on npm already
|
||||
*
|
||||
* @param project project name
|
||||
* @param version project version
|
||||
* @returns `true` if given project exists on NPM, otherwise `false`
|
||||
*/
|
||||
function npmCheckExist(project: string, version: string): boolean {
|
||||
logger.info(`Check if lib ${project} is already in npm with version ${version}`);
|
||||
let exist = '';
|
||||
try {
|
||||
@@ -91,11 +95,16 @@ function npmCheckExist(project: string, version: string) {
|
||||
return exist !== '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Change NPM registry
|
||||
*
|
||||
* @param args command parameters
|
||||
* @param project project name
|
||||
*/
|
||||
function changeRegistry(args: PublishArgs, project: string) {
|
||||
logger.info(`Change registry... to ${args.npmRegistry} `);
|
||||
const folder = `${args.pathProject}/dist/libs/${project}`;
|
||||
const content =
|
||||
`strict-ssl=true
|
||||
const content = `strict-ssl=true
|
||||
always-auth=true
|
||||
@alfresco:registry=https://${args.npmRegistry}
|
||||
//${args.npmRegistry}/:_authToken="${args.tokenRegistry}"`;
|
||||
@@ -108,6 +117,12 @@ always-auth=true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes custom `.npmrc` configuration file
|
||||
*
|
||||
* @param args command arguments
|
||||
* @param project project name
|
||||
*/
|
||||
function removeNpmConfig(args: PublishArgs, project: string) {
|
||||
logger.info(`Removing file from ${project}`);
|
||||
try {
|
||||
@@ -118,23 +133,25 @@ function removeNpmConfig(args: PublishArgs, project: string) {
|
||||
}
|
||||
}
|
||||
|
||||
export default async function(args: PublishArgs) {
|
||||
await main(args);
|
||||
}
|
||||
|
||||
async function main(args) {
|
||||
|
||||
/**
|
||||
* Publish to NPM command
|
||||
*
|
||||
* @param args command arguments
|
||||
*/
|
||||
export default async function main(args: PublishArgs) {
|
||||
program
|
||||
.version('0.1.0')
|
||||
.description('Move in the folder where you have your Dockerfile and run the command \n\n adf-cli docker-publish --dockerRepo "${docker_repository}" --dockerTags "${TAGS}" --pathProject "$(pwd)')
|
||||
.description(
|
||||
'Move in the folder where you have your Dockerfile and run the command \n\n adf-cli docker-publish --dockerRepo "${docker_repository}" --dockerTags "${TAGS}" --pathProject "$(pwd)'
|
||||
)
|
||||
.option('--tag [type]', 'tag')
|
||||
.option('--npmRegistry [type]', 'npm Registry')
|
||||
.option('--tokenRegistry [type]', 'token Registry')
|
||||
.option('--pathProject [type]', 'pathProject')
|
||||
.option('--dryrun [type]', 'dryrun')
|
||||
.parse(process.argv);
|
||||
.parse(argv);
|
||||
|
||||
if (process.argv.includes('-h') || process.argv.includes('--help')) {
|
||||
if (argv.includes('-h') || argv.includes('--help')) {
|
||||
program.outputHelp();
|
||||
return;
|
||||
}
|
||||
@@ -145,7 +162,12 @@ async function main(args) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a timeout
|
||||
*
|
||||
* @param ms timeout in milliseconds
|
||||
*/
|
||||
async function sleep(ms: number) {
|
||||
logger.info(`Waiting for ${ms} milliseconds...`);
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ export class ProcessAutomationHealth {
|
||||
const url = `${this.plugInInfo.host}/${this.plugInInfo.appName}/ui/${this.plugInInfo.uiName}/app.config.json`;
|
||||
const appConfig = await this.config.getAppConfig(url);
|
||||
let isEnabled = true;
|
||||
if (appConfig && appConfig.plugins && appConfig.plugins[this.plugInInfo.name]) {
|
||||
if (appConfig?.plugins?.[this.plugInInfo.name]) {
|
||||
logger.info(`The plugin ${this.plugInInfo.name} has been correctly configured in app.config.json`);
|
||||
} else {
|
||||
this.logConfigurationError();
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
|
||||
import { exit } from 'node:process';
|
||||
import { PluginInterface } from './plugin-model';
|
||||
import { logger } from '../logger';
|
||||
import { ProcessServiceHealth } from './process-services-health';
|
||||
@@ -50,13 +51,13 @@ export class ProcessServiceCheckPlugin {
|
||||
}
|
||||
];
|
||||
console.table(pluginStatus);
|
||||
process.exit(1);
|
||||
exit(1);
|
||||
}
|
||||
} catch (e) {
|
||||
this.logConfigurationError(e);
|
||||
pluginStatus = [{ PluginName: this.plugInInfo.name, Status: 'Inactive', BE: 'DOWN', FE: 'Disabled' }];
|
||||
console.table(pluginStatus);
|
||||
process.exit(1);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ export class ProcessServiceHealth {
|
||||
const url = `${this.plugInInfo.host}/app.config.json`;
|
||||
const appConfig = await this.config.getAppConfig(url);
|
||||
let isEnabled = true;
|
||||
if (appConfig && appConfig.plugins && appConfig.plugins[this.plugInInfo.name]) {
|
||||
if (appConfig?.plugins?.[this.plugInInfo.name]) {
|
||||
logger.info(`The plugin ${this.plugInInfo.name} has been correctly configured in app.config.json`);
|
||||
} else {
|
||||
this.logConfigurationError();
|
||||
|
||||
@@ -45,7 +45,10 @@ const green = '\x1b[32m';
|
||||
let alfrescoApi: AlfrescoApi;
|
||||
let loginAttempts: number = 0;
|
||||
|
||||
export default async function main(_args: string[]) {
|
||||
/**
|
||||
* Scan environment command
|
||||
*/
|
||||
export default async function main() {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log = () => {};
|
||||
|
||||
@@ -72,6 +75,12 @@ export default async function main(_args: string[]) {
|
||||
logger.info(generateTable(rowsToPrint));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate table
|
||||
*
|
||||
* @param rowsToPrint list of table rows to print
|
||||
* @returns table as a string
|
||||
*/
|
||||
function generateTable(rowsToPrint: Array<RowToPrint>) {
|
||||
const columnWidths = rowsToPrint.reduce(
|
||||
(maxWidths, row: RowToPrint) => ({
|
||||
@@ -99,6 +108,9 @@ ${grey}╞${horizontalLine}╡${reset}`;
|
||||
return tableString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to login
|
||||
*/
|
||||
async function attemptLogin() {
|
||||
logger.info(` Logging into ${yellow}${program.host}${reset} with user ${yellow}${program.username}${reset}`);
|
||||
try {
|
||||
@@ -123,6 +135,11 @@ async function attemptLogin() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles login error
|
||||
*
|
||||
* @param loginError error object
|
||||
*/
|
||||
async function handleLoginError(loginError) {
|
||||
if (loginAttempts === 0) {
|
||||
logger.error(` ${red}Login SSO error${reset}`);
|
||||
@@ -150,6 +167,11 @@ async function handleLoginError(loginError) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check environment is reachable
|
||||
*
|
||||
* @param loginError error object
|
||||
*/
|
||||
function checkEnvReachable(loginError) {
|
||||
const failingErrorCodes = ['ENOTFOUND', 'ETIMEDOUT', 'ECONNREFUSED'];
|
||||
if (typeof loginError === 'object' && failingErrorCodes.indexOf(loginError.code) > -1) {
|
||||
@@ -158,6 +180,11 @@ function checkEnvReachable(loginError) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get people count
|
||||
*
|
||||
* @param skipCount skip count
|
||||
*/
|
||||
async function getPeopleCount(skipCount: number = 0): Promise<PeopleTally> {
|
||||
if (skipCount === 0) {
|
||||
logger.info(` Fetching number of users`);
|
||||
@@ -191,6 +218,9 @@ async function getPeopleCount(skipCount: number = 0): Promise<PeopleTally> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the amount of Home folders
|
||||
*/
|
||||
async function getHomeFoldersCount(): Promise<number> {
|
||||
logger.info(` Fetching number of home folders`);
|
||||
try {
|
||||
@@ -205,6 +235,9 @@ async function getHomeFoldersCount(): Promise<number> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the amount of groups
|
||||
*/
|
||||
async function getGroupsCount(): Promise<number> {
|
||||
logger.info(` Fetching number of groups`);
|
||||
try {
|
||||
@@ -216,6 +249,9 @@ async function getGroupsCount(): Promise<number> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the amount of sites
|
||||
*/
|
||||
async function getSitesCount(): Promise<number> {
|
||||
logger.info(` Fetching number of sites`);
|
||||
try {
|
||||
@@ -227,6 +263,9 @@ async function getSitesCount(): Promise<number> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the amount of files
|
||||
*/
|
||||
async function getFilesCount(): Promise<number> {
|
||||
logger.info(` Fetching number of files`);
|
||||
try {
|
||||
@@ -246,9 +285,14 @@ async function getFilesCount(): Promise<number> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle error
|
||||
*
|
||||
* @param error error object
|
||||
*/
|
||||
function handleError(error) {
|
||||
logger.error(` ${red}Error encountered${reset}`);
|
||||
if (error && error.response && error?.response?.text) {
|
||||
if (error?.response && error?.response?.text) {
|
||||
try {
|
||||
const parsedJson = JSON.parse(error?.response?.text);
|
||||
if (typeof parsedJson === 'object' && parsedJson.error) {
|
||||
@@ -262,11 +306,19 @@ function handleError(error) {
|
||||
failScript();
|
||||
}
|
||||
|
||||
/**
|
||||
* Log the error and exit
|
||||
*/
|
||||
function failScript() {
|
||||
logger.error(`${red}${bright}Environment scan failed. Exiting${reset}`);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait with a certain period
|
||||
*
|
||||
* @param ms timeout in milliseconds
|
||||
*/
|
||||
async function wait(ms: number) {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(resolve, ms);
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { argv } from 'node:process';
|
||||
import { exec } from './exec';
|
||||
import program from 'commander';
|
||||
import { logger } from './logger';
|
||||
@@ -27,6 +28,12 @@ export interface CommitArgs {
|
||||
skipGnu: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get commit SHA
|
||||
*
|
||||
* @param args command arguments
|
||||
* @returns commit SHA value
|
||||
*/
|
||||
function getSha(args: CommitArgs): string {
|
||||
logger.info('Check commit sha...');
|
||||
|
||||
@@ -35,9 +42,16 @@ function getSha(args: CommitArgs): string {
|
||||
return exec('git', [`rev-parse`, `${gitPointer}`], {}).trim();
|
||||
}
|
||||
|
||||
function replacePerform(args: CommitArgs, sha: string) {
|
||||
/**
|
||||
* Performs the sha replacement
|
||||
*
|
||||
* @param args command parameters
|
||||
* @param sha value to use
|
||||
*/
|
||||
function performReplace(args: CommitArgs, sha: string) {
|
||||
logger.info(`Replace commit ${sha} in package...`);
|
||||
|
||||
// eslint-disable-next-line no-useless-escape
|
||||
const sedRule = `s/\"commit\": \".*\"/\"commit\": \"${sha}\"/g`;
|
||||
|
||||
if (args.skipGnu) {
|
||||
@@ -47,29 +61,31 @@ function replacePerform(args: CommitArgs, sha: string) {
|
||||
}
|
||||
}
|
||||
|
||||
export default function(args: CommitArgs) {
|
||||
main(args);
|
||||
}
|
||||
|
||||
function main(args) {
|
||||
|
||||
/**
|
||||
* Update commit SHA command
|
||||
*
|
||||
* @param args command arguments
|
||||
*/
|
||||
export default function main(args: CommitArgs) {
|
||||
program
|
||||
.version('0.1.0')
|
||||
.description('This command allows you to update the commit sha as part of the package.json.\n' +
|
||||
'Your package.json must to have an existing property called "commit.\n\n' +
|
||||
'adf-cli update-commit-sha --pointer "HEAD~1" --pathProject "$(pwd)"\n\n' +
|
||||
'adf-cli update-commit-sha --pathProject "$(pwd)" --skipGnu')
|
||||
.description(
|
||||
'This command allows you to update the commit sha as part of the package.json.\n' +
|
||||
'Your package.json must to have an existing property called "commit.\n\n' +
|
||||
'adf-cli update-commit-sha --pointer "HEAD~1" --pathProject "$(pwd)"\n\n' +
|
||||
'adf-cli update-commit-sha --pathProject "$(pwd)" --skipGnu'
|
||||
)
|
||||
.option('--pointer [type]', 'pointer')
|
||||
.option('--pathPackage [type]', 'pathPackage')
|
||||
.option('--skipGnu [type]', 'skipGnu')
|
||||
.parse(process.argv);
|
||||
.parse(argv);
|
||||
|
||||
if (process.argv.includes('-h') || process.argv.includes('--help')) {
|
||||
if (argv.includes('-h') || argv.includes('--help')) {
|
||||
program.outputHelp();
|
||||
return;
|
||||
}
|
||||
|
||||
const sha = getSha(args);
|
||||
|
||||
replacePerform(args, sha);
|
||||
performReplace(args, sha);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { argv } from 'node:process';
|
||||
import program from 'commander';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
@@ -36,6 +37,12 @@ export interface PackageInfo {
|
||||
devDependencies?: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse alfresco libraries in package.json file
|
||||
*
|
||||
* @param workingDir working directory
|
||||
* @returns package info model
|
||||
*/
|
||||
function parseAlfrescoLibs(workingDir: string): PackageInfo {
|
||||
const packagePath = path.resolve(path.join(workingDir, 'package.json'));
|
||||
|
||||
@@ -46,8 +53,8 @@ function parseAlfrescoLibs(workingDir: string): PackageInfo {
|
||||
const json = require(packagePath);
|
||||
const isAlfrescoLib = (key: string) => key.startsWith('@alfresco');
|
||||
|
||||
dependencies = Object.keys((json.dependencies || [])).filter(isAlfrescoLib);
|
||||
devDependencies = Object.keys((json.devDependencies || [])).filter(isAlfrescoLib);
|
||||
dependencies = Object.keys(json.dependencies || []).filter(isAlfrescoLib);
|
||||
devDependencies = Object.keys(json.devDependencies || []).filter(isAlfrescoLib);
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -56,13 +63,23 @@ function parseAlfrescoLibs(workingDir: string): PackageInfo {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Format npm command
|
||||
*
|
||||
* @param deps dependencies
|
||||
* @param tag tag
|
||||
* @returns npm command to execute
|
||||
*/
|
||||
function formatNpmCommand(deps: string[], tag: string): string {
|
||||
return [
|
||||
'npm i -E',
|
||||
deps.map(name => `${name}@${tag}`).join(' ')
|
||||
].join(' ');
|
||||
return ['npm i -E', deps.map((name) => `${name}@${tag}`).join(' ')].join(' ');
|
||||
}
|
||||
|
||||
/**
|
||||
* Run npm command
|
||||
*
|
||||
* @param command command to execute
|
||||
* @param workingDir working directory
|
||||
*/
|
||||
function runNpmCommand(command: string, workingDir: string) {
|
||||
if (shell.exec(command, { cwd: workingDir }).code !== 0) {
|
||||
shell.echo('Error running NPM command');
|
||||
@@ -70,25 +87,32 @@ function runNpmCommand(command: string, workingDir: string) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update libraries
|
||||
*
|
||||
* @param pkg package info model
|
||||
* @param tag tag name
|
||||
* @param workingDir working directory
|
||||
*/
|
||||
function updateLibs(pkg: PackageInfo, tag: string, workingDir: string) {
|
||||
if (pkg.dependencies && pkg.dependencies.length > 0) {
|
||||
runNpmCommand(
|
||||
formatNpmCommand(pkg.dependencies, tag),
|
||||
workingDir
|
||||
);
|
||||
runNpmCommand(formatNpmCommand(pkg.dependencies, tag), workingDir);
|
||||
}
|
||||
|
||||
if (pkg.devDependencies && pkg.devDependencies.length > 0) {
|
||||
runNpmCommand(
|
||||
formatNpmCommand(pkg.devDependencies, tag) + ' -D',
|
||||
workingDir
|
||||
);
|
||||
runNpmCommand(formatNpmCommand(pkg.devDependencies, tag) + ' -D', workingDir);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse tag
|
||||
*
|
||||
* @param args update arguments
|
||||
* @returns tag value
|
||||
*/
|
||||
function parseTag(args: UpdateArgs): string {
|
||||
if (args.alpha) {
|
||||
return 'alpha';
|
||||
return 'alpha';
|
||||
}
|
||||
|
||||
if (args.beta) {
|
||||
@@ -98,19 +122,27 @@ function parseTag(args: UpdateArgs): string {
|
||||
return args.version || 'latest';
|
||||
}
|
||||
|
||||
/**
|
||||
* update version command
|
||||
*
|
||||
* @param args arguments
|
||||
* @param workingDir working directory
|
||||
*/
|
||||
export default function main(args: UpdateArgs, workingDir: string) {
|
||||
program
|
||||
.description('This command allows you to update the adf dependencies and js-api with different versions\n\n' +
|
||||
'Update adf libs and js-api with latest alpha\n\n' +
|
||||
'adf-cli update-version --alpha')
|
||||
.description(
|
||||
'This command allows you to update the adf dependencies and js-api with different versions\n\n' +
|
||||
'Update adf libs and js-api with latest alpha\n\n' +
|
||||
'adf-cli update-version --alpha'
|
||||
)
|
||||
.option('--pathPackage [dir]', 'Directory that contains package.json file', 'current directory')
|
||||
.option('--alpha', 'use alpha')
|
||||
.option('--beta', 'use beta')
|
||||
.option('--version [tag]', 'use specific version can be also alpha/beta/latest', 'latest')
|
||||
.option('--vjs [tag]', 'Upgrade only JS-API to a specific version')
|
||||
.parse(process.argv);
|
||||
.parse(argv);
|
||||
|
||||
if (process.argv.includes('-h') || process.argv.includes('--help')) {
|
||||
if (argv.includes('-h') || argv.includes('--help')) {
|
||||
program.outputHelp();
|
||||
return;
|
||||
}
|
||||
@@ -118,9 +150,7 @@ export default function main(args: UpdateArgs, workingDir: string) {
|
||||
workingDir = args.pathPackage || workingDir;
|
||||
|
||||
const tag = args.vjs || parseTag(args);
|
||||
const pkg = args.vjs
|
||||
? { dependencies: ['@alfresco/js-api'] }
|
||||
: parseAlfrescoLibs(workingDir);
|
||||
const pkg = args.vjs ? { dependencies: ['@alfresco/js-api'] } : parseAlfrescoLibs(workingDir);
|
||||
|
||||
updateLibs(pkg, tag, workingDir);
|
||||
}
|
||||
|
||||
@@ -4,10 +4,7 @@
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.ts"],
|
||||
"extends": [
|
||||
"plugin:@nrwl/nx/angular",
|
||||
"plugin:@angular-eslint/template/process-inline-templates"
|
||||
],
|
||||
"extends": ["plugin:@nrwl/nx/angular", "plugin:@angular-eslint/template/process-inline-templates"],
|
||||
"rules": {
|
||||
"jsdoc/newline-after-description": "warn",
|
||||
"@typescript-eslint/naming-convention": "warn",
|
||||
@@ -27,24 +24,15 @@
|
||||
"error",
|
||||
{
|
||||
"type": "element",
|
||||
"prefix": [
|
||||
"adf",
|
||||
"app"
|
||||
],
|
||||
"prefix": ["adf", "app"],
|
||||
"style": "kebab-case"
|
||||
}
|
||||
],
|
||||
"@angular-eslint/directive-selector": [
|
||||
"error",
|
||||
{
|
||||
"type": [
|
||||
"element",
|
||||
"attribute"
|
||||
],
|
||||
"prefix": [
|
||||
"adf",
|
||||
"app"
|
||||
],
|
||||
"type": ["element", "attribute"],
|
||||
"prefix": ["adf", "app"],
|
||||
"style": "kebab-case"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -1,15 +1,9 @@
|
||||
const rootMain = require('../../../.storybook/main');
|
||||
|
||||
module.exports = {
|
||||
...rootMain,
|
||||
core: { ...rootMain.core, builder: 'webpack5' },
|
||||
stories: [
|
||||
...rootMain.stories,
|
||||
'../**/*.stories.@(js|jsx|ts|tsx)'
|
||||
],
|
||||
staticDirs: [
|
||||
...rootMain.staticDirs,
|
||||
{ from: __dirname + '/../src/lib/i18n', to: 'assets/adf-content-services/i18n' }
|
||||
],
|
||||
addons: [...rootMain.addons ]
|
||||
...rootMain,
|
||||
core: { ...rootMain.core, builder: 'webpack5' },
|
||||
stories: [...rootMain.stories, '../**/*.stories.@(js|jsx|ts|tsx)'],
|
||||
staticDirs: [...rootMain.staticDirs, { from: __dirname + '/../src/lib/i18n', to: 'assets/adf-content-services/i18n' }],
|
||||
addons: [...rootMain.addons]
|
||||
};
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
"@angular/platform-browser": ">=14.1.3",
|
||||
"@angular/platform-browser-dynamic": ">=14.1.3",
|
||||
"@angular/router": ">=14.1.3",
|
||||
"@alfresco/js-api": ">=7.0.0",
|
||||
"@alfresco/js-api": ">=7.1.0-1372",
|
||||
"@ngx-translate/core": ">=14.0.0",
|
||||
"moment": ">=2.22.2",
|
||||
"@alfresco/adf-core": ">=6.3.0"
|
||||
|
||||
@@ -129,9 +129,9 @@ describe('AspectListComponent', () => {
|
||||
});
|
||||
|
||||
it('should show the loading spinner when result is loading', () => {
|
||||
const delayReusult = of(null).pipe(delay(0));
|
||||
spyOn(nodeService, 'getNode').and.returnValue(delayReusult);
|
||||
spyOn(aspectListService, 'getAspects').and.returnValue(delayReusult);
|
||||
const delayResult = of(null).pipe(delay(0));
|
||||
spyOn(nodeService, 'getNode').and.returnValue(delayResult);
|
||||
spyOn(aspectListService, 'getAspects').and.returnValue(delayResult);
|
||||
fixture.detectChanges();
|
||||
const spinner = fixture.nativeElement.querySelector('#adf-aspect-spinner');
|
||||
expect(spinner).toBeDefined();
|
||||
|
||||
@@ -68,7 +68,7 @@ export class AuditService {
|
||||
* @param auditApplicationId The identifier of an audit application.
|
||||
* @param auditAppBodyUpdate The audit application to update.
|
||||
* @param opts Options.
|
||||
* @returns
|
||||
* @returns audit application model
|
||||
*/
|
||||
updateAuditApp(auditApplicationId: string, auditAppBodyUpdate: boolean, opts?: any): Observable<AuditApp | any> {
|
||||
const defaultOptions = {};
|
||||
@@ -117,7 +117,7 @@ export class AuditService {
|
||||
*
|
||||
* @param nodeId The identifier of a node.
|
||||
* @param opts Options.
|
||||
* @returns
|
||||
* @returns audit entry list
|
||||
*/
|
||||
getAuditEntriesForNode(nodeId: string, opts?: any): Observable<AuditEntryPaging> {
|
||||
const defaultOptions = {
|
||||
@@ -132,7 +132,7 @@ export class AuditService {
|
||||
*
|
||||
* @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.
|
||||
* @returns
|
||||
* @returns void operation
|
||||
*/
|
||||
deleteAuditEntries(auditApplicationId: string, where: string): Observable<any> {
|
||||
return from(this.auditApi.deleteAuditEntriesForAuditApp(auditApplicationId, where)).pipe(catchError((err: any) => this.handleError(err)));
|
||||
@@ -143,7 +143,7 @@ export class AuditService {
|
||||
*
|
||||
* @param auditApplicationId The identifier of an audit application.
|
||||
* @param auditEntryId The identifier of an audit entry.
|
||||
* @returns
|
||||
* @returns void operation
|
||||
*/
|
||||
deleteAuditEntry(auditApplicationId: string, auditEntryId: string): Observable<any> {
|
||||
return from(this.auditApi.deleteAuditEntry(auditApplicationId, auditEntryId)).pipe(catchError((err: any) => this.handleError(err)));
|
||||
|
||||
@@ -34,26 +34,30 @@ export class BreadcrumbComponent implements OnInit, OnChanges, OnDestroy {
|
||||
@Input()
|
||||
folderNode: Node = null;
|
||||
|
||||
/** (optional) Name of the root element of the breadcrumb. You can use
|
||||
/**
|
||||
* Name of the root element of the breadcrumb. You can use
|
||||
* this property to rename "Company Home" to "Personal Files" for
|
||||
* example. You can use an i18n resource key for the property value.
|
||||
*/
|
||||
@Input()
|
||||
root: string = null;
|
||||
root?: string = null;
|
||||
|
||||
/** (optional) The id of the root element. You can use this property
|
||||
/**
|
||||
* The id of the root element. You can use this property
|
||||
* to set a custom element the breadcrumb should start with.
|
||||
*/
|
||||
@Input()
|
||||
rootId: string = null;
|
||||
rootId?: string = null;
|
||||
|
||||
/** (optional) Document List component to operate with. The list will
|
||||
/**
|
||||
* Document List component to operate with. The list will
|
||||
* update when the breadcrumb is clicked.
|
||||
*/
|
||||
@Input()
|
||||
target: DocumentListComponent;
|
||||
target?: DocumentListComponent;
|
||||
|
||||
/** Transformation to be performed on the chosen/folder node before building
|
||||
/**
|
||||
* Transformation to be performed on the chosen/folder node before building
|
||||
* the breadcrumb UI. Can be useful when custom formatting is needed for the
|
||||
* breadcrumb. You can change the path elements from the node that are used to
|
||||
* build the breadcrumb using this function.
|
||||
|
||||
@@ -56,7 +56,9 @@ export class DropdownBreadcrumbComponent extends BreadcrumbComponent implements
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if route has more than one element (means: we are not in the root directory)
|
||||
* Check if route has more than one element (means: we are not in the root directory)
|
||||
*
|
||||
* @returns `true` if there are previous nodes, otherwise `false`
|
||||
*/
|
||||
hasPreviousNodes(): boolean {
|
||||
return this.previousNodes.length > 0;
|
||||
|
||||
+78
-15
@@ -67,18 +67,40 @@ describe('CategoriesManagementComponent', () => {
|
||||
categoryService = TestBed.inject(CategoryService);
|
||||
});
|
||||
|
||||
/**
|
||||
* Get no categories message
|
||||
*
|
||||
* @returns message text
|
||||
*/
|
||||
function getNoCategoriesMessage(): string {
|
||||
return fixture.debugElement.query(By.css(`.adf-no-categories-message`))?.nativeElement.textContent.trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get assigned categories list
|
||||
*
|
||||
* @returns list of native elements
|
||||
*/
|
||||
function getAssignedCategoriesList(): HTMLSpanElement[] {
|
||||
return fixture.debugElement.queryAll(By.css('.adf-assigned-categories'))?.map((debugElem) => debugElem.nativeElement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the exiting categories list
|
||||
*
|
||||
* @returns list of material option element
|
||||
*/
|
||||
function getExistingCategoriesList(): MatListOption[] {
|
||||
return fixture.debugElement.queryAll(By.directive(MatListOption))?.map((debugElem) => debugElem.componentInstance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new category
|
||||
*
|
||||
* @param name name of the category
|
||||
* @param addUsingEnter use Enter key
|
||||
* @param typingTimeout typing timeout in milliseconds (default 300)
|
||||
*/
|
||||
function createCategory(name: string, addUsingEnter?: boolean, typingTimeout = 300): void {
|
||||
typeCategory(name, typingTimeout);
|
||||
|
||||
@@ -92,26 +114,57 @@ describe('CategoriesManagementComponent', () => {
|
||||
fixture.detectChanges();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get first error
|
||||
*
|
||||
* @returns error text
|
||||
*/
|
||||
function getFirstError(): string {
|
||||
return fixture.debugElement.query(By.directive(MatError)).nativeElement.textContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get selection list
|
||||
*
|
||||
* @returns material selection list
|
||||
*/
|
||||
function getSelectionList(): MatSelectionList {
|
||||
return fixture.debugElement.query(By.directive(MatSelectionList)).componentInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get remove category buttons
|
||||
*
|
||||
* @returns list of native elements
|
||||
*/
|
||||
function getRemoveCategoryButtons(): HTMLButtonElement[] {
|
||||
return fixture.debugElement.queryAll(By.css(`[data-automation-id="categories-remove-category-button"]`)).map((debugElem) => debugElem.nativeElement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get category control input
|
||||
*
|
||||
* @returns native input element
|
||||
*/
|
||||
function getCategoryControlInput(): HTMLInputElement {
|
||||
return fixture.debugElement.query(By.css('.adf-category-name-field input'))?.nativeElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get create category label
|
||||
*
|
||||
* @returns native element
|
||||
*/
|
||||
function getCreateCategoryLabel(): HTMLSpanElement {
|
||||
return fixture.debugElement.query(By.css('.adf-existing-categories-panel span'))?.nativeElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Type new category
|
||||
*
|
||||
* @param name name of the category
|
||||
* @param timeout typing timeout in milliseconds (default 300)
|
||||
*/
|
||||
function typeCategory(name: string, timeout = 300): void {
|
||||
component.categoryNameControlVisible = true;
|
||||
fixture.detectChanges();
|
||||
@@ -140,9 +193,9 @@ describe('CategoriesManagementComponent', () => {
|
||||
});
|
||||
|
||||
it('should unassign/remove specific category after clicking at remove icon and emit categories change', () => {
|
||||
const removeBtns = getRemoveCategoryButtons();
|
||||
const removeButtons = getRemoveCategoryButtons();
|
||||
const categoriesChangeSpy = spyOn(component.categoriesChange, 'emit');
|
||||
removeBtns[0].click();
|
||||
removeButtons[0].click();
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
@@ -156,9 +209,9 @@ describe('CategoriesManagementComponent', () => {
|
||||
it('should disable unassigning/removing categories when disableRemoval is set', () => {
|
||||
component.disableRemoval = true;
|
||||
fixture.detectChanges();
|
||||
const removeBtns = getRemoveCategoryButtons();
|
||||
const allBtnsDisabled = removeBtns.every((removeBtn) => removeBtn.disabled);
|
||||
expect(allBtnsDisabled).toBeTrue();
|
||||
const removeButtons = getRemoveCategoryButtons();
|
||||
const allButtonsDisabled = removeButtons.every((removeBtn) => removeBtn.disabled);
|
||||
expect(allButtonsDisabled).toBeTrue();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -208,6 +261,11 @@ describe('CategoriesManagementComponent', () => {
|
||||
});
|
||||
|
||||
describe('Spinner', () => {
|
||||
/**
|
||||
* Get the spinner element
|
||||
*
|
||||
* @returns debug element
|
||||
*/
|
||||
function getSpinner(): DebugElement {
|
||||
return fixture.debugElement.query(By.css(`.mat-progress-spinner`));
|
||||
}
|
||||
@@ -269,8 +327,8 @@ describe('CategoriesManagementComponent', () => {
|
||||
});
|
||||
|
||||
it('should have correct remove category title', () => {
|
||||
const removeBtns = getRemoveCategoryButtons();
|
||||
const isTitleCorrect = removeBtns.every((removeBtn) => removeBtn.attributes.getNamedItem('title').textContent === 'CATEGORIES_MANAGEMENT.UNASSIGN_CATEGORY');
|
||||
const removeButtons = getRemoveCategoryButtons();
|
||||
const isTitleCorrect = removeButtons.every((removeBtn) => removeBtn.attributes.getNamedItem('title').textContent === 'CATEGORIES_MANAGEMENT.UNASSIGN_CATEGORY');
|
||||
expect(isTitleCorrect).toBeTrue();
|
||||
});
|
||||
|
||||
@@ -329,8 +387,8 @@ describe('CategoriesManagementComponent', () => {
|
||||
fixture.detectChanges();
|
||||
|
||||
const categoriesChangeSpy = spyOn(component.categoriesChange, 'emit').and.callThrough();
|
||||
const removeCategoryBtns = getRemoveCategoryButtons();
|
||||
removeCategoryBtns[2].click();
|
||||
const removeCategoryButtons = getRemoveCategoryButtons();
|
||||
removeCategoryButtons[2].click();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.categories.length).toBe(2);
|
||||
@@ -345,8 +403,8 @@ describe('CategoriesManagementComponent', () => {
|
||||
typeCategory('test');
|
||||
expect(component.existingCategories.length).toBe(2);
|
||||
const categoriesChangeSpy = spyOn(component.categoriesChange, 'emit').and.callThrough();
|
||||
const removeCategoryBtns = getRemoveCategoryButtons();
|
||||
removeCategoryBtns[0].click();
|
||||
const removeCategoryButtons = getRemoveCategoryButtons();
|
||||
removeCategoryButtons[0].click();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.categories.length).toBe(1);
|
||||
@@ -375,8 +433,8 @@ describe('CategoriesManagementComponent', () => {
|
||||
});
|
||||
|
||||
it('should have correct remove category title', () => {
|
||||
const removeBtns = getRemoveCategoryButtons();
|
||||
const isTitleCorrect = removeBtns.every((removeBtn) => removeBtn.attributes.getNamedItem('title').textContent === 'CATEGORIES_MANAGEMENT.DELETE_CATEGORY');
|
||||
const removeButtons = getRemoveCategoryButtons();
|
||||
const isTitleCorrect = removeButtons.every((removeBtn) => removeBtn.attributes.getNamedItem('title').textContent === 'CATEGORIES_MANAGEMENT.DELETE_CATEGORY');
|
||||
expect(isTitleCorrect).toBeTrue();
|
||||
});
|
||||
|
||||
@@ -434,8 +492,8 @@ describe('CategoriesManagementComponent', () => {
|
||||
createCategory('test');
|
||||
|
||||
const categoriesChangeSpy = spyOn(component.categoriesChange, 'emit');
|
||||
const removeCategoryBtns = getRemoveCategoryButtons();
|
||||
removeCategoryBtns[2].click();
|
||||
const removeCategoryButtons = getRemoveCategoryButtons();
|
||||
removeCategoryButtons[2].click();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.categories.length).toBe(2);
|
||||
@@ -446,12 +504,16 @@ describe('CategoriesManagementComponent', () => {
|
||||
describe('Errors', () => {
|
||||
it('should display validation error when searching for empty category', fakeAsync(() => {
|
||||
typeCategory(' ');
|
||||
component.categoryNameControl.markAsTouched();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(getFirstError()).toBe('CATEGORIES_MANAGEMENT.ERRORS.EMPTY_CATEGORY');
|
||||
}));
|
||||
|
||||
it('should show error for required', fakeAsync(() => {
|
||||
typeCategory('');
|
||||
component.categoryNameControl.markAsTouched();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(getFirstError()).toBe('CATEGORIES_MANAGEMENT.ERRORS.REQUIRED');
|
||||
}));
|
||||
@@ -476,6 +538,7 @@ describe('CategoriesManagementComponent', () => {
|
||||
it('should show error for required when not typed anything and blur input', fakeAsync(() => {
|
||||
typeCategory('');
|
||||
getCategoryControlInput().blur();
|
||||
component.categoryNameControl.markAsTouched();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(getFirstError()).toBe('CATEGORIES_MANAGEMENT.ERRORS.REQUIRED');
|
||||
|
||||
@@ -64,17 +64,15 @@ export class CategoryTreeDatasourceService extends TreeService<CategoryNode> {
|
||||
.join(pathSeparator);
|
||||
|
||||
return this.categoryService.getCategory(category.entry.id).pipe(
|
||||
map((res) => {
|
||||
return {
|
||||
id: category.entry.id,
|
||||
nodeName: path ? `${path}/${category.entry.name}` : category.entry.name,
|
||||
parentId: category.entry.parentId,
|
||||
level: 0,
|
||||
nodeType: TreeNodeType.RegularNode,
|
||||
hasChildren: res.entry.hasChildren,
|
||||
isLoading: false
|
||||
};
|
||||
})
|
||||
map((res) => ({
|
||||
id: category.entry.id,
|
||||
nodeName: path ? `${path}/${category.entry.name}` : category.entry.name,
|
||||
parentId: category.entry.parentId,
|
||||
level: 0,
|
||||
nodeType: TreeNodeType.RegularNode,
|
||||
hasChildren: res.entry.hasChildren,
|
||||
isLoading: false
|
||||
}))
|
||||
);
|
||||
}),
|
||||
toArray(),
|
||||
|
||||
@@ -52,7 +52,7 @@ export class CategoryService {
|
||||
* @param parentCategoryId The identifier of a parent category.
|
||||
* @param skipCount Number of top categories to skip.
|
||||
* @param maxItems Maximum number of subcategories returned from Observable.
|
||||
* @return Observable<CategoryPaging>
|
||||
* @returns Observable<CategoryPaging>
|
||||
*/
|
||||
getSubcategories(parentCategoryId: string, skipCount?: number, maxItems?: number): Observable<CategoryPaging> {
|
||||
return from(this.categoriesApi.getSubcategories(parentCategoryId ?? '-root-', {skipCount, maxItems}));
|
||||
@@ -67,7 +67,7 @@ export class CategoryService {
|
||||
* @param opts.include Returns additional information about the category. The following optional fields can be requested:
|
||||
* count
|
||||
* path
|
||||
* @return Observable<CategoryEntry>
|
||||
* @returns Observable<CategoryEntry>
|
||||
*/
|
||||
getCategory(categoryId: string, opts?: any): Observable<CategoryEntry> {
|
||||
return from(this.categoriesApi.getCategory(categoryId, opts));
|
||||
@@ -78,7 +78,7 @@ export class CategoryService {
|
||||
*
|
||||
* @param parentCategoryId The identifier of a parent category.
|
||||
* @param payload List of categories to be created.
|
||||
* @return Observable<CategoryPaging | CategoryEntry>
|
||||
* @returns Observable<CategoryPaging | CategoryEntry>
|
||||
*/
|
||||
createSubcategories(parentCategoryId: string, payload: CategoryBody[]): Observable<CategoryPaging | CategoryEntry> {
|
||||
return from(this.categoriesApi.createSubcategories(parentCategoryId, payload, {}));
|
||||
@@ -89,7 +89,7 @@ export class CategoryService {
|
||||
*
|
||||
* @param categoryId The identifier of a category.
|
||||
* @param payload Updated category body
|
||||
* @return Observable<CategoryEntry>
|
||||
* @returns Observable<CategoryEntry>
|
||||
*/
|
||||
updateCategory(categoryId: string, payload: CategoryBody): Observable<CategoryEntry> {
|
||||
return from(this.categoriesApi.updateCategory(categoryId, payload, {}));
|
||||
@@ -99,7 +99,7 @@ export class CategoryService {
|
||||
* Deletes category
|
||||
*
|
||||
* @param categoryId The identifier of a category.
|
||||
* @return Observable<void>
|
||||
* @returns Observable<void>
|
||||
*/
|
||||
deleteCategory(categoryId: string): Observable<void> {
|
||||
return from(this.categoriesApi.deleteCategory(categoryId));
|
||||
@@ -111,7 +111,7 @@ export class CategoryService {
|
||||
* @param name Value for name which should be used during searching categories.
|
||||
* @param skipCount Specify how many first results should be skipped. Default 0.
|
||||
* @param maxItems Specify max number of returned categories. Default is specified by UserPreferencesService.
|
||||
* @return Observable<ResultSetPaging> Found categories which name contains searched name.
|
||||
* @returns Observable<ResultSetPaging> Found categories which name contains searched name.
|
||||
*/
|
||||
searchCategories(name: string, skipCount = 0, maxItems?: number): Observable<ResultSetPaging> {
|
||||
maxItems = maxItems || this.userPreferencesService.paginationSize;
|
||||
@@ -132,7 +132,7 @@ export class CategoryService {
|
||||
* List of categories that node is assigned to
|
||||
*
|
||||
* @param nodeId The identifier of a node.
|
||||
* @return Observable<CategoryPaging> Categories that node is assigned to
|
||||
* @returns Observable<CategoryPaging> Categories that node is assigned to
|
||||
*/
|
||||
getCategoryLinksForNode(nodeId: string): Observable<CategoryPaging> {
|
||||
return from(this.categoriesApi.getCategoryLinksForNode(nodeId, {include: ['path']}));
|
||||
@@ -143,7 +143,7 @@ export class CategoryService {
|
||||
*
|
||||
* @param nodeId The identifier of a node.
|
||||
* @param categoryId The identifier of a category.
|
||||
* @return Observable<void>
|
||||
* @returns Observable<void>
|
||||
*/
|
||||
unlinkNodeFromCategory(nodeId: string, categoryId: string): Observable<void> {
|
||||
return from(this.categoriesApi.unlinkNodeFromCategory(nodeId, categoryId));
|
||||
@@ -154,7 +154,7 @@ export class CategoryService {
|
||||
*
|
||||
* @param nodeId The identifier of a node.
|
||||
* @param categoryLinkBodyCreate Array of a categories that node will be linked to.
|
||||
* @return Observable<CategoryEntry>
|
||||
* @returns Observable<CategoryEntry>
|
||||
*/
|
||||
linkNodeToCategory(nodeId: string, categoryLinkBodyCreate: CategoryLinkBody[]): Observable<CategoryPaging | CategoryEntry> {
|
||||
return from(this.categoriesApi.linkNodeToCategory(nodeId, categoryLinkBodyCreate));
|
||||
|
||||
@@ -171,11 +171,11 @@ export class NodesApiService {
|
||||
/**
|
||||
* Create a new Node from form metadata.
|
||||
*
|
||||
* @param path Path to the node
|
||||
* @param nodeType Node type
|
||||
* @param name Node name
|
||||
* @param nameSpace Namespace for properties
|
||||
* @param data Property data to store in the node under namespace
|
||||
* @param path Path to the node
|
||||
* @param name Node name
|
||||
* @returns The created node
|
||||
*/
|
||||
public createNodeMetadata(nodeType: string, nameSpace: any, data: any, path: string, name?: string): Observable<NodeEntry> {
|
||||
|
||||
@@ -88,9 +88,8 @@ export class RenditionService {
|
||||
}
|
||||
|
||||
private async waitRendition(nodeId: string, renditionId: string, retries: number): Promise<RenditionEntry> {
|
||||
const rendition = await this.renditionsApi.getRendition(nodeId, renditionId);
|
||||
|
||||
if (this.maxRetries < retries) {
|
||||
if (this.maxRetries > retries) {
|
||||
const rendition = await this.renditionsApi.getRendition(nodeId, renditionId);
|
||||
const status = rendition.entry.status.toString();
|
||||
|
||||
if (status === 'CREATED') {
|
||||
@@ -260,6 +259,9 @@ export class RenditionService {
|
||||
* This method takes a url to trigger the print dialog against, and the type of artifact that it
|
||||
* is.
|
||||
* This URL should be one that can be rendered in the browser, for example PDF, Image, or Text
|
||||
*
|
||||
* @param url url to print
|
||||
* @param type type of the rendition
|
||||
*/
|
||||
printFile(url: string, type: string): void {
|
||||
const pwa = window.open(url, RenditionService.TARGET);
|
||||
@@ -285,6 +287,8 @@ export class RenditionService {
|
||||
* These are: images, PDF files, or PDF rendition of files.
|
||||
* We also force PDF rendition for TEXT type objects, otherwise the default URL is to download.
|
||||
* TODO there are different TEXT type objects, (HTML, plaintext, xml, etc. we should determine how these are handled)
|
||||
* @param objectId object it
|
||||
* @param mimeType mime type
|
||||
*/
|
||||
printFileGeneric(objectId: string, mimeType: string): void {
|
||||
const nodeId = objectId;
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { AlfrescoApiService, LogService, TranslationService, ViewUtilService } from '@alfresco/adf-core';
|
||||
import { Rendition, RenditionEntry, RenditionPaging, RenditionsApi } from '@alfresco/js-api';
|
||||
import { RenditionService } from '@alfresco/adf-content-services';
|
||||
|
||||
const getRenditionEntry = (status: Rendition.StatusEnum): RenditionEntry => {
|
||||
return {
|
||||
entry: {
|
||||
id: 'pdf',
|
||||
status: status,
|
||||
content: { mimeType: 'application/pdf', mimeTypeName: 'application/pdf', sizeInBytes: 10 }
|
||||
}
|
||||
};
|
||||
};
|
||||
const getRenditionPaging = (status: Rendition.StatusEnum): RenditionPaging => {
|
||||
return {
|
||||
list: {
|
||||
entries: [getRenditionEntry(status)]
|
||||
}
|
||||
};
|
||||
};
|
||||
describe('RenditionService', () => {
|
||||
let renditionService: RenditionService;
|
||||
let renditionsApi: any;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [
|
||||
RenditionService,
|
||||
{ provide: AlfrescoApiService, useValue: {} },
|
||||
{ provide: LogService, useValue: { error: jasmine.createSpy('error') } },
|
||||
{ provide: TranslationService, useValue: {} },
|
||||
{ provide: ViewUtilService, useValue: {} },
|
||||
{ provide: RenditionsApi, useValue: {
|
||||
listRenditions: jasmine.createSpy('listRenditions'),
|
||||
getRendition: jasmine.createSpy('getRendition'),
|
||||
createRendition: jasmine.createSpy('createRendition')
|
||||
} }
|
||||
]
|
||||
});
|
||||
renditionService = TestBed.inject(RenditionService);
|
||||
renditionsApi = TestBed.inject(RenditionsApi);
|
||||
spyOnProperty(renditionService, 'renditionsApi').and.returnValue(renditionsApi);
|
||||
});
|
||||
|
||||
describe('getRendition', () => {
|
||||
it('should retry getting the rendition until maxRetries if status is NOT_CREATED', async () => {
|
||||
const mockRenditionPaging: RenditionPaging = getRenditionPaging(Rendition.StatusEnum.NOTCREATED);
|
||||
const mockRenditionEntry: RenditionEntry = getRenditionEntry(Rendition.StatusEnum.NOTCREATED);
|
||||
|
||||
renditionsApi.listRenditions.and.returnValue(Promise.resolve(mockRenditionPaging));
|
||||
renditionsApi.getRendition.and.returnValue(Promise.resolve(mockRenditionEntry));
|
||||
|
||||
await renditionService.getRendition('nodeId', 'pdf');
|
||||
expect(renditionsApi.getRendition).toHaveBeenCalledTimes(renditionService.maxRetries);
|
||||
}, 10000);
|
||||
});
|
||||
|
||||
it('should return the rendition when status transitions from PENDING to CREATED', async () => {
|
||||
const mockRenditionPaging: RenditionPaging = getRenditionPaging(Rendition.StatusEnum.NOTCREATED);
|
||||
const mockRenditionEntry: RenditionEntry = getRenditionEntry(Rendition.StatusEnum.CREATED);
|
||||
|
||||
renditionsApi.listRenditions.and.returnValue(Promise.resolve(mockRenditionPaging));
|
||||
renditionsApi.getRendition.and.returnValues(
|
||||
Promise.resolve(getRenditionEntry(Rendition.StatusEnum.NOTCREATED)),
|
||||
Promise.resolve(getRenditionEntry(Rendition.StatusEnum.NOTCREATED)),
|
||||
Promise.resolve(mockRenditionEntry)
|
||||
);
|
||||
|
||||
const result = await renditionService.getRendition('nodeId', 'pdf');
|
||||
|
||||
expect(result).toEqual(mockRenditionEntry);
|
||||
expect(renditionsApi.getRendition).toHaveBeenCalledTimes(3);
|
||||
});
|
||||
|
||||
it('should return the rendition when status is CREATED on the first run', async () => {
|
||||
const mockRenditionPaging: RenditionPaging = getRenditionPaging(Rendition.StatusEnum.CREATED);
|
||||
|
||||
renditionsApi.listRenditions.and.returnValue(Promise.resolve(mockRenditionPaging));
|
||||
|
||||
const result = await renditionService.getRendition('nodeId', 'pdf');
|
||||
|
||||
expect(result).toEqual(mockRenditionPaging.list.entries[0]);
|
||||
expect(renditionsApi.getRendition).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
@@ -158,7 +158,7 @@ export class SitesService {
|
||||
* @param siteId The identifier of a site
|
||||
* @param siteMembershipBodyCreate The person to add and their role
|
||||
* @param opts Optional parameters
|
||||
* @return Observable<SiteMemberEntry>
|
||||
* @returns Observable<SiteMemberEntry>
|
||||
*/
|
||||
createSiteMembership(siteId: string, siteMembershipBodyCreate: SiteMembershipBodyCreate, opts?: any): Observable<SiteMemberEntry> {
|
||||
return from(this.sitesApi.createSiteMembership(siteId, siteMembershipBodyCreate, opts)).pipe(catchError((err: any) => this.handleError(err)));
|
||||
@@ -171,7 +171,7 @@ export class SitesService {
|
||||
* @param personId The identifier of a person.
|
||||
* @param siteMembershipBodyUpdate The persons new role
|
||||
* @param opts Optional parameters
|
||||
* @return Observable<SiteMemberEntry>
|
||||
* @returns Observable<SiteMemberEntry>
|
||||
*/
|
||||
updateSiteMembership(
|
||||
siteId: string,
|
||||
@@ -189,7 +189,7 @@ export class SitesService {
|
||||
*
|
||||
* @param siteId The identifier of a site.
|
||||
* @param personId The identifier of a person.
|
||||
* @return Null response notifying when the operation is complete
|
||||
* @returns Null response notifying when the operation is complete
|
||||
*/
|
||||
deleteSiteMembership(siteId: string, personId: string): Observable<void> {
|
||||
return from(this.sitesApi.deleteSiteMembership(siteId, personId)).pipe(catchError((err: any) => this.handleError(err)));
|
||||
@@ -246,7 +246,7 @@ export class SitesService {
|
||||
*
|
||||
* @param siteId The identifier of a site.
|
||||
* @param groupId The authorityId of a group.
|
||||
* @return Observable<SiteGroupEntry>
|
||||
* @returns Observable<SiteGroupEntry>
|
||||
*/
|
||||
getSiteGroupMembership(siteId: string, groupId: string): Observable<SiteGroupEntry> {
|
||||
return from(this.sitesApi.getSiteGroupMembership(siteId, groupId)).pipe(catchError((err: any) => this.handleError(err)));
|
||||
@@ -258,7 +258,7 @@ export class SitesService {
|
||||
* @param siteId The identifier of a site.
|
||||
* @param groupId The authorityId of a group.
|
||||
* @param siteMembershipBodyUpdate The group new role
|
||||
* @return Observable<SiteGroupEntry>
|
||||
* @returns Observable<SiteGroupEntry>
|
||||
*/
|
||||
updateSiteGroupMembership(siteId: string, groupId: string, siteMembershipBodyUpdate: SiteMembershipBodyUpdate): Observable<SiteGroupEntry> {
|
||||
return from(this.sitesApi.updateSiteGroupMembership(siteId, groupId, siteMembershipBodyUpdate)).pipe(
|
||||
@@ -271,7 +271,7 @@ export class SitesService {
|
||||
*
|
||||
* @param siteId The identifier of a site.
|
||||
* @param groupId The authorityId of a group.
|
||||
* @return Observable<void>
|
||||
* @returns Observable<void>
|
||||
*/
|
||||
deleteSiteGroupMembership(siteId: string, groupId: string): Observable<void> {
|
||||
return from(this.sitesApi.deleteSiteGroupMembership(siteId, groupId)).pipe(catchError((err: any) => this.handleError(err)));
|
||||
|
||||
+21
-18
@@ -35,56 +35,59 @@ export class ContentMetadataCardComponent implements OnChanges {
|
||||
@Input()
|
||||
node: Node;
|
||||
|
||||
/** (optional) This flag displays/hides empty metadata
|
||||
/**
|
||||
* This flag displays/hides empty metadata
|
||||
* fields.
|
||||
*/
|
||||
@Input()
|
||||
displayEmpty: boolean = false;
|
||||
displayEmpty?: boolean = false;
|
||||
|
||||
/** (optional) This flag displays desired aspect when open for the first time
|
||||
* fields.
|
||||
/**
|
||||
* This flag displays desired aspect when open for the first time fields.
|
||||
*/
|
||||
@Input()
|
||||
displayAspect: string = null;
|
||||
displayAspect?: string = null;
|
||||
|
||||
/** Display tags in the card **/
|
||||
/** Display tags in the card */
|
||||
@Input()
|
||||
displayTags = true;
|
||||
|
||||
/** Display categories in the card **/
|
||||
/** Display categories in the card */
|
||||
@Input()
|
||||
displayCategories = true;
|
||||
|
||||
/** (required) Name or configuration of the metadata preset, which defines aspects
|
||||
/**
|
||||
* Name or configuration of the metadata preset, which defines aspects
|
||||
* and their properties.
|
||||
*/
|
||||
@Input()
|
||||
preset: string | PresetConfig;
|
||||
|
||||
/** (optional) This flag sets the metadata in read only mode
|
||||
* preventing changes.
|
||||
/**
|
||||
* This flag sets the metadata in read only mode preventing changes.
|
||||
*/
|
||||
@Input()
|
||||
readOnly = false;
|
||||
readOnly? = false;
|
||||
|
||||
/** (optional) This flag allows the component to display more
|
||||
/**
|
||||
* This flag allows the component to display more
|
||||
* than one accordion at a time.
|
||||
*/
|
||||
@Input()
|
||||
multi = false;
|
||||
multi? = false;
|
||||
|
||||
/** (optional) This flag toggles editable of content. **/
|
||||
/** This flag toggles editable of content. */
|
||||
@Input()
|
||||
editable = false;
|
||||
editable? = false;
|
||||
|
||||
/** Emitted when content's editable state is changed. **/
|
||||
/** Emitted when content's editable state is changed. */
|
||||
@Output()
|
||||
editableChange = new EventEmitter<boolean>();
|
||||
|
||||
private _displayDefaultProperties: boolean = true;
|
||||
|
||||
/** (optional) This flag displays/hides the metadata
|
||||
* properties.
|
||||
/**
|
||||
* This flag displays/hides the metadata properties.
|
||||
*/
|
||||
@Input()
|
||||
set displayDefaultProperties(value: boolean) {
|
||||
|
||||
+42
-22
@@ -92,18 +92,38 @@ describe('ContentMetadataComponent', () => {
|
||||
const findShowingTagInputButton = (): HTMLButtonElement =>
|
||||
fixture.debugElement.query(By.css('[data-automation-id=showing-tag-input-button]')).nativeElement;
|
||||
|
||||
/**
|
||||
* Get metadata categories
|
||||
*
|
||||
* @returns list of native elements
|
||||
*/
|
||||
function getCategories(): HTMLParagraphElement[] {
|
||||
return fixture.debugElement.queryAll(By.css('.adf-metadata-categories'))?.map((debugElem) => debugElem.nativeElement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a categories management component
|
||||
*
|
||||
* @returns angular component
|
||||
*/
|
||||
function getCategoriesManagementComponent(): CategoriesManagementComponent {
|
||||
return fixture.debugElement.query(By.directive(CategoriesManagementComponent))?.componentInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get categories title button
|
||||
*
|
||||
* @returns native element
|
||||
*/
|
||||
function getAssignCategoriesBtn(): HTMLButtonElement {
|
||||
return fixture.debugElement.query(By.css('.adf-metadata-categories-title button')).nativeElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update aspect property
|
||||
*
|
||||
* @param newValue value to set
|
||||
*/
|
||||
async function updateAspectProperty(newValue: string): Promise<void> {
|
||||
component.editable = true;
|
||||
const property = { key: 'properties.property-key', value: 'original-value' } as CardViewBaseItemModel;
|
||||
@@ -610,7 +630,7 @@ describe('ContentMetadataComponent', () => {
|
||||
let classesApi: ClassesApi;
|
||||
let expectedNode: Node;
|
||||
|
||||
const versionableResponse: PropertyGroup = {
|
||||
const verResponse: PropertyGroup = {
|
||||
name: 'cm:versionable',
|
||||
title: 'Versionable',
|
||||
properties: {
|
||||
@@ -705,7 +725,7 @@ describe('ContentMetadataComponent', () => {
|
||||
'cm:versionable': '*'
|
||||
});
|
||||
|
||||
spyOn(classesApi, 'getClass').and.returnValue(Promise.resolve(versionableResponse));
|
||||
spyOn(classesApi, 'getClass').and.returnValue(Promise.resolve(verResponse));
|
||||
|
||||
component.ngOnChanges({ node: new SimpleChange(node, expectedNode, false) });
|
||||
fixture.detectChanges();
|
||||
@@ -713,9 +733,9 @@ describe('ContentMetadataComponent', () => {
|
||||
await component.groupedProperties$.toPromise();
|
||||
fixture.detectChanges();
|
||||
|
||||
const versionableProp = queryDom(fixture, 'Versionable');
|
||||
const verProp = queryDom(fixture, 'Versionable');
|
||||
|
||||
expect(versionableProp).toBeTruthy();
|
||||
expect(verProp).toBeTruthy();
|
||||
expect(classesApi.getClass).toHaveBeenCalledWith('cm_versionable');
|
||||
});
|
||||
|
||||
@@ -725,7 +745,7 @@ describe('ContentMetadataComponent', () => {
|
||||
'cm:versionable': '*'
|
||||
});
|
||||
|
||||
spyOn(classesApi, 'getClass').and.returnValue(Promise.resolve(versionableResponse));
|
||||
spyOn(classesApi, 'getClass').and.returnValue(Promise.resolve(verResponse));
|
||||
|
||||
component.ngOnChanges({ node: new SimpleChange(node, expectedNode, false) });
|
||||
fixture.detectChanges();
|
||||
@@ -733,9 +753,9 @@ describe('ContentMetadataComponent', () => {
|
||||
await component.groupedProperties$.toPromise();
|
||||
fixture.detectChanges();
|
||||
|
||||
const versionableProps = fixture.debugElement.queryAll(By.css('[data-automation-id="adf-metadata-group-Versionable"]'));
|
||||
const verProps = fixture.debugElement.queryAll(By.css('[data-automation-id="adf-metadata-group-Versionable"]'));
|
||||
|
||||
expect(versionableProps.length).toEqual(2);
|
||||
expect(verProps.length).toEqual(2);
|
||||
expect(classesApi.getClass).toHaveBeenCalledWith('cm_versionable');
|
||||
});
|
||||
|
||||
@@ -745,7 +765,7 @@ describe('ContentMetadataComponent', () => {
|
||||
exclude: 'cm:versionable'
|
||||
});
|
||||
|
||||
spyOn(classesApi, 'getClass').and.returnValue(Promise.resolve(versionableResponse));
|
||||
spyOn(classesApi, 'getClass').and.returnValue(Promise.resolve(verResponse));
|
||||
|
||||
component.ngOnChanges({ node: new SimpleChange(node, expectedNode, false) });
|
||||
fixture.detectChanges();
|
||||
@@ -753,9 +773,9 @@ describe('ContentMetadataComponent', () => {
|
||||
await component.groupedProperties$.toPromise();
|
||||
fixture.detectChanges();
|
||||
|
||||
const versionableProp = queryDom(fixture, 'Versionable');
|
||||
const verProp = queryDom(fixture, 'Versionable');
|
||||
|
||||
expect(versionableProp).toBeNull();
|
||||
expect(verProp).toBeNull();
|
||||
expect(classesApi.getClass).toHaveBeenCalledWith('cm_versionable');
|
||||
});
|
||||
|
||||
@@ -766,7 +786,7 @@ describe('ContentMetadataComponent', () => {
|
||||
'cm:versionable': '*'
|
||||
});
|
||||
|
||||
spyOn(classesApi, 'getClass').and.returnValue(Promise.resolve(versionableResponse));
|
||||
spyOn(classesApi, 'getClass').and.returnValue(Promise.resolve(verResponse));
|
||||
|
||||
component.ngOnChanges({ node: new SimpleChange(node, expectedNode, false) });
|
||||
fixture.detectChanges();
|
||||
@@ -774,9 +794,9 @@ describe('ContentMetadataComponent', () => {
|
||||
await component.groupedProperties$.toPromise();
|
||||
fixture.detectChanges();
|
||||
|
||||
const versionableProp = queryDom(fixture, 'Versionable');
|
||||
const verProp = queryDom(fixture, 'Versionable');
|
||||
|
||||
expect(versionableProp).toBeTruthy();
|
||||
expect(verProp).toBeTruthy();
|
||||
expect(classesApi.getClass).toHaveBeenCalledWith('cm_versionable');
|
||||
});
|
||||
|
||||
@@ -786,7 +806,7 @@ describe('ContentMetadataComponent', () => {
|
||||
exclude: ['cm:versionable', 'cm:auditable']
|
||||
});
|
||||
|
||||
spyOn(classesApi, 'getClass').and.returnValue(Promise.resolve(versionableResponse));
|
||||
spyOn(classesApi, 'getClass').and.returnValue(Promise.resolve(verResponse));
|
||||
|
||||
component.ngOnChanges({ node: new SimpleChange(node, expectedNode, false) });
|
||||
fixture.detectChanges();
|
||||
@@ -794,8 +814,8 @@ describe('ContentMetadataComponent', () => {
|
||||
await component.groupedProperties$.toPromise();
|
||||
fixture.detectChanges();
|
||||
|
||||
const versionableProp = queryDom(fixture, 'Versionable');
|
||||
expect(versionableProp).toBeNull();
|
||||
const verProp = queryDom(fixture, 'Versionable');
|
||||
expect(verProp).toBeNull();
|
||||
|
||||
const auditableProp = queryDom(fixture, 'Auditable');
|
||||
expect(auditableProp).toBeNull();
|
||||
@@ -825,17 +845,17 @@ describe('ContentMetadataComponent', () => {
|
||||
|
||||
exifProp.nativeElement.click();
|
||||
|
||||
const pixelXDimentionElement = fixture.debugElement.query(
|
||||
const pixelXDimensionElement = fixture.debugElement.query(
|
||||
By.css('[data-automation-id="card-textitem-label-properties.exif:pixelXDimension"]')
|
||||
);
|
||||
expect(pixelXDimentionElement).toBeTruthy();
|
||||
expect(pixelXDimentionElement.nativeElement.textContent.trim()).toEqual('Image Width');
|
||||
expect(pixelXDimensionElement).toBeTruthy();
|
||||
expect(pixelXDimensionElement.nativeElement.textContent.trim()).toEqual('Image Width');
|
||||
|
||||
const pixelYDimentionElement = fixture.debugElement.query(
|
||||
const pixelYDimensionElement = fixture.debugElement.query(
|
||||
By.css('[data-automation-id="card-textitem-label-properties.exif:pixelYDimension"]')
|
||||
);
|
||||
expect(pixelYDimentionElement).toBeTruthy();
|
||||
expect(pixelYDimentionElement.nativeElement.textContent.trim()).toEqual('Image Height');
|
||||
expect(pixelYDimensionElement).toBeTruthy();
|
||||
expect(pixelYDimensionElement.nativeElement.textContent.trim()).toEqual('Image Height');
|
||||
});
|
||||
|
||||
it('should show Exif twice when includeAll is set to true', async () => {
|
||||
|
||||
+5
-4
@@ -76,7 +76,8 @@ export class ContentMetadataComponent implements OnChanges, OnInit, OnDestroy {
|
||||
@Input()
|
||||
displayEmpty: boolean = false;
|
||||
|
||||
/** Toggles between expanded (ie, full information) and collapsed
|
||||
/**
|
||||
* Toggles between expanded (ie, full information) and collapsed
|
||||
* (ie, reduced information) in the display
|
||||
*/
|
||||
@Input()
|
||||
@@ -115,7 +116,7 @@ export class ContentMetadataComponent implements OnChanges, OnInit, OnDestroy {
|
||||
displayCategories = false;
|
||||
|
||||
private _assignedTags: string[] = [];
|
||||
private assignedTagsEntries: TagEntry[];
|
||||
private assignedTagsEntries: TagEntry[] = [];
|
||||
private _editable = false;
|
||||
private _tagsCreatorMode = TagsCreatorMode.CREATE_AND_ASSIGN;
|
||||
private _tags: string[] = [];
|
||||
@@ -317,7 +318,7 @@ export class ContentMetadataComponent implements OnChanges, OnInit, OnDestroy {
|
||||
this._saving = false;
|
||||
return of(null);
|
||||
}))
|
||||
.subscribe((result) => {
|
||||
.subscribe((result: any) => {
|
||||
if (result) {
|
||||
this.updateUndefinedNodeProperties(result.updatedNode);
|
||||
if (this.hasContentTypeChanged(this.changedProperties)) {
|
||||
@@ -330,7 +331,7 @@ export class ContentMetadataComponent implements OnChanges, OnInit, OnDestroy {
|
||||
this.loadTagsForNode(this.node.id);
|
||||
}
|
||||
if (this.displayCategories && !!result.LinkingCategories) {
|
||||
this.assignedCategories = !!result.LinkingCategories.list ?
|
||||
this.assignedCategories = result.LinkingCategories.list ?
|
||||
result.LinkingCategories.list.entries.map((entry: CategoryEntry) => entry.entry) :
|
||||
[result.LinkingCategories.entry];
|
||||
}
|
||||
|
||||
+6
-6
@@ -110,7 +110,7 @@ describe('ContentMetaDataService', () => {
|
||||
}
|
||||
};
|
||||
|
||||
const versionableResponse: PropertyGroup = {
|
||||
const verResponse: PropertyGroup = {
|
||||
name: 'cm:versionable',
|
||||
title: 'Versionable',
|
||||
properties: {
|
||||
@@ -232,7 +232,7 @@ describe('ContentMetaDataService', () => {
|
||||
'cm:versionable': '*'
|
||||
});
|
||||
|
||||
spyOn(classesApi, 'getClass').and.returnValue(Promise.resolve(versionableResponse));
|
||||
spyOn(classesApi, 'getClass').and.returnValue(Promise.resolve(verResponse));
|
||||
|
||||
const groupedProperties = await service.getGroupedProperties(fakeContentNode).toPromise();
|
||||
|
||||
@@ -249,7 +249,7 @@ describe('ContentMetaDataService', () => {
|
||||
'cm:versionable': '*'
|
||||
});
|
||||
|
||||
spyOn(classesApi, 'getClass').and.returnValue(Promise.resolve(versionableResponse));
|
||||
spyOn(classesApi, 'getClass').and.returnValue(Promise.resolve(verResponse));
|
||||
|
||||
const groupedProperties = await service.getGroupedProperties(fakeContentNode).toPromise();
|
||||
|
||||
@@ -267,7 +267,7 @@ describe('ContentMetaDataService', () => {
|
||||
exclude: 'cm:versionable'
|
||||
});
|
||||
|
||||
spyOn(classesApi, 'getClass').and.returnValue(Promise.resolve(versionableResponse));
|
||||
spyOn(classesApi, 'getClass').and.returnValue(Promise.resolve(verResponse));
|
||||
|
||||
const groupedProperties = await service.getGroupedProperties(fakeContentNode).toPromise();
|
||||
expect(groupedProperties.length).toEqual(0);
|
||||
@@ -283,7 +283,7 @@ describe('ContentMetaDataService', () => {
|
||||
'cm:versionable': '*'
|
||||
});
|
||||
|
||||
spyOn(classesApi, 'getClass').and.returnValue(Promise.resolve(versionableResponse));
|
||||
spyOn(classesApi, 'getClass').and.returnValue(Promise.resolve(verResponse));
|
||||
|
||||
const groupedProperties = await service.getGroupedProperties(fakeContentNode).toPromise();
|
||||
expect(groupedProperties.length).toEqual(1);
|
||||
@@ -299,7 +299,7 @@ describe('ContentMetaDataService', () => {
|
||||
exclude: ['cm:versionable', 'cm:auditable']
|
||||
});
|
||||
|
||||
spyOn(classesApi, 'getClass').and.returnValue(Promise.resolve(versionableResponse));
|
||||
spyOn(classesApi, 'getClass').and.returnValue(Promise.resolve(verResponse));
|
||||
|
||||
const groupedProperties = await service.getGroupedProperties(fakeContentNode).toPromise();
|
||||
expect(groupedProperties.length).toEqual(0);
|
||||
|
||||
+1
-1
@@ -80,7 +80,7 @@ describe('PropertyDescriptorLoaderService', () => {
|
||||
expect(data['exif:exif']).toBe(exifResponse);
|
||||
expect(data['cm:content']).toBe(contentResponse);
|
||||
},
|
||||
complete: done
|
||||
complete: () => done()
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+27
-9
@@ -81,14 +81,16 @@ export class ContentNodeSelectorPanelComponent implements OnInit, OnDestroy {
|
||||
@Input()
|
||||
currentFolderId: string = null;
|
||||
|
||||
/** Hide the "My Files" option added to the site list by default.
|
||||
/**
|
||||
* Hide the "My Files" option added to the site list by default.
|
||||
* See the [Sites Dropdown component](sites-dropdown.component.md)
|
||||
* for more information.
|
||||
*/
|
||||
@Input()
|
||||
dropdownHideMyFiles: boolean = false;
|
||||
|
||||
/** Custom site for site dropdown. This is the same as the `siteList`.
|
||||
/**
|
||||
* Custom site for site dropdown. This is the same as the `siteList`.
|
||||
* property of the Sites Dropdown component (see its doc page
|
||||
* for more information).
|
||||
*/
|
||||
@@ -97,7 +99,8 @@ export class ContentNodeSelectorPanelComponent implements OnInit, OnDestroy {
|
||||
|
||||
_rowFilter: RowFilter = defaultValidation;
|
||||
|
||||
/** Custom *where* filter function. See the
|
||||
/**
|
||||
* Custom *where* filter function. See the
|
||||
* Document List component
|
||||
* for more information.
|
||||
*/
|
||||
@@ -120,7 +123,8 @@ export class ContentNodeSelectorPanelComponent implements OnInit, OnDestroy {
|
||||
|
||||
_excludeSiteContent: string[] = [];
|
||||
|
||||
/** Custom list of site content componentIds.
|
||||
/**
|
||||
* Custom list of site content componentIds.
|
||||
* Used to filter out the corresponding items from the displayed nodes
|
||||
*/
|
||||
@Input()
|
||||
@@ -149,13 +153,15 @@ export class ContentNodeSelectorPanelComponent implements OnInit, OnDestroy {
|
||||
@Input()
|
||||
selectionMode: 'single' | 'multiple' = 'single';
|
||||
|
||||
/** Function used to decide if the selected node has permission to be selected.
|
||||
/**
|
||||
* Function used to decide if the selected node has permission to be selected.
|
||||
* Default value is a function that always returns true.
|
||||
*/
|
||||
@Input()
|
||||
isSelectionValid: ValidationFunction = defaultValidation;
|
||||
|
||||
/** Transformation to be performed on the chosen/folder node before building the
|
||||
/**
|
||||
* Transformation to be performed on the chosen/folder node before building the
|
||||
* breadcrumb UI. Can be useful when custom formatting is needed for the breadcrumb.
|
||||
* You can change the path elements from the node that are used to build the
|
||||
* breadcrumb using this function.
|
||||
@@ -427,7 +433,9 @@ export class ContentNodeSelectorPanelComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the actually selected|entered folder node or null in case of searching for the breadcrumb
|
||||
* Get current breadcrumb folder node
|
||||
*
|
||||
* @returns the actually selected|entered folder node or null in case of searching for the breadcrumb
|
||||
*/
|
||||
get breadcrumbFolderNode(): Node | null {
|
||||
let folderNode: Node;
|
||||
@@ -443,6 +451,8 @@ export class ContentNodeSelectorPanelComponent implements OnInit, OnDestroy {
|
||||
|
||||
/**
|
||||
* Prepares the dialog for a new search
|
||||
*
|
||||
* @param searchRequest request options
|
||||
*/
|
||||
prepareDialogForNewSearch(searchRequest: SearchRequest): void {
|
||||
this.target = searchRequest ? null : this.documentList;
|
||||
@@ -527,6 +537,8 @@ export class ContentNodeSelectorPanelComponent implements OnInit, OnDestroy {
|
||||
|
||||
/**
|
||||
* Sets showingSearchResults state to be able to differentiate between search results or folder results
|
||||
*
|
||||
* @param $event node event
|
||||
*/
|
||||
onFolderChange($event: NodeEntryEvent): void {
|
||||
this.folderIdToShow = $event.value.id;
|
||||
@@ -540,6 +552,8 @@ export class ContentNodeSelectorPanelComponent implements OnInit, OnDestroy {
|
||||
|
||||
/**
|
||||
* Attempts to set the currently loaded node
|
||||
*
|
||||
* @param nodePaging pagination model
|
||||
*/
|
||||
onFolderLoaded(nodePaging: NodePaging): void {
|
||||
setTimeout(() => {
|
||||
@@ -554,6 +568,8 @@ export class ContentNodeSelectorPanelComponent implements OnInit, OnDestroy {
|
||||
|
||||
/**
|
||||
* Updates pagination.hasMoreItems to false after filtering only folders during 'COPY' and 'MOVE' action
|
||||
*
|
||||
* @param nodePaging pagination model
|
||||
*/
|
||||
updatePaginationAfterRowFilter(nodePaging: NodePaging): void {
|
||||
if (this.documentList.data.getRows().length < nodePaging.list.pagination.maxItems) {
|
||||
@@ -563,6 +579,8 @@ export class ContentNodeSelectorPanelComponent implements OnInit, OnDestroy {
|
||||
|
||||
/**
|
||||
* Returns whether breadcrumb has to be shown or not
|
||||
*
|
||||
* @returns `true` if needs to show the breadcrumb, otherwise `false`
|
||||
*/
|
||||
showBreadcrumbs() {
|
||||
return !this.showingSearchResults || this.chosenNode;
|
||||
@@ -586,7 +604,7 @@ export class ContentNodeSelectorPanelComponent implements OnInit, OnDestroy {
|
||||
/**
|
||||
* Selects node as chosen if it has the right permission, clears the selection otherwise
|
||||
*
|
||||
* @param entry
|
||||
* @param entry node entry
|
||||
*/
|
||||
private attemptNodeSelection(entry: Node): void {
|
||||
if (entry && this.isSelectionValid(entry)) {
|
||||
@@ -604,7 +622,7 @@ export class ContentNodeSelectorPanelComponent implements OnInit, OnDestroy {
|
||||
/**
|
||||
* It filters and emit the selection coming from the document list
|
||||
*
|
||||
* @param nodesEntries
|
||||
* @param nodesEntries selected nodes
|
||||
*/
|
||||
onCurrentSelection(nodesEntries: NodeEntry[]): void {
|
||||
const validNodesEntity = nodesEntries.filter((node) => this.isSelectionValid(node.entry));
|
||||
|
||||
+1
-1
@@ -296,7 +296,7 @@ describe('ContentNodeSelectorComponent', () => {
|
||||
const adfUploadButton = fixture.debugElement.query(By.css('adf-upload-button'));
|
||||
|
||||
expect(adfUploadButton).not.toBeNull();
|
||||
expect(adfUploadButton.nativeElement.innerText).toEqual('file_uploadFORM.FIELD.UPLOAD');
|
||||
expect(adfUploadButton.nativeElement.textContent).toEqual('file_uploadFORM.FIELD.UPLOAD');
|
||||
});
|
||||
|
||||
it('should be able to disable UploadButton if showingSearch set to true', () => {
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
[style.display]="isExpiryDateToggleChecked ? 'block' : 'none'"
|
||||
data-automation-id="adf-slide-toggle-checked"
|
||||
class="adf-share-link__date-time-container">
|
||||
<mat-form-field class="adf-full-width adf-float-label" floatLabel='never'>
|
||||
<mat-form-field class="adf-full-width adf-float-label">
|
||||
<mat-label>{{ 'SHARE.EXPIRATION-PLACEHOLDER' | translate }}</mat-label>
|
||||
<mat-datepicker-toggle
|
||||
[disabled]="time.disabled"
|
||||
@@ -51,7 +51,12 @@
|
||||
[attr.aria-label]="'SHARE.EXPIRATION-LABEL' | translate"
|
||||
[min]="minDate"
|
||||
formControlName="time"
|
||||
[matDatepicker]="datePicker" />
|
||||
(keydown)="preventIncorrectCharacters($event)"
|
||||
(blur)="onTimeChanged()"
|
||||
(keydown.enter)="datePickerInput.blur()"
|
||||
[matDatepicker]="datePicker"/>
|
||||
<mat-error *ngIf="time.errors?.['invalidDate'] && (time.dirty || time.touched)"
|
||||
data-automation-id="adf-share-link-input-warning">{{ 'SHARE.INVALID_DATE_ERROR' | translate }}</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<p class="adf-share-link__info adf-share-link__para">{{ 'SHARE.SHARE-LINK' | translate }}</p>
|
||||
@@ -69,7 +74,6 @@
|
||||
</div>
|
||||
<mat-form-field
|
||||
class="adf-full-width adf-float-label"
|
||||
floatLabel='never'
|
||||
[ngClass]="isLinkWithExpiryDate? 'adf-share-link__border-color' : ''">
|
||||
<input
|
||||
#sharedLinkInput
|
||||
|
||||
@@ -21,12 +21,12 @@ import { of } from 'rxjs';
|
||||
import { NotificationService, AppConfigService } from '@alfresco/adf-core';
|
||||
import { NodesApiService } from '../common/services/nodes-api.service';
|
||||
import { RenditionService } from '../common/services/rendition.service';
|
||||
|
||||
import { SharedLinksApiService } from './services/shared-links-api.service';
|
||||
import { ShareDialogComponent } from './content-node-share.dialog';
|
||||
import { ContentTestingModule } from '../testing/content.testing.module';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { format, endOfDay } from 'date-fns';
|
||||
import { By } from '@angular/platform-browser';
|
||||
|
||||
describe('ShareDialogComponent', () => {
|
||||
let node;
|
||||
@@ -45,6 +45,17 @@ describe('ShareDialogComponent', () => {
|
||||
|
||||
const getShareToggleLinkedClasses = (): DOMTokenList => fixture.nativeElement.querySelector(shareToggleId).classList;
|
||||
|
||||
const fillInDatepickerInput = (value: string) => {
|
||||
const input = fixture.debugElement.query(By.css('.adf-share-link__input')).nativeElement;
|
||||
input.value = value;
|
||||
input.dispatchEvent(new Event('input'));
|
||||
input.dispatchEvent(new Event('blur'));
|
||||
fixture.detectChanges();
|
||||
};
|
||||
|
||||
const clickExpireToggleButton = () => fixture.nativeElement.querySelector('mat-slide-toggle[data-automation-id="adf-expire-toggle"] label')
|
||||
.dispatchEvent(new MouseEvent('click'));
|
||||
|
||||
const clickShareToggleButton = () => fixture.nativeElement.querySelector(`${shareToggleId} label`)
|
||||
.dispatchEvent(new MouseEvent('click'));
|
||||
|
||||
@@ -250,17 +261,10 @@ describe('ShareDialogComponent', () => {
|
||||
};
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
component.form.controls['time'].setValue(new Date());
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
fixture.nativeElement
|
||||
.querySelector('.mat-slide-toggle[data-automation-id="adf-expire-toggle"] label')
|
||||
.dispatchEvent(new MouseEvent('click'));
|
||||
|
||||
clickExpireToggleButton();
|
||||
fixture.detectChanges();
|
||||
|
||||
await fixture.whenStable();
|
||||
|
||||
expect(sharedLinksApiService.deleteSharedLink).toHaveBeenCalled();
|
||||
@@ -304,10 +308,10 @@ describe('ShareDialogComponent', () => {
|
||||
spyOn(appConfigService, 'get').and.callFake(() => dateTimePickerType as any);
|
||||
|
||||
fixture.detectChanges();
|
||||
fixture.nativeElement.querySelector('mat-slide-toggle[data-automation-id="adf-expire-toggle"] label')
|
||||
.dispatchEvent(new MouseEvent('click'));
|
||||
clickExpireToggleButton();
|
||||
|
||||
fixture.componentInstance.time.setValue(date);
|
||||
component.onTimeChanged();
|
||||
fixture.detectChanges();
|
||||
tick(500);
|
||||
|
||||
@@ -326,11 +330,11 @@ describe('ShareDialogComponent', () => {
|
||||
spyOn(appConfigService, 'get').and.returnValue(dateTimePickerType);
|
||||
|
||||
fixture.detectChanges();
|
||||
fixture.nativeElement.querySelector('mat-slide-toggle[data-automation-id="adf-expire-toggle"] label')
|
||||
.dispatchEvent(new MouseEvent('click'));
|
||||
clickExpireToggleButton();
|
||||
|
||||
fixture.componentInstance.type = 'datetime';
|
||||
fixture.componentInstance.time.setValue(date);
|
||||
component.onTimeChanged();
|
||||
fixture.detectChanges();
|
||||
tick(100);
|
||||
|
||||
@@ -342,5 +346,44 @@ describe('ShareDialogComponent', () => {
|
||||
expiresAt: expiryDate
|
||||
});
|
||||
}));
|
||||
|
||||
it('should not update node when provided date is less than minDate', () => {
|
||||
fixture.detectChanges();
|
||||
clickExpireToggleButton();
|
||||
fillInDatepickerInput('01.01.2010');
|
||||
|
||||
expect(component.form.invalid).toBeTrue();
|
||||
expect(sharedLinksApiService.deleteSharedLink).not.toHaveBeenCalled();
|
||||
expect(sharedLinksApiService.createSharedLinks).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not accept alphabets in the datepicker input', () => {
|
||||
fixture.detectChanges();
|
||||
clickExpireToggleButton();
|
||||
fillInDatepickerInput('test');
|
||||
|
||||
expect(component.form.invalid).toBeTrue();
|
||||
expect(component.form.controls['time'].value).toBeNull();
|
||||
});
|
||||
|
||||
it('should show an error if provided date is invalid', () => {
|
||||
fixture.detectChanges();
|
||||
clickExpireToggleButton();
|
||||
fillInDatepickerInput('32');
|
||||
const error = fixture.debugElement.query(By.css('[data-automation-id="adf-share-link-input-warning"]'));
|
||||
|
||||
expect(error).toBeTruthy();
|
||||
expect(component.time.hasError('invalidDate')).toBeTrue();
|
||||
});
|
||||
|
||||
it('should not show an error when provided date is valid', () => {
|
||||
fixture.detectChanges();
|
||||
clickExpireToggleButton();
|
||||
fillInDatepickerInput('12.12.2525');
|
||||
const error = fixture.debugElement.query(By.css('[data-automation-id="adf-share-link-input-warning"]'));
|
||||
|
||||
expect(error).toBeNull();
|
||||
expect(component.time.hasError('invalidDate')).toBeFalse();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -18,17 +18,15 @@
|
||||
import { Component, Inject, OnInit, ViewEncapsulation, ViewChild, OnDestroy } from '@angular/core';
|
||||
import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog';
|
||||
import { MatSlideToggleChange } from '@angular/material/slide-toggle';
|
||||
import { UntypedFormGroup, UntypedFormControl, AbstractControl } from '@angular/forms';
|
||||
import { AbstractControl, FormControl, FormGroup, Validators } from '@angular/forms';
|
||||
import { Subject } from 'rxjs';
|
||||
import { ContentService } from '../common/services/content.service';
|
||||
|
||||
import { SharedLinksApiService } from './services/shared-links-api.service';
|
||||
import { SharedLinkBodyCreate, SharedLinkEntry } from '@alfresco/js-api';
|
||||
import { ConfirmDialogComponent } from '../dialogs/confirm.dialog';
|
||||
import { ContentNodeShareSettings } from './content-node-share.settings';
|
||||
import { takeUntil, debounceTime } from 'rxjs/operators';
|
||||
import { RenditionService } from '../common/services/rendition.service';
|
||||
import { format, add, endOfDay } from 'date-fns';
|
||||
import { format, add, endOfDay, isBefore } from 'date-fns';
|
||||
|
||||
type DatePickerType = 'date' | 'time' | 'month' | 'datetime';
|
||||
|
||||
@@ -40,6 +38,9 @@ type DatePickerType = 'date' | 'time' | 'month' | 'datetime';
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class ShareDialogComponent implements OnInit, OnDestroy {
|
||||
private minDateValidator = (control: AbstractControl): any =>
|
||||
isBefore(endOfDay(new Date(control.value)), this.minDate) ? { invalidDate: true } : null;
|
||||
|
||||
minDate = add(new Date(), { days: 1 });
|
||||
sharedId: string;
|
||||
fileName: string;
|
||||
@@ -47,9 +48,9 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
||||
isFileShared = false;
|
||||
isDisabled = false;
|
||||
isLinkWithExpiryDate = false;
|
||||
form: UntypedFormGroup = new UntypedFormGroup({
|
||||
sharedUrl: new UntypedFormControl(''),
|
||||
time: new UntypedFormControl({ value: '', disabled: true })
|
||||
form: FormGroup = new FormGroup({
|
||||
sharedUrl: new FormControl(''),
|
||||
time: new FormControl({ value: '', disabled: true }, [Validators.required, this.minDateValidator])
|
||||
});
|
||||
type: DatePickerType = 'date';
|
||||
maxDebounceTime = 500;
|
||||
@@ -90,12 +91,12 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
||||
this.isLinkWithExpiryDate ? this.time.enable() : this.time.disable();
|
||||
}
|
||||
}
|
||||
|
||||
this.time.valueChanges.pipe(debounceTime(this.maxDebounceTime), takeUntil(this.onDestroy$)).subscribe((value) => this.onTimeChanged(value));
|
||||
}
|
||||
|
||||
onTimeChanged(date: Date) {
|
||||
this.updateNode(date);
|
||||
onTimeChanged() {
|
||||
if (this.time.valid) {
|
||||
this.updateNode(this.time.value);
|
||||
}
|
||||
}
|
||||
|
||||
get time(): AbstractControl {
|
||||
@@ -137,12 +138,17 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
onDatePickerClosed() {
|
||||
this.datePickerInput.nativeElement.blur();
|
||||
this.onTimeChanged();
|
||||
if (!this.time.value) {
|
||||
this.slideToggleExpirationDate.checked = false;
|
||||
}
|
||||
}
|
||||
|
||||
preventIncorrectCharacters(e: KeyboardEvent): boolean {
|
||||
const regex = /[^\d/.-]/;
|
||||
return e.key.length === 1 ? !regex.test(e.key) : true;
|
||||
}
|
||||
|
||||
private openConfirmationDialog() {
|
||||
this.isFileShared = false;
|
||||
|
||||
|
||||
@@ -147,9 +147,9 @@ describe('Content Type Dialog Component', () => {
|
||||
});
|
||||
|
||||
it('should show the property with the aspect prefix not the inherited ones', async () => {
|
||||
const showPropertyAccordon: HTMLButtonElement = fixture.nativeElement.querySelector('.adf-content-type-accordion .mat-expansion-panel-header');
|
||||
expect(showPropertyAccordon).toBeDefined();
|
||||
showPropertyAccordon.click();
|
||||
const showPropertyAccordion: HTMLButtonElement = fixture.nativeElement.querySelector('.adf-content-type-accordion .mat-expansion-panel-header');
|
||||
expect(showPropertyAccordion).toBeDefined();
|
||||
showPropertyAccordion.click();
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
const propertyShowed: NodeList = fixture.nativeElement.querySelectorAll('.adf-content-type-table .mat-row');
|
||||
|
||||
@@ -55,22 +55,21 @@
|
||||
[outerHTML]="ecmUser | usernameInitials:'adf-userinfo-profile-initials adf-hide-small'"></div>
|
||||
</ng-template>
|
||||
|
||||
<div class="adf-userinfo-title" id="ecm-username">{{ecmUser | fullName}}</div>
|
||||
<div class="mat-title" id="ecm-username">{{ecmUser | fullName}}</div>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<div class="adf-userinfo-supporting-text">
|
||||
<div class="adf-userinfo-detail">
|
||||
<span id="ecm-full-name"
|
||||
class="adf-userinfo__detail-title">{{ecmUser | fullName}}</span>
|
||||
<span class="adf-userinfo__detail-profile" id="ecm-email"> {{ecmUser.email}} </span>
|
||||
<a class="adf-userinfo__detail-profile" href="#/profile">
|
||||
<h2 id="ecm-full-name"
|
||||
class="adf-userinfo__detail-title">{{ecmUser | fullName}}</h2>
|
||||
<span id="ecm-email"> {{ecmUser.email}} </span>
|
||||
<a href="#/profile">
|
||||
{{ 'USER_PROFILE.LABELS.MY_PROFILE' | translate }}</a>
|
||||
</div>
|
||||
<div class="adf-userinfo-detail">
|
||||
<span class="adf-userinfo__secondary-info" id="ecm-job-title-label">
|
||||
{{ 'USER_PROFILE.LABELS.ECM.JOB_TITLE' | translate }}
|
||||
<span id="ecm-job-title"
|
||||
class="adf-userinfo__detail-profile"> {{ ecmUser.jobTitle ? ecmUser.jobTitle : 'N/A' }} </span>
|
||||
<span id="ecm-job-title"> {{ ecmUser.jobTitle ? ecmUser.jobTitle : 'N/A' }} </span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -90,16 +89,15 @@
|
||||
<div
|
||||
[outerHTML]="identityUser | usernameInitials:'adf-userinfo-profile-initials adf-hide-small'"></div>
|
||||
</ng-template>
|
||||
<div class="adf-userinfo-title" id="identity-username">{{identityUser | fullName}}</div>
|
||||
<div class="mat-title" id="identity-username">{{identityUser | fullName}}</div>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<div class="adf-userinfo-supporting-text">
|
||||
<div class="adf-userinfo-detail">
|
||||
<span id="identity-full-name"
|
||||
class="adf-userinfo__detail-title">{{identityUser | fullName}}</span>
|
||||
<span class="adf-userinfo__detail-profile"
|
||||
id="identity-email"> {{identityUser.email}} </span>
|
||||
<a class="adf-userinfo__detail-profile" href="#/profile">
|
||||
<h2 id="identity-full-name"
|
||||
class="adf-userinfo__detail-title">{{identityUser | fullName}}</h2>
|
||||
<span id="identity-email"> {{identityUser.email}} </span>
|
||||
<a href="#/profile">
|
||||
{{ 'USER_PROFILE.LABELS.MY_PROFILE' | translate }}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -84,10 +84,6 @@
|
||||
}
|
||||
|
||||
&-userinfo-supporting-text {
|
||||
font-size: var(--theme-body-1-font-size);
|
||||
font-weight: 400;
|
||||
letter-spacing: 0;
|
||||
line-height: 18px;
|
||||
overflow: hidden;
|
||||
padding: 32px;
|
||||
column-count: 2;
|
||||
@@ -99,28 +95,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
&-userinfo-title {
|
||||
font-size: var(--theme-title-font-size);
|
||||
}
|
||||
|
||||
&-userinfo__detail-profile {
|
||||
align-items: flex-start;
|
||||
font-size: var(--theme-body-1-font-size);
|
||||
font-weight: 400;
|
||||
letter-spacing: 0;
|
||||
line-height: 18px;
|
||||
display: block;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
&-userinfo__detail-title {
|
||||
text-overflow: ellipsis;
|
||||
font-size: var(--theme-subheading-2-font-size);
|
||||
font-weight: 400;
|
||||
letter-spacing: 0.04em;
|
||||
line-height: 20px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
&-userinfo__secondary-info {
|
||||
|
||||
@@ -68,7 +68,8 @@ export class ContentUserInfoComponent implements OnDestroy {
|
||||
@Input()
|
||||
showName: boolean = true;
|
||||
|
||||
/** When the username is shown, this defines its position relative to the user info button.
|
||||
/**
|
||||
* When the username is shown, this defines its position relative to the user info button.
|
||||
* Can be `right` or `left`.
|
||||
*/
|
||||
@Input()
|
||||
|
||||
@@ -161,7 +161,7 @@ describe('Confirm Dialog Component', () => {
|
||||
By.css('[data-automation-id="adf-confirm-dialog-confirm-all"]')
|
||||
);
|
||||
expect(thirdOptionElement).not.toBeNull();
|
||||
expect(thirdOptionElement.nativeElement.innerText).toBe('YES ALL');
|
||||
expect(thirdOptionElement.nativeElement.innerText.toUpperCase()).toBe('YES ALL');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -20,6 +20,7 @@ import { UntypedFormControl } from '@angular/forms';
|
||||
const I18N_ERRORS_PATH = 'CORE.FOLDER_DIALOG.FOLDER_NAME.ERRORS';
|
||||
|
||||
export const forbidSpecialCharacters = ({ value }: UntypedFormControl) => {
|
||||
// eslint-disable-next-line no-useless-escape
|
||||
const specialCharacters: RegExp = /([\*\"\<\>\\\/\?\:\|])/;
|
||||
const isValid: boolean = !specialCharacters.test(value);
|
||||
|
||||
|
||||
@@ -39,12 +39,14 @@ export class FolderDialogComponent implements OnInit {
|
||||
|
||||
folder: Node = null;
|
||||
|
||||
/** Emitted when the edit/create folder give error for example a folder with same name already exist
|
||||
/**
|
||||
* Emitted when the edit/create folder give error for example a folder with same name already exist
|
||||
*/
|
||||
@Output()
|
||||
error: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
/** Emitted when the edit/create folder is successfully created/modified
|
||||
/**
|
||||
* Emitted when the edit/create folder is successfully created/modified
|
||||
*/
|
||||
@Output()
|
||||
success: EventEmitter<any> = new EventEmitter<Node>();
|
||||
|
||||
@@ -49,7 +49,8 @@ export class LibraryDialogComponent implements OnInit, OnDestroy {
|
||||
@Output()
|
||||
error: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
/** Emitted when the new library is created successfully. The
|
||||
/**
|
||||
* Emitted when the new library is created successfully. The
|
||||
* event parameter is a SiteEntry object with the details of the
|
||||
* newly-created library.
|
||||
*/
|
||||
|
||||
@@ -15,19 +15,19 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import moment from 'moment';
|
||||
|
||||
import { TestBed, fakeAsync, tick, ComponentFixture } from '@angular/core/testing';
|
||||
import { MatDialogRef } from '@angular/material/dialog';
|
||||
import { NodeLockDialogComponent } from './node-lock.dialog';
|
||||
import { ContentTestingModule } from '../testing/content.testing.module';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { addMinutes } from 'date-fns';
|
||||
|
||||
describe('NodeLockDialogComponent', () => {
|
||||
|
||||
let fixture: ComponentFixture<NodeLockDialogComponent>;
|
||||
let component: NodeLockDialogComponent;
|
||||
let expiryDate;
|
||||
let expiryDate: Date;
|
||||
|
||||
const dialogRef = {
|
||||
close: jasmine.createSpy('close')
|
||||
};
|
||||
@@ -54,7 +54,7 @@ describe('NodeLockDialogComponent', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
jasmine.clock().mockDate(new Date());
|
||||
expiryDate = moment().add(1, 'minutes');
|
||||
expiryDate = addMinutes(new Date(), 1);
|
||||
|
||||
component.data = {
|
||||
node: {
|
||||
@@ -77,25 +77,12 @@ describe('NodeLockDialogComponent', () => {
|
||||
expect(component.form.value.isLocked).toBe(true);
|
||||
expect(component.form.value.allowOwner).toBe(true);
|
||||
expect(component.form.value.isTimeLock).toBe(true);
|
||||
expect(component.form.value.time.format()).toBe(expiryDate.format());
|
||||
});
|
||||
|
||||
it('should update form inputs', () => {
|
||||
const newTime = moment();
|
||||
component.form.controls['isLocked'].setValue(false);
|
||||
component.form.controls['allowOwner'].setValue(false);
|
||||
component.form.controls['isTimeLock'].setValue(false);
|
||||
component.form.controls['time'].setValue(newTime);
|
||||
|
||||
expect(component.form.value.isLocked).toBe(false);
|
||||
expect(component.form.value.allowOwner).toBe(false);
|
||||
expect(component.form.value.isTimeLock).toBe(false);
|
||||
expect(component.form.value.time.format()).toBe(newTime.format());
|
||||
expect(component.form.value.time).toEqual(expiryDate);
|
||||
});
|
||||
|
||||
it('should call dialog to close with form data when submit is successfully', fakeAsync(() => {
|
||||
const node: any = { entry: {} };
|
||||
spyOn(component['nodesApi'], 'lockNode').and.returnValue(Promise.resolve(node));
|
||||
spyOn(component.nodesApi, 'lockNode').and.returnValue(Promise.resolve(node));
|
||||
|
||||
component.submit();
|
||||
tick();
|
||||
@@ -105,7 +92,7 @@ describe('NodeLockDialogComponent', () => {
|
||||
}));
|
||||
|
||||
it('should call onError if submit fails', fakeAsync(() => {
|
||||
spyOn(component['nodesApi'], 'lockNode').and.returnValue(Promise.reject('error'));
|
||||
spyOn(component.nodesApi, 'lockNode').and.returnValue(Promise.reject('error'));
|
||||
spyOn(component.data, 'onError');
|
||||
|
||||
component.submit();
|
||||
|
||||
@@ -15,12 +15,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import moment from 'moment';
|
||||
|
||||
import { Component, Inject, OnInit, Optional, ViewEncapsulation } from '@angular/core';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
|
||||
|
||||
import { differenceInSeconds } from 'date-fns';
|
||||
import { NodeBodyLock, Node, NodeEntry, NodesApi } from '@alfresco/js-api';
|
||||
import { AlfrescoApiService } from '@alfresco/adf-core';
|
||||
|
||||
@@ -35,7 +33,7 @@ export class NodeLockDialogComponent implements OnInit {
|
||||
node: Node = null;
|
||||
nodeName: string;
|
||||
|
||||
_nodesApi: NodesApi;
|
||||
private _nodesApi: NodesApi;
|
||||
get nodesApi(): NodesApi {
|
||||
this._nodesApi = this._nodesApi ?? new NodesApi(this.alfrescoApi.getInstance());
|
||||
return this._nodesApi;
|
||||
@@ -55,18 +53,20 @@ export class NodeLockDialogComponent implements OnInit {
|
||||
const { node } = this.data;
|
||||
this.nodeName = node.name;
|
||||
|
||||
const isTimeLock = !!node.properties['cm:expiryDate'];
|
||||
const time = isTimeLock ? new Date(node.properties['cm:expiryDate']) : new Date();
|
||||
|
||||
this.form = this.formBuilder.group({
|
||||
isLocked: node.isLocked || false,
|
||||
allowOwner: node.properties['cm:lockType'] === 'WRITE_LOCK',
|
||||
isTimeLock: !!node.properties['cm:expiryDate'],
|
||||
time: !!node.properties['cm:expiryDate'] ? moment(node.properties['cm:expiryDate']) : moment()
|
||||
isTimeLock,
|
||||
time
|
||||
});
|
||||
}
|
||||
|
||||
private get lockTimeInSeconds(): number {
|
||||
if (this.form.value.isTimeLock) {
|
||||
const duration = moment.duration(moment(this.form.value.time).diff(moment()));
|
||||
return duration.asSeconds();
|
||||
return differenceInSeconds(new Date(this.form.value.time), Date.now());
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -24,10 +24,10 @@ import { TranslateModule } from '@ngx-translate/core';
|
||||
@Component({
|
||||
template: `<div tabindex="0" adf-auto-focus> Test</div>`
|
||||
})
|
||||
class AutoFoucsTestComponent {}
|
||||
class AutoFocusTestComponent {}
|
||||
|
||||
describe('AutoFocusDirective', () => {
|
||||
let fixture: ComponentFixture<AutoFoucsTestComponent>;
|
||||
let fixture: ComponentFixture<AutoFocusTestComponent>;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
@@ -36,10 +36,10 @@ describe('AutoFocusDirective', () => {
|
||||
],
|
||||
declarations: [
|
||||
AutoFocusDirective,
|
||||
AutoFoucsTestComponent
|
||||
AutoFocusTestComponent
|
||||
]
|
||||
});
|
||||
fixture = TestBed.createComponent(AutoFoucsTestComponent);
|
||||
fixture = TestBed.createComponent(AutoFocusTestComponent);
|
||||
});
|
||||
|
||||
it('should focus the element after content is initialized', fakeAsync(() => {
|
||||
|
||||
@@ -28,7 +28,8 @@ import { NodeAllowableOperationSubject } from '../interfaces/node-allowable-oper
|
||||
})
|
||||
export class CheckAllowableOperationDirective implements OnChanges {
|
||||
|
||||
/** Node permission to check (create, delete, update, updatePermissions,
|
||||
/**
|
||||
* Node permission to check (create, delete, update, updatePermissions,
|
||||
* !create, !delete, !update, !updatePermissions).
|
||||
*/
|
||||
@Input('adf-check-allowable-operation')
|
||||
@@ -57,7 +58,7 @@ export class CheckAllowableOperationDirective implements OnChanges {
|
||||
/**
|
||||
* Updates disabled state for the decorated element
|
||||
*
|
||||
* @memberof CheckAllowableOperationDirective
|
||||
* @returns the new state
|
||||
*/
|
||||
updateElement(): boolean {
|
||||
const enable = this.hasAllowableOperations(this.nodes, this.permission);
|
||||
@@ -112,7 +113,7 @@ export class CheckAllowableOperationDirective implements OnChanges {
|
||||
*
|
||||
* @param nodes Node collection to check
|
||||
* @param permission Permission to check for each node
|
||||
* @memberof CheckAllowableOperationDirective
|
||||
* @returns `true` if there are allowable operations, otherwise `false`
|
||||
*/
|
||||
hasAllowableOperations(nodes: NodeEntry[], permission: string): boolean {
|
||||
if (nodes && nodes.length > 0) {
|
||||
|
||||
@@ -118,7 +118,7 @@ export class NodeDeleteDirective implements OnChanges {
|
||||
|
||||
let promise: Promise<any>;
|
||||
|
||||
if (node.entry.hasOwnProperty('archivedAt') && node.entry['archivedAt']) {
|
||||
if (Object.prototype.hasOwnProperty.call(node.entry, 'archivedAt') && node.entry['archivedAt']) {
|
||||
promise = this.trashcanApi.deleteDeletedNode(id);
|
||||
} else {
|
||||
promise = this.nodesApi.deleteNode(id, { permanent: this.permanent });
|
||||
|
||||
@@ -130,7 +130,7 @@ export class NodeFavoriteDirective implements OnChanges {
|
||||
const node: Node | SharedLink = selected.entry;
|
||||
|
||||
// ACS 6.x with 'isFavorite' include
|
||||
if (node?.hasOwnProperty('isFavorite')) {
|
||||
if (node && Object.prototype.hasOwnProperty.call(node, 'isFavorite')) {
|
||||
return of(selected);
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -35,6 +35,7 @@ export class ContentActionListComponent {
|
||||
* Registers action handler within the parent document list component.
|
||||
*
|
||||
* @param action Action model to register.
|
||||
* @returns `true` if actions was registered, otherwise `false`
|
||||
*/
|
||||
registerAction(action: ContentActionModel): boolean {
|
||||
if (this.documentList && action) {
|
||||
|
||||
+4
-2
@@ -76,13 +76,15 @@ export class ContentActionComponent implements OnInit, OnChanges, OnDestroy {
|
||||
@Output()
|
||||
permissionEvent = new EventEmitter();
|
||||
|
||||
/** Emitted when an error occurs during the action.
|
||||
/**
|
||||
* Emitted when an error occurs during the action.
|
||||
* Applies to copy and move actions.
|
||||
*/
|
||||
@Output()
|
||||
error = new EventEmitter();
|
||||
|
||||
/** Emitted when the action succeeds with the success string message.
|
||||
/**
|
||||
* Emitted when the action succeeds with the success string message.
|
||||
* Applies to copy, move and delete actions.
|
||||
*/
|
||||
@Output()
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user