[ADF-4894] Json editor dialog (#5082)

* move download-zip to its own folder

* json dialog

* update docs

* update test

* disable e2e test

* json widget for the Form

* remove deprecated test

* fix tests, update display text name
This commit is contained in:
Denys Vuika 2019-09-20 07:26:37 +01:00 committed by GitHub
parent c15807a013
commit 90b2cee70d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 357 additions and 127 deletions

View File

@ -19,8 +19,8 @@
[multiselect]="multiselect" [multiselect]="multiselect"
[actions]="true" [actions]="true"
rowStyleClass="custom-row-style" rowStyleClass="custom-row-style"
(showRowActionsMenu)="onShowRowActionsMenu($event)" (executeRowAction)="onExecuteRowAction($event)" (showRowActionsMenu)="onShowRowActionsMenu($event)"
(row-click)="onRowClick($event)" (row-dblclick)="onRowDblClick($event)"> (executeRowAction)="onExecuteRowAction($event)">
<!-- HTML column definition demo --> <!-- HTML column definition demo -->
<!-- <!--
<data-columns> <data-columns>

View File

@ -16,7 +16,7 @@
*/ */
import { Component, Input } from '@angular/core'; import { Component, Input } from '@angular/core';
import { LogService, DataColumn, DataRow } from '@alfresco/adf-core'; import { DataColumn, DataRow } from '@alfresco/adf-core';
import { DataCellEvent, DataRowActionEvent, DataSorting, ObjectDataColumn, ObjectDataRow, ObjectDataTableAdapter } from '@alfresco/adf-core'; import { DataCellEvent, DataRowActionEvent, DataSorting, ObjectDataColumn, ObjectDataRow, ObjectDataTableAdapter } from '@alfresco/adf-core';
export class FilteredDataAdapter extends ObjectDataTableAdapter { export class FilteredDataAdapter extends ObjectDataTableAdapter {
@ -71,7 +71,7 @@ export class DataTableComponent {
email: 'admin@alfresco.com' email: 'admin@alfresco.com'
}; };
constructor(private logService: LogService) { constructor() {
this.reset(); this.reset();
} }
@ -209,19 +209,9 @@ export class DataTableComponent {
onExecuteRowAction(event: DataRowActionEvent) { onExecuteRowAction(event: DataRowActionEvent) {
const args = event.value; const args = event.value;
this.logService.log(args.row);
this.logService.log(args.action);
window.alert(`My custom action: ${args.action.title}`); window.alert(`My custom action: ${args.action.title}`);
} }
onRowClick(event) {
this.logService.log(event);
}
onRowDblClick(event) {
this.logService.log(event);
}
toggleStickyHeader() { toggleStickyHeader() {
this.stickyHeader = !this.stickyHeader; this.stickyHeader = !this.stickyHeader;
} }

View File

@ -51,7 +51,17 @@ Defines column properties for DataTable, Tasklist, Document List and other compo
| sortable | `boolean` | true | Toggles ability to sort by this column, for example by clicking the column header. | | sortable | `boolean` | true | Toggles ability to sort by this column, for example by clicking the column header. |
| srTitle | `string` | | Title to be used for screen readers. | | 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. | | 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'. | | type | `string` | "text" | Value type for the column. |
Supported `type` values:
- text
- image
- date
- icon
- fileSize
- location
- json (v3.4.0+)
## Details ## Details

View File

@ -0,0 +1,32 @@
---
Title: Edit JSON Dialog
Added: v3.5.0
Status: Active
Last reviewed: 2019-09-17
---
# Edit JSON Dialog
Allows a user to preview or edit a JSON content in a dialog.
## Basic usage
```ts
import { EditJsonDialogSettings, EditJsonDialogComponent } from '@alfresco/adf-core';
const settings: EditJsonDialogSettings = {
title: 'Edit Json',
editable: true,
value: `{ "hello": "world" }`
};
this.dialog.open(EditJsonDialogComponent, {
data: settings,
minWidth: '50%',
minHeight: '50%'
})
.afterClosed()
.subscribe((value: string) => {
// do something with the updated value
});
```

View File

@ -180,16 +180,6 @@ describe('Datatable component', () => {
await expect(await dataTablePage.getClipboardInputText()).toEqual('1'); await expect(await dataTablePage.getClipboardInputText()).toEqual('1');
}); });
it('[C307101] A column value of type json and with copyContent set to true is copied when clicking on it', async () => {
const jsonValue = `{ "id": 4 }`;
await copyContentDataTablePage.mouseOverJsonColumn(2);
await expect(await copyContentDataTablePage.getCopyContentTooltip()).toEqual('Click to copy');
await copyContentDataTablePage.clickOnJsonColumn(2);
await notificationHistoryPage.checkNotifyContains('Text copied to clipboard');
await copyContentDataTablePage.pasteClipboard();
await expect(await copyContentDataTablePage.getClipboardInputText()).toContain(jsonValue);
});
afterAll(async () => { afterAll(async () => {
await navigationBarPage.clickHomeButton(); await navigationBarPage.clickHomeButton();
}); });

View File

@ -17,10 +17,8 @@
/* tslint:disable:component-selector no-input-rename */ /* tslint:disable:component-selector no-input-rename */
import { DataColumn } from '@alfresco/adf-core'; import { DataColumn, DataColumnType, LogService } from '@alfresco/adf-core';
import { LogService } from '@alfresco/adf-core';
import { AfterContentInit, Component, ContentChild, Input, OnInit, TemplateRef } from '@angular/core'; import { AfterContentInit, Component, ContentChild, Input, OnInit, TemplateRef } from '@angular/core';
import { ContentColumnListComponent } from './content-column-list.component'; import { ContentColumnListComponent } from './content-column-list.component';
@Component({ @Component({
@ -33,7 +31,7 @@ export class ContentColumnComponent implements OnInit, AfterContentInit, DataCol
key: string; key: string;
@Input() @Input()
type: string = 'text'; type: DataColumnType = 'text';
@Input() @Input()
format: string; format: string;

View File

@ -190,7 +190,7 @@ describe('ShareDataTableAdapter', () => {
const col = <DataColumn> { const col = <DataColumn> {
key: 'createdAt', key: 'createdAt',
type: 'string' type: 'text'
}; };
const row = new ShareDataRow(file, contentService, null); const row = new ShareDataRow(file, contentService, null);
@ -265,7 +265,7 @@ describe('ShareDataTableAdapter', () => {
const adapter = new ShareDataTableAdapter(thumbnailService, contentService, null); const adapter = new ShareDataTableAdapter(thumbnailService, contentService, null);
const row = new ShareDataRow(new SmartFolderNode(), contentService, null); const row = new ShareDataRow(new SmartFolderNode(), contentService, null);
const col = <DataColumn> { type: 'folder', key: '$thumbnail' }; const col = <DataColumn> { type: 'text', key: '$thumbnail' };
const value = adapter.getValue(row, col); const value = adapter.getValue(row, col);
expect(value).toContain(`assets/images/ft_ic_smart_folder`); expect(value).toContain(`assets/images/ft_ic_smart_folder`);
@ -278,7 +278,7 @@ describe('ShareDataTableAdapter', () => {
const adapter = new ShareDataTableAdapter(thumbnailService, contentService, null); const adapter = new ShareDataTableAdapter(thumbnailService, contentService, null);
const row = new ShareDataRow(new LinkFolderNode(), contentService, null); const row = new ShareDataRow(new LinkFolderNode(), contentService, null);
const col = <DataColumn> { type: 'folder', key: '$thumbnail' }; const col = <DataColumn> { type: 'text', key: '$thumbnail' };
const value = adapter.getValue(row, col); const value = adapter.getValue(row, col);
expect(value).toContain(`assets/images/ft_ic_folder_shortcut_link`); expect(value).toContain(`assets/images/ft_ic_folder_shortcut_link`);
@ -291,7 +291,7 @@ describe('ShareDataTableAdapter', () => {
const adapter = new ShareDataTableAdapter(thumbnailService, contentService, null); const adapter = new ShareDataTableAdapter(thumbnailService, contentService, null);
const row = new ShareDataRow(new RuleFolderNode(), contentService, null); const row = new ShareDataRow(new RuleFolderNode(), contentService, null);
const col = <DataColumn> { type: 'folder', key: '$thumbnail' }; const col = <DataColumn> { type: 'text', key: '$thumbnail' };
const value = adapter.getValue(row, col); const value = adapter.getValue(row, col);
expect(value).toContain(`assets/images/ft_ic_folder_rule`); expect(value).toContain(`assets/images/ft_ic_folder_rule`);

View File

@ -18,7 +18,7 @@
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { FlexLayoutModule } from '@angular/flex-layout'; import { FlexLayoutModule } from '@angular/flex-layout';
import { CoreModule } from '@alfresco/adf-core'; import { CoreModule, EditJsonDialogModule } from '@alfresco/adf-core';
import { MaterialModule } from '../material.module'; import { MaterialModule } from '../material.module';
import { UploadModule } from '../upload/upload.module'; import { UploadModule } from '../upload/upload.module';
@ -41,7 +41,8 @@ import { NameColumnComponent } from './components/name-column/name-column.compon
CommonModule, CommonModule,
FlexLayoutModule, FlexLayoutModule,
MaterialModule, MaterialModule,
UploadModule UploadModule,
EditJsonDialogModule
], ],
declarations: [ declarations: [
DocumentListComponent, DocumentListComponent,

View File

@ -70,6 +70,9 @@ export class DataColumnComponent implements OnInit {
@Input() @Input()
copyContent: boolean; copyContent: boolean;
@Input()
editable: boolean = false;
ngOnInit() { ngOnInit() {
if (!this.srTitle && this.key === '$thumbnail') { if (!this.srTitle && this.key === '$thumbnail') {
this.srTitle = 'Thumbnail'; this.srTitle = 'Thumbnail';

View File

@ -174,7 +174,7 @@
</div> </div>
<div *ngSwitchCase="'json'" tabindex="0" class="adf-cell-value"> <div *ngSwitchCase="'json'" tabindex="0" class="adf-cell-value">
<adf-json-cell <adf-json-cell
[copyContent]="col.copyContent" [editable]="col.editable"
[data]="data" [data]="data"
[column]="col" [column]="col"
[row]="row"> [row]="row">

View File

@ -72,12 +72,10 @@ describe('JsonCellComponent', () => {
}); });
}); });
it('should render json object inside cell', () => { it('should render json button inside cell', () => {
fixture.detectChanges(); fixture.detectChanges();
const spanElement: HTMLElement = fixture.debugElement.nativeElement.querySelector('.adf-datatable-cell-value'); const button: HTMLElement = fixture.debugElement.nativeElement.querySelector('.mat-button');
const unFormatedContent: string = spanElement.textContent.replace(/\n/g, '').replace(/\s/g, ''); expect(button).toBeDefined();
const rowDataStringify: string = JSON.stringify(rowData.entity).replace(/\s/g, '');
expect(unFormatedContent).toBe(rowDataStringify);
}); });
it('should not setup cell when has no data', () => { it('should not setup cell when has no data', () => {

View File

@ -17,23 +17,20 @@
import { ChangeDetectionStrategy, Component, OnInit, ViewEncapsulation, Input } from '@angular/core'; import { ChangeDetectionStrategy, Component, OnInit, ViewEncapsulation, Input } from '@angular/core';
import { DataTableCellComponent } from './datatable-cell.component'; import { DataTableCellComponent } from './datatable-cell.component';
import { MatDialog } from '@angular/material';
import { EditJsonDialogComponent, EditJsonDialogSettings } from '../../../dialogs/edit-json/edit-json.dialog';
import { AlfrescoApiService } from '../../../services/alfresco-api.service';
@Component({ @Component({
selector: 'adf-json-cell', selector: 'adf-json-cell',
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
template: ` template: `
<ng-container> <ng-container *ngIf="value$ | async as value; else editEmpty">
<span *ngIf="copyContent; else defaultJsonTemplate" class="adf-datatable-cell-value"> <button mat-button color="primary" (click)="view()">json</button>
<pre
class="adf-datatable-json-cell"
[adf-clipboard]="'CLIPBOARD.CLICK_TO_COPY'"
[clipboard-notification]="'CLIPBOARD.SUCCESS_COPY'">{{ value$ | async | json }}</pre>
</span>
</ng-container> </ng-container>
<ng-template #defaultJsonTemplate>
<span class="adf-datatable-cell-value"> <ng-template #editEmpty>
<pre class="adf-datatable-json-cell">{{ value$ | async | json }}</pre> <button *ngIf="editable" mat-button color="primary" (click)="view()">json</button>
</span>
</ng-template> </ng-template>
`, `,
styleUrls: ['./json-cell.component.scss'], styleUrls: ['./json-cell.component.scss'],
@ -42,13 +39,44 @@ import { DataTableCellComponent } from './datatable-cell.component';
}) })
export class JsonCellComponent extends DataTableCellComponent implements OnInit { export class JsonCellComponent extends DataTableCellComponent implements OnInit {
/** Enables/disables a Clipboard directive to allow copying of the cell's content. */
@Input() @Input()
copyContent: boolean; editable: boolean = false;
constructor(
private dialog: MatDialog,
alfrescoApiService: AlfrescoApiService
) {
super(alfrescoApiService);
}
ngOnInit() { ngOnInit() {
if (this.column && this.column.key && this.row && this.data) { if (this.column && this.column.key && this.row && this.data) {
this.value$.next(this.data.getValue(this.row, this.column)); this.value$.next(this.data.getValue(this.row, this.column));
} }
} }
view() {
const rawValue: string | object = this.data.getValue(this.row, this.column);
const value = typeof rawValue === 'object'
? JSON.stringify(rawValue || {}, null, 2)
: rawValue;
const settings: EditJsonDialogSettings = {
title: this.column.title,
editable: this.editable,
value
};
this.dialog.open(EditJsonDialogComponent, {
data: settings,
minWidth: '50%',
minHeight: '50%'
}).afterClosed().subscribe((/*result: string*/) => {
if (typeof rawValue === 'object') {
// todo: update cell value as object
} else {
// todo: update cell value as string
}
});
}
} }

View File

@ -17,9 +17,21 @@
import { TemplateRef } from '@angular/core'; import { TemplateRef } from '@angular/core';
export interface DataColumnTypes {
text: string;
image: string;
date: string;
json: string;
icon: string;
fileSize: string;
location: string;
}
export type DataColumnType = keyof DataColumnTypes;
export interface DataColumn { export interface DataColumn {
key: string; key: string;
type: string; // text|image|date type: DataColumnType;
format?: string; format?: string;
sortable?: boolean; sortable?: boolean;
title?: string; title?: string;
@ -28,4 +40,5 @@ export interface DataColumn {
template?: TemplateRef<any>; template?: TemplateRef<any>;
formatTooltip?: Function; formatTooltip?: Function;
copyContent?: boolean; copyContent?: boolean;
editable?: boolean;
} }

View File

@ -16,13 +16,13 @@
*/ */
import { TemplateRef } from '@angular/core'; import { TemplateRef } from '@angular/core';
import { DataColumn } from './data-column.model'; import { DataColumn, DataColumnType } from './data-column.model';
// Simple implementation of the DataColumn interface. // Simple implementation of the DataColumn interface.
export class ObjectDataColumn implements DataColumn { export class ObjectDataColumn implements DataColumn {
key: string; key: string;
type: string; // text|image type: DataColumnType;
format: string; format: string;
sortable: boolean; sortable: boolean;
title: string; title: string;

View File

@ -19,7 +19,7 @@ import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { MaterialModule } from '../material.module'; import { MaterialModule } from '../material.module';
import { DownloadZipDialogComponent } from './download-zip.dialog'; import { DownloadZipDialogComponent } from './download-zip/download-zip.dialog';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { PipeModule } from '../pipes/pipe.module'; import { PipeModule } from '../pipes/pipe.module';

View File

@ -2,9 +2,8 @@
<div mat-dialog-content> <div mat-dialog-content>
<mat-progress-bar color="primary" mode="indeterminate"></mat-progress-bar> <mat-progress-bar color="primary" mode="indeterminate"></mat-progress-bar>
</div> </div>
<div mat-dialog-actions> <mat-dialog-actions align="end">
<span class="adf-spacer"></span>
<button mat-button color="primary" id="cancel-button" (click)="cancelDownload()"> <button mat-button color="primary" id="cancel-button" (click)="cancelDownload()">
{{ 'CORE.DIALOG.DOWNLOAD_ZIP.ACTIONS.CANCEL' | translate }} {{ 'CORE.DIALOG.DOWNLOAD_ZIP.ACTIONS.CANCEL' | translate }}
</button> </button>
</div> </mat-dialog-actions>

View File

@ -1,5 +1,3 @@
.adf-spacer { flex: 1 1 auto; }
.adf-download-zip-dialog .mat-dialog-actions .mat-button-wrapper { .adf-download-zip-dialog .mat-dialog-actions .mat-button-wrapper {
text-transform: uppercase; text-transform: uppercase;
} }

View File

@ -19,9 +19,9 @@ import { TestBed } from '@angular/core/testing';
import { ComponentFixture } from '@angular/core/testing'; import { ComponentFixture } from '@angular/core/testing';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material'; import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
import { DownloadZipDialogComponent } from './download-zip.dialog'; import { DownloadZipDialogComponent } from './download-zip.dialog';
import { setupTestBed } from '../testing/setupTestBed'; import { setupTestBed } from '../../testing/setupTestBed';
import { CoreTestingModule } from '../testing/core.testing.module'; import { CoreTestingModule } from '../../testing/core.testing.module';
import { DownloadZipService } from '../services/download-zip.service'; import { DownloadZipService } from '../../services/download-zip.service';
import { Observable } from 'rxjs/index'; import { Observable } from 'rxjs/index';
describe('DownloadZipDialogComponent', () => { describe('DownloadZipDialogComponent', () => {

View File

@ -18,8 +18,8 @@
import { Component, Inject, OnInit, ViewEncapsulation } from '@angular/core'; import { Component, Inject, OnInit, ViewEncapsulation } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
import { DownloadEntry, NodeEntry } from '@alfresco/js-api'; import { DownloadEntry, NodeEntry } from '@alfresco/js-api';
import { LogService } from '../services/log.service'; import { LogService } from '../../services/log.service';
import { DownloadZipService } from '../services/download-zip.service'; import { DownloadZipService } from '../../services/download-zip.service';
@Component({ @Component({
selector: 'adf-download-zip-dialog', selector: 'adf-download-zip-dialog',

View File

@ -0,0 +1,13 @@
<h1 mat-dialog-title>{{ title | translate }}</h1>
<mat-dialog-content>
<textarea [(ngModel)]="value" [attr.readonly]="!editable"></textarea>
</mat-dialog-content>
<mat-dialog-actions align="end">
<button mat-button mat-dialog-close cdkFocusInitial>
{{ 'CORE.DIALOG.EDIT_JSON.CLOSE' | translate }}
</button>
<button *ngIf="editable" mat-button [mat-dialog-close]="value">
{{ 'CORE.DIALOG.EDIT_JSON.UPDATE' | translate }}
</button>
</mat-dialog-actions>

View File

@ -0,0 +1,45 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatDialogModule } from '@angular/material/dialog';
import { TranslateModule } from '@ngx-translate/core';
import { EditJsonDialogComponent } from './edit-json.dialog';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
@NgModule({
imports: [
CommonModule,
FormsModule,
ReactiveFormsModule,
TranslateModule.forChild(),
MatDialogModule,
MatButtonModule
],
declarations: [
EditJsonDialogComponent
],
exports: [
EditJsonDialogComponent
],
entryComponents: [
EditJsonDialogComponent
]
})
export class EditJsonDialogModule {}

View File

@ -0,0 +1,19 @@
.adf-edit-json-dialog {
.mat-dialog-content {
height: 300px;
overflow: hidden;
}
textarea {
&:focus {
outline: none;
}
resize: none;
width: 100%;
height: 100%;
margin: 0;
padding: 0;
box-sizing: border-box; /* For IE and modern versions of Chrome */
-moz-box-sizing: border-box; /* For Firefox */
-webkit-box-sizing: border-box; /* For Safari */
}
}

View File

@ -0,0 +1,52 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 { Component, Inject, OnInit, Input, ViewEncapsulation } from '@angular/core';
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
export interface EditJsonDialogSettings {
title?: string;
editable?: boolean;
value?: string;
}
@Component({
templateUrl: 'edit-json.dialog.html',
styleUrls: ['edit-json.dialog.scss'],
encapsulation: ViewEncapsulation.None,
host: { class: 'adf-edit-json-dialog' }
})
export class EditJsonDialogComponent implements OnInit {
editable: boolean = false;
title: string = 'JSON';
@Input()
value: string = '';
constructor(
@Inject(MAT_DIALOG_DATA) private settings: EditJsonDialogSettings
) {}
ngOnInit() {
if (this.settings) {
this.editable = this.settings.editable ? true : false;
this.value = this.settings.value || '';
this.title = this.settings.title || 'JSON';
}
}
}

View File

@ -15,6 +15,9 @@
* limitations under the License. * limitations under the License.
*/ */
export * from './download-zip.dialog'; export * from './download-zip/download-zip.dialog';
export * from './edit-json/edit-json.dialog';
export * from './edit-json/edit-json.dialog.module';
export * from './dialog.module'; export * from './dialog.module';

View File

@ -18,7 +18,7 @@
import { Directive, Input, HostListener } from '@angular/core'; import { Directive, Input, HostListener } from '@angular/core';
import { MatDialog } from '@angular/material'; import { MatDialog } from '@angular/material';
import { AlfrescoApiService } from '../services/alfresco-api.service'; import { AlfrescoApiService } from '../services/alfresco-api.service';
import { DownloadZipDialogComponent } from '../dialogs/download-zip.dialog'; import { DownloadZipDialogComponent } from '../dialogs/download-zip/download-zip.dialog';
import { NodeEntry } from '@alfresco/js-api'; import { NodeEntry } from '@alfresco/js-api';
/** /**

View File

@ -28,7 +28,7 @@ import { baseHost , WidgetComponent } from './../widget.component';
host: baseHost, host: baseHost,
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class DisplayTextWidgetComponentComponent extends WidgetComponent { export class DisplayTextWidgetComponent extends WidgetComponent {
constructor(public formService: FormService) { constructor(public formService: FormService) {
super(formService); super(formService);

View File

@ -22,7 +22,7 @@ import { UnknownWidgetComponent } from './unknown/unknown.widget';
import { AmountWidgetComponent } from './amount/amount.widget'; import { AmountWidgetComponent } from './amount/amount.widget';
import { CheckboxWidgetComponent } from './checkbox/checkbox.widget'; import { CheckboxWidgetComponent } from './checkbox/checkbox.widget';
import { DateWidgetComponent } from './date/date.widget'; import { DateWidgetComponent } from './date/date.widget';
import { DisplayTextWidgetComponentComponent } from './display-text/display-text.widget'; import { DisplayTextWidgetComponent } from './display-text/display-text.widget';
import { DocumentWidgetComponent } from './document/document.widget'; import { DocumentWidgetComponent } from './document/document.widget';
import { DropdownWidgetComponent } from './dropdown/dropdown.widget'; import { DropdownWidgetComponent } from './dropdown/dropdown.widget';
import { DynamicTableWidgetComponent } from './dynamic-table/dynamic-table.widget'; import { DynamicTableWidgetComponent } from './dynamic-table/dynamic-table.widget';
@ -44,6 +44,7 @@ import { TextWidgetComponent } from './text/text.widget';
import { TypeaheadWidgetComponent } from './typeahead/typeahead.widget'; import { TypeaheadWidgetComponent } from './typeahead/typeahead.widget';
import { UploadWidgetComponent } from './upload/upload.widget'; import { UploadWidgetComponent } from './upload/upload.widget';
import { DateTimeWidgetComponent } from './date-time/date-time.widget'; import { DateTimeWidgetComponent } from './date-time/date-time.widget';
import { JsonWidgetComponent } from './json/json.widget';
// core // core
export * from './widget.component'; export * from './widget.component';
@ -73,6 +74,7 @@ export * from './dynamic-table/dynamic-table.widget';
export * from './error/error.component'; export * from './error/error.component';
export * from './document/document.widget'; export * from './document/document.widget';
export * from './date-time/date-time.widget'; export * from './date-time/date-time.widget';
export * from './json/json.widget';
// editors (dynamic table) // editors (dynamic table)
export * from './dynamic-table/dynamic-table.widget.model'; export * from './dynamic-table/dynamic-table.widget.model';
@ -95,7 +97,7 @@ export const WIDGET_DIRECTIVES: any[] = [
DropdownWidgetComponent, DropdownWidgetComponent,
HyperlinkWidgetComponent, HyperlinkWidgetComponent,
RadioButtonsWidgetComponent, RadioButtonsWidgetComponent,
DisplayTextWidgetComponentComponent, DisplayTextWidgetComponent,
UploadWidgetComponent, UploadWidgetComponent,
TypeaheadWidgetComponent, TypeaheadWidgetComponent,
FunctionalGroupWidgetComponent, FunctionalGroupWidgetComponent,
@ -111,7 +113,8 @@ export const WIDGET_DIRECTIVES: any[] = [
ErrorWidgetComponent, ErrorWidgetComponent,
DocumentWidgetComponent, DocumentWidgetComponent,
DateTimeWidgetComponent, DateTimeWidgetComponent,
DateTimeEditorComponent DateTimeEditorComponent,
JsonWidgetComponent
]; ];
export const MASK_DIRECTIVE: any[] = [ export const MASK_DIRECTIVE: any[] = [

View File

@ -0,0 +1,56 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 { Component, ViewEncapsulation } from '@angular/core';
import { FormService } from './../../../services/form.service';
import { baseHost, WidgetComponent } from './../widget.component';
import { MatDialog } from '@angular/material/dialog';
import { EditJsonDialogSettings, EditJsonDialogComponent } from '../../../../dialogs/edit-json/edit-json.dialog';
@Component({
template: `
<button mat-raised-button color="primary" (click)="view()">json</button>
`,
host: baseHost,
encapsulation: ViewEncapsulation.None
})
export class JsonWidgetComponent extends WidgetComponent {
constructor(public formService: FormService, private dialog: MatDialog) {
super(formService);
}
view() {
const rawValue = this.field.value;
const value =
typeof rawValue === 'object'
? JSON.stringify(rawValue || {}, null, 2)
: rawValue;
const settings: EditJsonDialogSettings = {
title: this.field.name,
editable: false,
value
};
this.dialog
.open(EditJsonDialogComponent, {
data: settings,
minWidth: '50%',
minHeight: '50%'
});
}
}

View File

@ -21,10 +21,10 @@ import {
FormFieldTypes, FormFieldTypes,
UnknownWidgetComponent, UnknownWidgetComponent,
UploadWidgetComponent, UploadWidgetComponent,
TextWidgetComponent TextWidgetComponent,
JsonWidgetComponent
} from './../components/widgets/index'; } from './../components/widgets/index';
import { FormRenderingService } from './form-rendering.service'; import { FormRenderingService } from './form-rendering.service';
import { DisplayTextWidgetComponentComponent } from '../components/widgets';
describe('FormRenderingService', () => { describe('FormRenderingService', () => {
@ -126,7 +126,7 @@ describe('FormRenderingService', () => {
it('should resolve Display Text Widget for JSON field type', () => { it('should resolve Display Text Widget for JSON field type', () => {
const resolver = service.getComponentTypeResolver('json'); const resolver = service.getComponentTypeResolver('json');
const type = resolver(null); const type = resolver(null);
expect(type).toBe(DisplayTextWidgetComponentComponent); expect(type).toBe(JsonWidgetComponent);
}); });
}); });

View File

@ -17,61 +17,36 @@
import { DynamicComponentMapper, DynamicComponentResolveFunction, DynamicComponentResolver } from '../../services/dynamic-component-mapper.service'; import { DynamicComponentMapper, DynamicComponentResolveFunction, DynamicComponentResolver } from '../../services/dynamic-component-mapper.service';
import { Injectable, Type } from '@angular/core'; import { Injectable, Type } from '@angular/core';
import * as widgets from './../components/widgets/index';
import {
AmountWidgetComponent,
CheckboxWidgetComponent,
ContainerWidgetComponent,
DateWidgetComponent,
DisplayTextWidgetComponentComponent,
DocumentWidgetComponent,
DropdownWidgetComponent,
DynamicTableWidgetComponent,
FunctionalGroupWidgetComponent,
HyperlinkWidgetComponent,
MultilineTextWidgetComponentComponent,
NumberWidgetComponent,
PeopleWidgetComponent,
RadioButtonsWidgetComponent,
TextWidgetComponent,
TypeaheadWidgetComponent,
UnknownWidgetComponent,
UploadWidgetComponent,
DateTimeWidgetComponent
} from './../components/widgets/index';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
}) })
export class FormRenderingService extends DynamicComponentMapper { export class FormRenderingService extends DynamicComponentMapper {
protected defaultValue: Type<{}> = UnknownWidgetComponent; protected defaultValue: Type<{}> = widgets.UnknownWidgetComponent;
protected types: { [key: string]: DynamicComponentResolveFunction } = { protected types: { [key: string]: DynamicComponentResolveFunction } = {
'text': DynamicComponentResolver.fromType(TextWidgetComponent), 'text': DynamicComponentResolver.fromType(widgets.TextWidgetComponent),
'string': DynamicComponentResolver.fromType(TextWidgetComponent), 'string': DynamicComponentResolver.fromType(widgets.TextWidgetComponent),
'integer': DynamicComponentResolver.fromType(NumberWidgetComponent), 'integer': DynamicComponentResolver.fromType(widgets.NumberWidgetComponent),
'multi-line-text': DynamicComponentResolver.fromType(MultilineTextWidgetComponentComponent), 'multi-line-text': DynamicComponentResolver.fromType(widgets.MultilineTextWidgetComponentComponent),
'boolean': DynamicComponentResolver.fromType(CheckboxWidgetComponent), 'boolean': DynamicComponentResolver.fromType(widgets.CheckboxWidgetComponent),
'dropdown': DynamicComponentResolver.fromType(DropdownWidgetComponent), 'dropdown': DynamicComponentResolver.fromType(widgets.DropdownWidgetComponent),
'date': DynamicComponentResolver.fromType(DateWidgetComponent), 'date': DynamicComponentResolver.fromType(widgets.DateWidgetComponent),
'amount': DynamicComponentResolver.fromType(AmountWidgetComponent), 'amount': DynamicComponentResolver.fromType(widgets.AmountWidgetComponent),
'radio-buttons': DynamicComponentResolver.fromType(RadioButtonsWidgetComponent), 'radio-buttons': DynamicComponentResolver.fromType(widgets.RadioButtonsWidgetComponent),
'hyperlink': DynamicComponentResolver.fromType(HyperlinkWidgetComponent), 'hyperlink': DynamicComponentResolver.fromType(widgets.HyperlinkWidgetComponent),
'readonly-text': DynamicComponentResolver.fromType(DisplayTextWidgetComponentComponent), 'readonly-text': DynamicComponentResolver.fromType(widgets.DisplayTextWidgetComponent),
'json': DynamicComponentResolver.fromType(DisplayTextWidgetComponentComponent), 'json': DynamicComponentResolver.fromType(widgets.JsonWidgetComponent),
'readonly': DynamicComponentResolver.fromType(TextWidgetComponent), 'readonly': DynamicComponentResolver.fromType(widgets.TextWidgetComponent),
'typeahead': DynamicComponentResolver.fromType(TypeaheadWidgetComponent), 'typeahead': DynamicComponentResolver.fromType(widgets.TypeaheadWidgetComponent),
'people': DynamicComponentResolver.fromType(PeopleWidgetComponent), 'people': DynamicComponentResolver.fromType(widgets.PeopleWidgetComponent),
'functional-group': DynamicComponentResolver.fromType(FunctionalGroupWidgetComponent), 'functional-group': DynamicComponentResolver.fromType(widgets.FunctionalGroupWidgetComponent),
'dynamic-table': DynamicComponentResolver.fromType(DynamicTableWidgetComponent), 'dynamic-table': DynamicComponentResolver.fromType(widgets.DynamicTableWidgetComponent),
'container': DynamicComponentResolver.fromType(ContainerWidgetComponent), 'container': DynamicComponentResolver.fromType(widgets.ContainerWidgetComponent),
'group': DynamicComponentResolver.fromType(ContainerWidgetComponent), 'group': DynamicComponentResolver.fromType(widgets.ContainerWidgetComponent),
'document': DynamicComponentResolver.fromType(DocumentWidgetComponent), 'document': DynamicComponentResolver.fromType(widgets.DocumentWidgetComponent),
'upload': DynamicComponentResolver.fromType(UploadWidgetComponent), 'upload': DynamicComponentResolver.fromType(widgets.UploadWidgetComponent),
'datetime': DynamicComponentResolver.fromType(DateTimeWidgetComponent) 'datetime': DynamicComponentResolver.fromType(widgets.DateTimeWidgetComponent)
}; };
constructor() {
super();
}
} }

View File

@ -72,6 +72,10 @@
"CANCEL": "Cancel" "CANCEL": "Cancel"
}, },
"TITLE": "Adding files to zip, this could take a few minutes" "TITLE": "Adding files to zip, this could take a few minutes"
},
"EDIT_JSON": {
"CLOSE": "Close",
"UPDATE": "Update"
} }
}, },
"FILE_DIALOG": { "FILE_DIALOG": {