diff --git a/backend/src/entities/s3-widget/application/data-structures/s3-widget-params.ds.ts b/backend/src/entities/s3-widget/application/data-structures/s3-widget-params.ds.ts index 254c66da6..571b380c4 100644 --- a/backend/src/entities/s3-widget/application/data-structures/s3-widget-params.ds.ts +++ b/backend/src/entities/s3-widget/application/data-structures/s3-widget-params.ds.ts @@ -1,7 +1,8 @@ export interface S3WidgetParams { - bucket: string; - prefix?: string; - region?: string; - aws_access_key_id_secret_name: string; - aws_secret_access_key_secret_name: string; + bucket: string; + prefix?: string; + region?: string; + aws_access_key_id_secret_name: string; + aws_secret_access_key_secret_name: string; + type?: 'file' | 'image'; // 'file' (default) - accepts all files, 'image' - accepts only images } diff --git a/frontend/src/app/components/dashboard/db-table-view/db-table-row-view/db-table-row-view.component.html b/frontend/src/app/components/dashboard/db-table-view/db-table-row-view/db-table-row-view.component.html index f88494d7e..2e915eed2 100644 --- a/frontend/src/app/components/dashboard/db-table-view/db-table-row-view/db-table-row-view.component.html +++ b/frontend/src/app/components/dashboard/db-table-view/db-table-row-view/db-table-row-view.component.html @@ -99,7 +99,9 @@

Preview

[ndcDynamicInputs]="{ key: column.title, value: selectedRow.record[column.title], - widgetStructure: selectedRow.widgets[column.title] + widgetStructure: selectedRow.widgets[column.title], + rowData: selectedRow.record, + primaryKeys: selectedRow.primaryKeys }"> diff --git a/frontend/src/app/components/dashboard/db-table-view/db-table-view.component.html b/frontend/src/app/components/dashboard/db-table-view/db-table-view.component.html index 8dd2adf21..48798d9b4 100644 --- a/frontend/src/app/components/dashboard/db-table-view/db-table-view.component.html +++ b/frontend/src/app/components/dashboard/db-table-view/db-table-view.component.html @@ -254,7 +254,9 @@

{{ displayName }}

[ndcDynamicInputs]="{ key: i, value: element[column], - widgetStructure: tableData.widgets[column] + widgetStructure: tableData.widgets[column], + rowData: element, + primaryKeys: tableData.keyAttributes }" [ndcDynamicOutputs]="{ onCopyToClipboard: { handler: showCopyNotification, args: ['$event'] } diff --git a/frontend/src/app/components/dashboard/db-table-view/db-table-widgets/db-table-widgets.component.ts b/frontend/src/app/components/dashboard/db-table-view/db-table-widgets/db-table-widgets.component.ts index 43b499808..2621fe2f1 100644 --- a/frontend/src/app/components/dashboard/db-table-view/db-table-widgets/db-table-widgets.component.ts +++ b/frontend/src/app/components/dashboard/db-table-view/db-table-widgets/db-table-widgets.component.ts @@ -1,94 +1,88 @@ -import { Angulartics2, Angulartics2OnModule } from 'angulartics2'; +import { CommonModule, Location } from '@angular/common'; import { Component, OnInit } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { MatButtonModule } from '@angular/material/button'; +import { MatDialog, MatDialogModule } from '@angular/material/dialog'; +import { MatIconModule } from '@angular/material/icon'; +import { MatInputModule } from '@angular/material/input'; +import { MatSelectModule } from '@angular/material/select'; +import { Title } from '@angular/platform-browser'; +import { Router, RouterModule } from '@angular/router'; +import { Angulartics2, Angulartics2OnModule } from 'angulartics2'; +import { difference } from 'lodash'; +import { UIwidgets } from 'src/app/consts/record-edit-types'; +import { normalizeTableName } from 'src/app/lib/normalize'; import { TableField, Widget } from 'src/app/models/table'; - +import { CompanyService } from 'src/app/services/company.service'; +import { ConnectionsService } from 'src/app/services/connections.service'; +import { TablesService } from 'src/app/services/tables.service'; +import { UiSettingsService } from 'src/app/services/ui-settings.service'; +import { PlaceholderTableWidgetsComponent } from '../../../skeletons/placeholder-table-widgets/placeholder-table-widgets.component'; import { AlertComponent } from '../../../ui-components/alert/alert.component'; import { BreadcrumbsComponent } from '../../../ui-components/breadcrumbs/breadcrumbs.component'; import { CodeEditComponent } from '../../../ui-components/record-edit-fields/code/code.component'; -import { CommonModule } from '@angular/common'; -import { CompanyService } from 'src/app/services/company.service'; -import { ConnectionsService } from 'src/app/services/connections.service'; -import { FormsModule } from '@angular/forms'; import { ImageEditComponent } from '../../../ui-components/record-edit-fields/image/image.component'; -import { Location } from '@angular/common'; import { LongTextEditComponent } from '../../../ui-components/record-edit-fields/long-text/long-text.component'; import { MarkdownEditComponent } from '../../../ui-components/record-edit-fields/markdown/markdown.component'; -import { MatButtonModule } from '@angular/material/button'; -import { MatDialog } from '@angular/material/dialog'; -import { MatDialogModule } from '@angular/material/dialog'; -import { MatIconModule } from '@angular/material/icon'; -import { MatInputModule } from '@angular/material/input'; -import { MatSelectModule } from '@angular/material/select'; import { PasswordEditComponent } from '../../../ui-components/record-edit-fields/password/password.component'; -import { PlaceholderTableWidgetsComponent } from '../../../skeletons/placeholder-table-widgets/placeholder-table-widgets.component'; -import { Router } from '@angular/router'; -import { RouterModule } from '@angular/router'; import { SelectEditComponent } from '../../../ui-components/record-edit-fields/select/select.component'; -import { TablesService } from 'src/app/services/tables.service'; import { TextEditComponent } from '../../../ui-components/record-edit-fields/text/text.component'; -import { Title } from '@angular/platform-browser'; -import { UIwidgets } from "src/app/consts/record-edit-types"; -import { UiSettingsService } from 'src/app/services/ui-settings.service'; import { WidgetComponent } from './widget/widget.component'; import { WidgetDeleteDialogComponent } from './widget-delete-dialog/widget-delete-dialog.component'; -import { difference } from "lodash"; -import { normalizeTableName } from 'src/app/lib/normalize'; @Component({ - selector: 'app-db-table-widgets', - templateUrl: './db-table-widgets.component.html', - styleUrls: ['./db-table-widgets.component.css'], - imports: [ - CommonModule, - FormsModule, - MatButtonModule, - MatDialogModule, - MatIconModule, - MatInputModule, - MatSelectModule, - RouterModule, - AlertComponent, - PlaceholderTableWidgetsComponent, - BreadcrumbsComponent, - PasswordEditComponent, - ImageEditComponent, - CodeEditComponent, - MarkdownEditComponent, - WidgetComponent, - TextEditComponent, - LongTextEditComponent, - SelectEditComponent, - Angulartics2OnModule - ], + selector: 'app-db-table-widgets', + templateUrl: './db-table-widgets.component.html', + styleUrls: ['./db-table-widgets.component.css'], + imports: [ + CommonModule, + FormsModule, + MatButtonModule, + MatDialogModule, + MatIconModule, + MatInputModule, + MatSelectModule, + RouterModule, + AlertComponent, + PlaceholderTableWidgetsComponent, + BreadcrumbsComponent, + PasswordEditComponent, + ImageEditComponent, + CodeEditComponent, + MarkdownEditComponent, + WidgetComponent, + TextEditComponent, + LongTextEditComponent, + SelectEditComponent, + Angulartics2OnModule, + ], }) export class DbTableWidgetsComponent implements OnInit { - - public connectionID: string | null = null; - public tableName: string | null = null; - public dispalyTableName: string; - public fields: string[] = []; - public fieldsCount: number; - public widgets: Widget[] = null; - public widgetTypes = Object.keys(UIwidgets); - public submitting: boolean = false; - public widgetsWithSettings: string[]; - public codeEditorTheme: 'vs' | 'vs-dark' = 'vs-dark'; - public paramsEditorOptions = { - minimap: { enabled: false }, - lineNumbersMinChars: 3, - folding: false, - automaticLayout: true, - scrollBeyondLastLine: false, - wordWrap: 'on', - }; - public widgetCodeEample = `

Why UI Customization Matters in Admin Panels

+ public connectionID: string | null = null; + public tableName: string | null = null; + public dispalyTableName: string; + public fields: string[] = []; + public fieldsCount: number; + public widgets: Widget[] = null; + public widgetTypes = Object.keys(UIwidgets); + public submitting: boolean = false; + public widgetsWithSettings: string[]; + public codeEditorTheme: 'vs' | 'vs-dark' = 'vs-dark'; + public paramsEditorOptions = { + minimap: { enabled: false }, + lineNumbersMinChars: 3, + folding: false, + automaticLayout: true, + scrollBeyondLastLine: false, + wordWrap: 'on', + }; + public widgetCodeEample = `

Why UI Customization Matters in Admin Panels

A well-designed admin panel isn’t just about managing data — it’s about making that data easier to understand and interact with. By customizing how each field is displayed, you can turn raw database values into meaningful, user-friendly interfaces that save time and reduce errors.

`; - // JSON5-formatted default params - public defaultParams = { - Boolean: -`// Display "Yes/No" buttons with configurable options: + // JSON5-formatted default params + public defaultParams = { + Boolean: `// Display "Yes/No" buttons with configurable options: // - allow_null: Use "false" to require selection, "true" if field can be left unspecified // - invert_colors: Swap the color scheme (typically green=Yes, red=No becomes red=Yes, green=No) @@ -97,14 +91,13 @@ export class DbTableWidgetsComponent implements OnInit { "invert_colors": false } `, - Code: -`// provide language of code to highlight: 'html', 'css', 'typescript', 'yaml', 'markdown' + Code: `// provide language of code to highlight: 'html', 'css', 'typescript', 'yaml', 'markdown' // example: { "language": "html" } `, - Color: `// Optional: Specify output format for color values + Color: `// Optional: Specify output format for color values // Supported formats: "hex", "hex_hash" (default), "rgb", "hsl" // Example configuration: @@ -117,42 +110,40 @@ export class DbTableWidgetsComponent implements OnInit { // - "hex_hash": Display as "#FF5733" (default) // - "rgb": Display as "rgb(255, 87, 51)" // - "hsl": Display as "hsl(9, 100%, 60%)"`, - Country: `// Configure country display options + Country: `// Configure country display options // Example: { "show_flag": true, "allow_null": false } `, - Date: `// Configure date display options + Date: `// Configure date display options // formatDistanceWithinHours: Shows relative time (e.g., "2 hours ago") for dates within the specified hours // Default: 0 hours. Set to 0 to disable relative time display { "formatDistanceWithinHours": 0 }`, - DateTime: `// Configure datetime display options + DateTime: `// Configure datetime display options // formatDistanceWithinHours: Shows relative time (e.g., "2 hours ago") for dates within the specified hours // Default: 0 hours. Set to 0 to disable relative time display { "formatDistanceWithinHours": 0 }`, - Default: `// No settings required`, - File: -`// provide type of file: 'hex', 'base64' or 'file' + Default: `// No settings required`, + File: `// provide type of file: 'hex', 'base64' or 'file' // example: { "type": "hex" } `, - Foreign_key: `// Provide settings for foreign key widget + Foreign_key: `// Provide settings for foreign key widget { "column_name": "", // copy the name of the column you selected "referenced_column_name": "", "referenced_table_name": "" } `, - Image: -`// provide image height in px to dispaly in table + Image: `// provide image height in px to dispaly in table // prefix: optional URL prefix to prepend to image source // example: { @@ -160,15 +151,15 @@ export class DbTableWidgetsComponent implements OnInit { "prefix": "https://example.com/images/" } `, - JSON: `// No settings required`, - Language: `// Configure language display options + JSON: `// No settings required`, + Language: `// Configure language display options // show_flag: Display country flag emoji next to language name // Example: { "show_flag": true }`, - Markdown: `// No settings required`, - Money: `// Configure money widget settings + Markdown: `// No settings required`, + Money: `// Configure money widget settings // example: { "default_currency": "USD", @@ -176,7 +167,7 @@ export class DbTableWidgetsComponent implements OnInit { "allow_negative": true } `, - Number: `// Configure number display with unit conversion and threshold validation + Number: `// Configure number display with unit conversion and threshold validation // Example units: "bytes", "meters", "seconds", "grams" // threshold_min/threshold_max: Values outside these limits will be highlighted { @@ -184,8 +175,7 @@ export class DbTableWidgetsComponent implements OnInit { "threshold_min": null, "threshold_max": null }`, - Password: -`// provide algorithm to encrypt your password, one of: + Password: `// provide algorithm to encrypt your password, one of: //sha1, sha3, sha224, sha256, sha512, sha384, bcrypt, scrypt, argon2, pbkdf2. // example: @@ -195,8 +185,7 @@ export class DbTableWidgetsComponent implements OnInit { } `, - Phone: -`// Configure international phone number widget + Phone: `// Configure international phone number widget // example: { "preferred_countries": ["US", "GB", "CA"], @@ -204,7 +193,7 @@ export class DbTableWidgetsComponent implements OnInit { "phone_validation": true } `, - Range: `// Configure the minimum, maximum and step values for the range + Range: `// Configure the minimum, maximum and step values for the range // Default: min = 0, max = 100, step = 1 { "min": 0, @@ -212,9 +201,8 @@ export class DbTableWidgetsComponent implements OnInit { "step": 1 } `, - Readonly: `// No settings required`, - Select: -`// provide array of options to map database value (key 'value') in human readable value (key 'label'); + Readonly: `// No settings required`, + Select: `// provide array of options to map database value (key 'value') in human readable value (key 'label'); // for example: // AK => Alaska, // CA => California @@ -239,7 +227,7 @@ export class DbTableWidgetsComponent implements OnInit { } ] }`, - String: `// Optional validation for string values + String: `// Optional validation for string values // validate: Any validator.js method (e.g., "isEmail", "isURL", "isUUID", "isJSON", "isAlpha", "isNumeric") // Full list: isEmail, isURL, isMACAddress, isIP, isIPRange, isFQDN, isBoolean, isIBAN, isBIC, // isAlpha, isAlphanumeric, isNumeric, isPort, isLowercase, isUppercase, isAscii, isBase64, @@ -252,25 +240,25 @@ export class DbTableWidgetsComponent implements OnInit { "validate": null, "regex": null }`, - Textarea: `// provide number of strings to show. + Textarea: `// provide number of strings to show. { "rows": 5 }`, - Time: `// No settings required`, - Timezone: `// Configure timezone widget options + Time: `// No settings required`, + Timezone: `// Configure timezone widget options // Uses Intl API to populate timezone list automatically // allow_null: Allow empty/null value selection { "allow_null": false } `, - URL: `// prefix: optional URL prefix to prepend to the href + URL: `// prefix: optional URL prefix to prepend to the href // example: { "prefix": "https://example.com/" } `, - UUID: `// Configure UUID generation version and parameters + UUID: `// Configure UUID generation version and parameters // Available versions: "v1", "v3", "v4" (default), "v5", "v7" // For v3/v5: provide namespace and optionally name { @@ -279,171 +267,175 @@ export class DbTableWidgetsComponent implements OnInit { "name": "" } `, - S3: `// Configure AWS S3 widget for file storage + S3: `// Configure AWS S3 widget for file storage // bucket: S3 bucket name (required) // prefix: Optional path prefix for uploaded files // region: AWS region (default: us-east-1) +// type: "file" (default) - accepts all file types, "image" - accepts only images // aws_access_key_id_secret_name: Slug of the secret containing AWS Access Key ID // aws_secret_access_key_secret_name: Slug of the secret containing AWS Secret Access Key -// Note: Create secrets in Settings -> Secrets before configuring this widget +// +// ⚠️ IMPORTANT: DO NOT INCLUDE AWS SECRETS DIRECTLY IN WIDGET SETTINGS! +// Store your AWS credentials as secrets in Settings -> Secrets first, +// then reference them by their slug names in the settings below. { "bucket": "your-bucket-name", "prefix": "uploads/", "region": "us-east-1", + "type": "file", "aws_access_key_id_secret_name": "aws-access-key-id", "aws_secret_access_key_secret_name": "aws-secret-access-key" } `, - } + }; - constructor( - private _connections: ConnectionsService, - private _tables: TablesService, - private _location: Location, - private _uiSettings: UiSettingsService, - private _company: CompanyService, - public dialog: MatDialog, - public router: Router, - private title: Title, - private angulartics2: Angulartics2, - ) {} + constructor( + private _connections: ConnectionsService, + private _tables: TablesService, + private _location: Location, + private _uiSettings: UiSettingsService, + private _company: CompanyService, + public dialog: MatDialog, + public router: Router, + private title: Title, + private angulartics2: Angulartics2, + ) {} - ngOnInit(): void { - this.connectionID = this._connections.currentConnectionID; - this.tableName = this._tables.currentTableName; - this.widgetsWithSettings = Object - .entries(this.defaultParams) - .filter(([_key, value]) => value !== '// No settings required') - .map(widgetDefault => widgetDefault[0]); + ngOnInit(): void { + this.connectionID = this._connections.currentConnectionID; + this.tableName = this._tables.currentTableName; + this.widgetsWithSettings = Object.entries(this.defaultParams) + .filter(([_key, value]) => value !== '// No settings required') + .map((widgetDefault) => widgetDefault[0]); - this._tables.fetchTableStructure(this.connectionID, this.tableName) - .subscribe(res => { - this.fieldsCount = res.structure.length; - this.fields = res.structure.map((field: TableField) => field.column_name); - this.dispalyTableName = res.display_name || normalizeTableName(this.tableName); - this.title.setTitle(`${this.dispalyTableName} - Field display | ${this._company.companyTabTitle || 'Rocketadmin'}`); - this.getWidgets(); - }) - this.codeEditorTheme = this._uiSettings.editorTheme; - } + this._tables.fetchTableStructure(this.connectionID, this.tableName).subscribe((res) => { + this.fieldsCount = res.structure.length; + this.fields = res.structure.map((field: TableField) => field.column_name); + this.dispalyTableName = res.display_name || normalizeTableName(this.tableName); + this.title.setTitle( + `${this.dispalyTableName} - Field display | ${this._company.companyTabTitle || 'Rocketadmin'}`, + ); + this.getWidgets(); + }); + this.codeEditorTheme = this._uiSettings.editorTheme; + } - get currentConnection() { - return this._connections.currentConnection; - } + get currentConnection() { + return this._connections.currentConnection; + } - getCrumbs(name: string) { - return [ - { - label: name, - link: `/dashboard/${this.connectionID}` - }, - { - label: this.dispalyTableName, - link: `/dashboard/${this.connectionID}/${this.tableName}` - }, - { - label: 'UI Widgets', - link: null - } - ] - } + getCrumbs(name: string) { + return [ + { + label: name, + link: `/dashboard/${this.connectionID}`, + }, + { + label: this.dispalyTableName, + link: `/dashboard/${this.connectionID}/${this.tableName}`, + }, + { + label: 'UI Widgets', + link: null, + }, + ]; + } - goBack() { - this._location.back(); - } + goBack() { + this._location.back(); + } - addNewWidget() { - this.widgets.push({ - field_name: '', - widget_type: 'Default', - widget_params: '// No settings required', - name: '', - description: '' - }); - } + addNewWidget() { + this.widgets.push({ + field_name: '', + widget_type: 'Default', + widget_params: '// No settings required', + name: '', + description: '', + }); + } - selectWidgetField(column_name: string) { - this.fields.splice(this.fields.indexOf(column_name), 1) - } + selectWidgetField(column_name: string) { + this.fields.splice(this.fields.indexOf(column_name), 1); + } - widgetTypeChange(fieldName) { - let currentWidget = this.widgets.find(widget => widget.field_name === fieldName); - currentWidget.widget_params = this.defaultParams[currentWidget.widget_type || 'Default']; + widgetTypeChange(fieldName) { + let currentWidget = this.widgets.find((widget) => widget.field_name === fieldName); + currentWidget.widget_params = this.defaultParams[currentWidget.widget_type || 'Default']; - this.widgetParamsChange({fieldName: currentWidget.field_name, value: currentWidget.widget_params}); - } + this.widgetParamsChange({ fieldName: currentWidget.field_name, value: currentWidget.widget_params }); + } - isReadOnly(type: string) { - return !this.widgetsWithSettings.includes(type); - } + isReadOnly(type: string) { + return !this.widgetsWithSettings.includes(type); + } - widgetParamsChange(e: { - fieldName: string, - value: any - }) { - let currentWidget = this.widgets.find(widget => widget.field_name === e.fieldName); - currentWidget.widget_params = e.value; - } + widgetParamsChange(e: { fieldName: string; value: any }) { + let currentWidget = this.widgets.find((widget) => widget.field_name === e.fieldName); + currentWidget.widget_params = e.value; + } - openDeleteWidgetDialog(widgetFieldName: string) { - const dialogRef = this.dialog.open(WidgetDeleteDialogComponent, { - width: '25em', - data: widgetFieldName - }) + openDeleteWidgetDialog(widgetFieldName: string) { + const dialogRef = this.dialog.open(WidgetDeleteDialogComponent, { + width: '25em', + data: widgetFieldName, + }); - dialogRef.afterClosed().subscribe(action => { - if (action === 'delete') { - this.fields.push(widgetFieldName); - this.widgets = this.widgets.filter((widget) => widget.field_name !== widgetFieldName); - this.updateWidgets(true); - } - }) - } + dialogRef.afterClosed().subscribe((action) => { + if (action === 'delete') { + this.fields.push(widgetFieldName); + this.widgets = this.widgets.filter((widget) => widget.field_name !== widgetFieldName); + this.updateWidgets(true); + } + }); + } - openClearAllConfirmation() { - const dialogRef = this.dialog.open(WidgetDeleteDialogComponent, { - width: '25em' - }) + openClearAllConfirmation() { + const dialogRef = this.dialog.open(WidgetDeleteDialogComponent, { + width: '25em', + }); - dialogRef.afterClosed().subscribe(action => { - if (action === 'delete') { - const widgetsToDelete = this.widgets.map(widget => widget.field_name); - this.fields = [...this.fields, ...widgetsToDelete]; - this.widgets = []; - this.updateWidgets(true); - } - }) - } + dialogRef.afterClosed().subscribe((action) => { + if (action === 'delete') { + const widgetsToDelete = this.widgets.map((widget) => widget.field_name); + this.fields = [...this.fields, ...widgetsToDelete]; + this.widgets = []; + this.updateWidgets(true); + } + }); + } - getWidgets() { - this._tables.fetchTableWidgets(this.connectionID, this.tableName) - .subscribe(res => { - const currentWidgetTypes = res.map((widget: Widget) => widget.field_name); - this.fields = difference(this.fields, currentWidgetTypes); - res.forEach((widget: Widget) => { - if (widget.widget_type === '') widget.widget_type = 'Default'; - }) - this.widgets = res; - }); - } + getWidgets() { + this._tables.fetchTableWidgets(this.connectionID, this.tableName).subscribe((res) => { + const currentWidgetTypes = res.map((widget: Widget) => widget.field_name); + this.fields = difference(this.fields, currentWidgetTypes); + res.forEach((widget: Widget) => { + if (widget.widget_type === '') widget.widget_type = 'Default'; + }); + this.widgets = res; + }); + } - updateWidgets(afterDeleteAll?: boolean) { - this.submitting = true; + updateWidgets(afterDeleteAll?: boolean) { + this.submitting = true; - this.widgets.forEach(widget => { - if (widget.widget_type === 'Default') widget.widget_type = ''; - }); + this.widgets.forEach((widget) => { + if (widget.widget_type === 'Default') widget.widget_type = ''; + }); - this._tables.updateTableWidgets(this.connectionID, this.tableName, this.widgets) - .subscribe(() => { - this.submitting = false; - this.angulartics2.eventTrack.next({ - action: 'Widgets: widgets are updated successfully' - }); - if (!afterDeleteAll) this.router.navigate([`/dashboard/${this.connectionID}/${this.tableName}`]); - }, - undefined, - () => {this.submitting = false}); - } + this._tables.updateTableWidgets(this.connectionID, this.tableName, this.widgets).subscribe( + () => { + this.submitting = false; + this.angulartics2.eventTrack.next({ + action: 'Widgets: widgets are updated successfully', + }); + if (!afterDeleteAll) this.router.navigate([`/dashboard/${this.connectionID}/${this.tableName}`]); + }, + undefined, + () => { + this.submitting = false; + }, + ); + } } diff --git a/frontend/src/app/components/ui-components/record-edit-fields/s3/s3.component.html b/frontend/src/app/components/ui-components/record-edit-fields/s3/s3.component.html index a124a4e5f..7b72cf9a5 100644 --- a/frontend/src/app/components/ui-components/record-edit-fields/s3/s3.component.html +++ b/frontend/src/app/components/ui-components/record-edit-fields/s3/s3.component.html @@ -8,7 +8,7 @@
- + +
diff --git a/frontend/src/app/components/ui-components/table-display-fields/s3/s3.component.ts b/frontend/src/app/components/ui-components/table-display-fields/s3/s3.component.ts new file mode 100644 index 000000000..dee15b2ea --- /dev/null +++ b/frontend/src/app/components/ui-components/table-display-fields/s3/s3.component.ts @@ -0,0 +1,99 @@ +import { ClipboardModule } from '@angular/cdk/clipboard'; +import { CommonModule } from '@angular/common'; +import { Component, OnInit } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { ConnectionsService } from 'src/app/services/connections.service'; +import { S3Service } from 'src/app/services/s3.service'; +import { TablesService } from 'src/app/services/tables.service'; +import { BaseTableDisplayFieldComponent } from '../base-table-display-field/base-table-display-field.component'; + +interface S3WidgetParams { + bucket: string; + prefix?: string; + region?: string; + aws_access_key_id_secret_name: string; + aws_secret_access_key_secret_name: string; + type?: 'file' | 'image'; +} + +@Component({ + selector: 'app-s3-display', + templateUrl: './s3.component.html', + styleUrls: ['../base-table-display-field/base-table-display-field.component.css', './s3.component.css'], + imports: [CommonModule, ClipboardModule, MatButtonModule, MatIconModule, MatProgressSpinnerModule, MatTooltipModule], +}) +export class S3DisplayComponent extends BaseTableDisplayFieldComponent implements OnInit { + public params: S3WidgetParams; + public previewUrl: string | null = null; + public isLoading: boolean = false; + + private connectionId: string; + private tableName: string; + + constructor( + private s3Service: S3Service, + private connectionsService: ConnectionsService, + private tablesService: TablesService, + ) { + super(); + } + + ngOnInit(): void { + this.connectionId = this.connectionsService.currentConnectionID; + this.tableName = this.tablesService.currentTableName; + this._parseWidgetParams(); + + if (this.value && this.isImageType && this.rowPrimaryKey) { + this._loadPreview(); + } + } + + get isImageType(): boolean { + return this.params?.type === 'image'; + } + + get rowPrimaryKey(): Record | null { + if (!this.rowData || !this.primaryKeys) return null; + + const primaryKey: Record = {}; + for (const pk of this.primaryKeys) { + primaryKey[pk.column_name] = this.rowData[pk.column_name]; + } + return primaryKey; + } + + private _parseWidgetParams(): void { + if (this.widgetStructure?.widget_params) { + try { + this.params = + typeof this.widgetStructure.widget_params === 'string' + ? JSON.parse(this.widgetStructure.widget_params) + : this.widgetStructure.widget_params; + } catch (e) { + console.error('Error parsing S3 widget params:', e); + } + } + } + + private _loadPreview(): void { + const primaryKey = this.rowPrimaryKey; + if (!this.value || !this.connectionId || !this.tableName || !primaryKey) return; + + this.isLoading = true; + + this.s3Service + .getFileUrl(this.connectionId, this.tableName, this.widgetStructure.field_name, primaryKey) + .subscribe({ + next: (response) => { + this.previewUrl = response.url; + this.isLoading = false; + }, + error: () => { + this.isLoading = false; + }, + }); + } +} diff --git a/frontend/src/app/consts/record-view-types.ts b/frontend/src/app/consts/record-view-types.ts index fface9b22..3e4375a80 100644 --- a/frontend/src/app/consts/record-view-types.ts +++ b/frontend/src/app/consts/record-view-types.ts @@ -1,4 +1,6 @@ import { BooleanRecordViewComponent } from 'src/app/components/ui-components/record-view-fields/boolean/boolean.component'; +import { LongTextRecordViewComponent } from 'src/app/components/ui-components/record-view-fields/long-text/long-text.component'; +import { TextRecordViewComponent } from 'src/app/components/ui-components/record-view-fields/text/text.component'; import { CodeRecordViewComponent } from '../components/ui-components/record-view-fields/code/code.component'; import { ColorRecordViewComponent } from '../components/ui-components/record-view-fields/color/color.component'; import { CountryRecordViewComponent } from '../components/ui-components/record-view-fields/country/country.component'; @@ -10,7 +12,6 @@ import { IdRecordViewComponent } from '../components/ui-components/record-view-f import { ImageRecordViewComponent } from '../components/ui-components/record-view-fields/image/image.component'; import { JsonEditorRecordViewComponent } from '../components/ui-components/record-view-fields/json-editor/json-editor.component'; import { LanguageRecordViewComponent } from '../components/ui-components/record-view-fields/language/language.component'; -import { LongTextRecordViewComponent } from 'src/app/components/ui-components/record-view-fields/long-text/long-text.component'; import { MarkdownRecordViewComponent } from '../components/ui-components/record-view-fields/markdown/markdown.component'; import { MoneyRecordViewComponent } from '../components/ui-components/record-view-fields/money/money.component'; import { NumberRecordViewComponent } from '../components/ui-components/record-view-fields/number/number.component'; @@ -18,322 +19,323 @@ import { PasswordRecordViewComponent } from '../components/ui-components/record- import { PhoneRecordViewComponent } from '../components/ui-components/record-view-fields/phone/phone.component'; import { PointRecordViewComponent } from '../components/ui-components/record-view-fields/point/point.component'; import { RangeRecordViewComponent } from '../components/ui-components/record-view-fields/range/range.component'; +import { S3RecordViewComponent } from '../components/ui-components/record-view-fields/s3/s3.component'; import { SelectRecordViewComponent } from '../components/ui-components/record-view-fields/select/select.component'; import { StaticTextRecordViewComponent } from '../components/ui-components/record-view-fields/static-text/static-text.component'; -import { TextRecordViewComponent } from 'src/app/components/ui-components/record-view-fields/text/text.component'; -import { TimeIntervalRecordViewComponent } from '../components/ui-components/record-view-fields/time-interval/time-interval.component'; import { TimeRecordViewComponent } from '../components/ui-components/record-view-fields/time/time.component'; +import { TimeIntervalRecordViewComponent } from '../components/ui-components/record-view-fields/time-interval/time-interval.component'; import { TimezoneRecordViewComponent } from '../components/ui-components/record-view-fields/timezone/timezone.component'; import { UrlRecordViewComponent } from '../components/ui-components/record-view-fields/url/url.component'; import { UuidRecordViewComponent } from '../components/ui-components/record-view-fields/uuid/uuid.component'; export const UIwidgets = { - Default: '', - Boolean: BooleanRecordViewComponent, - Date: DateRecordViewComponent, - Time: TimeRecordViewComponent, - DateTime: DateTimeRecordViewComponent, - JSON: JsonEditorRecordViewComponent, - Language: LanguageRecordViewComponent, - Markdown: MarkdownRecordViewComponent, - Textarea: LongTextRecordViewComponent, - String: TextRecordViewComponent, - Readonly: StaticTextRecordViewComponent, - Number: NumberRecordViewComponent, - Select: SelectRecordViewComponent, - Password: PasswordRecordViewComponent, - File: FileRecordViewComponent, - Code: CodeRecordViewComponent, - Image: ImageRecordViewComponent, - URL: UrlRecordViewComponent, - Country: CountryRecordViewComponent, - Phone: PhoneRecordViewComponent, - Money: MoneyRecordViewComponent, - Foreign_key: ForeignKeyRecordViewComponent, - Color: ColorRecordViewComponent, - UUID: UuidRecordViewComponent, - Range: RangeRecordViewComponent, - Timezone: TimezoneRecordViewComponent -} + Default: '', + Boolean: BooleanRecordViewComponent, + Date: DateRecordViewComponent, + Time: TimeRecordViewComponent, + DateTime: DateTimeRecordViewComponent, + JSON: JsonEditorRecordViewComponent, + Language: LanguageRecordViewComponent, + Markdown: MarkdownRecordViewComponent, + Textarea: LongTextRecordViewComponent, + String: TextRecordViewComponent, + Readonly: StaticTextRecordViewComponent, + Number: NumberRecordViewComponent, + Select: SelectRecordViewComponent, + Password: PasswordRecordViewComponent, + File: FileRecordViewComponent, + Code: CodeRecordViewComponent, + Image: ImageRecordViewComponent, + URL: UrlRecordViewComponent, + Country: CountryRecordViewComponent, + Phone: PhoneRecordViewComponent, + Money: MoneyRecordViewComponent, + Foreign_key: ForeignKeyRecordViewComponent, + Color: ColorRecordViewComponent, + UUID: UuidRecordViewComponent, + Range: RangeRecordViewComponent, + Timezone: TimezoneRecordViewComponent, + S3: S3RecordViewComponent, +}; export const recordViewFieldTypes = { - postgres: { - // numbers (number) - real: NumberRecordViewComponent, - "double precision": NumberRecordViewComponent, - smallint: NumberRecordViewComponent, - integer: NumberRecordViewComponent, - bigint: NumberRecordViewComponent, - numeric: NumberRecordViewComponent, - - //boolean (checkbox) - boolean: BooleanRecordViewComponent, - - //datetime (datepicker) - "timestamp without time zone": DateTimeRecordViewComponent, - "timestamp with time zone": DateTimeRecordViewComponent, - "time without time zone": TimeRecordViewComponent, - "time with time zone": TimeRecordViewComponent, - date: DateRecordViewComponent, - abstime: DateTimeRecordViewComponent, - realtime: DateTimeRecordViewComponent, - interval: TimeIntervalRecordViewComponent, - - // short text (text) - "character varying": TextRecordViewComponent, - macaddr: TextRecordViewComponent, - macaddr8: TextRecordViewComponent, - cidr: TextRecordViewComponent, - inet: TextRecordViewComponent, - uuid: UuidRecordViewComponent, - - //long text (textarea) - text: LongTextRecordViewComponent, - xml: LongTextRecordViewComponent, - - //select (select) - enum: SelectRecordViewComponent, - - // json-editor - json: JsonEditorRecordViewComponent, - jsonb: JsonEditorRecordViewComponent, - ARRAY: JsonEditorRecordViewComponent, - - //file - bytea: FileRecordViewComponent, - - //etc - money: MoneyRecordViewComponent, - - //mess (math) - point: PointRecordViewComponent, - line: TextRecordViewComponent, - circle: TextRecordViewComponent, - path: TextRecordViewComponent, - box: TextRecordViewComponent, - lseg: TextRecordViewComponent, - - "foreign key": ForeignKeyRecordViewComponent - }, - - mysql: { - // numbers (number) - tinyint: NumberRecordViewComponent, - smallint: NumberRecordViewComponent, - mediumint: NumberRecordViewComponent, - int: NumberRecordViewComponent, - bigint: NumberRecordViewComponent, - decimal: NumberRecordViewComponent, - float: NumberRecordViewComponent, - double: NumberRecordViewComponent, - year: NumberRecordViewComponent, - - //boolean (radiogroup) - boolean: BooleanRecordViewComponent, - - //datetime (datepicker) - date: DateRecordViewComponent, - time: TimeRecordViewComponent, - datetime: DateTimeRecordViewComponent, - timestamp: DateTimeRecordViewComponent, - - // short text (text) - char: TextRecordViewComponent, - varchar: TextRecordViewComponent, - - //long text (textarea) - text: LongTextRecordViewComponent, - tinytext: LongTextRecordViewComponent, - mediumtext: LongTextRecordViewComponent, - longtext: LongTextRecordViewComponent, - - json: JsonEditorRecordViewComponent, //json-editor - - //select (select) - enum: SelectRecordViewComponent, - - //file - binary: FileRecordViewComponent, - varbinary: FileRecordViewComponent, - blob: FileRecordViewComponent, - tinyblob: FileRecordViewComponent, - mediumblob: FileRecordViewComponent, - longblob: FileRecordViewComponent, - - //etc - set: TextRecordViewComponent, - - "foreign key": ForeignKeyRecordViewComponent - }, - - oracledb: { - // numbers (number) - NUMBER: NumberRecordViewComponent, - FLOAT: NumberRecordViewComponent, - BINARY_FLOAT: NumberRecordViewComponent, - BINARY_DOUBLE: NumberRecordViewComponent, - "INTERVAL YEAR": NumberRecordViewComponent, - "INTERVAL DAY": NumberRecordViewComponent, - - //datetime (datepicker) - DATE: DateRecordViewComponent, - TIMESTAMP: DateTimeRecordViewComponent, - - // short text (text) - CHAR: TextRecordViewComponent, - NCHAR: TextRecordViewComponent, - CLOB: TextRecordViewComponent, - NCLOB: TextRecordViewComponent, - VARCHAR2: TextRecordViewComponent, - VARCHAR: TextRecordViewComponent, - NVARCHAR2: TextRecordViewComponent, - - //file - BLOB: FileRecordViewComponent, - BFILE: FileRecordViewComponent, - RAW: FileRecordViewComponent, - "LONG RAW": FileRecordViewComponent, - LONG: FileRecordViewComponent, - - "foreign key": ForeignKeyRecordViewComponent - }, - - mssql: { - // numbers (number) - bigint: NumberRecordViewComponent, - int: NumberRecordViewComponent, - smallint: NumberRecordViewComponent, - tinyint: NumberRecordViewComponent, - decimal: NumberRecordViewComponent, - bitdecimal: NumberRecordViewComponent, - numeric: NumberRecordViewComponent, - real: NumberRecordViewComponent, - - // short text (text) - uniqueidentifier: UuidRecordViewComponent, - char: TextRecordViewComponent, - varchar: TextRecordViewComponent, - - //long text (textarea) - text: LongTextRecordViewComponent, - nchar: LongTextRecordViewComponent, - nvarchar: LongTextRecordViewComponent, - ntext: LongTextRecordViewComponent, - - //datetime (datepicker) - date: DateRecordViewComponent, - datetime: DateTimeRecordViewComponent, - smalldatetime: DateTimeRecordViewComponent, - timestamp: DateTimeRecordViewComponent, - - //file - binary: FileRecordViewComponent, - varbinary: FileRecordViewComponent, - image: ImageRecordViewComponent, - - // etc - money: MoneyRecordViewComponent, - smallmoney: MoneyRecordViewComponent, - - "foreign key": ForeignKeyRecordViewComponent - }, - mongodb: { - // numbers (number) - number: NumberRecordViewComponent, - double: NumberRecordViewComponent, - int32: NumberRecordViewComponent, - long: NumberRecordViewComponent, - decimal128: NumberRecordViewComponent, - - //boolean (radiogroup) - boolean: BooleanRecordViewComponent, - - //datetime (datepicker) - date: DateRecordViewComponent, - timestamp: DateTimeRecordViewComponent, - - // short text (text) - string: TextRecordViewComponent, - regexp: TextRecordViewComponent, - objectid: TextRecordViewComponent, - - //file - binary: FileRecordViewComponent, - - //json - object: JsonEditorRecordViewComponent, - array: JsonEditorRecordViewComponent, - - //etc - unknown: TextRecordViewComponent, - - "foreign key": ForeignKeyRecordViewComponent - }, - dynamodb: { - string: TextRecordViewComponent, - number: NumberRecordViewComponent, - boolean: BooleanRecordViewComponent, - null: StaticTextRecordViewComponent, - array: JsonEditorRecordViewComponent, - json: JsonEditorRecordViewComponent, - binary: FileRecordViewComponent, - }, - cassandra: { - int: NumberRecordViewComponent, - bigint: NumberRecordViewComponent, - varint: NumberRecordViewComponent, - decimal: NumberRecordViewComponent, - float: NumberRecordViewComponent, - double: NumberRecordViewComponent, - - boolean: BooleanRecordViewComponent, - - timeuuid: IdRecordViewComponent, - - timestamp: DateTimeRecordViewComponent, - date: DateRecordViewComponent, - time: TimeRecordViewComponent, - - uuid: UuidRecordViewComponent, - varchar: TextRecordViewComponent, - inet: TextRecordViewComponent, - ascii: TextRecordViewComponent, - text: LongTextRecordViewComponent, - - list: JsonEditorRecordViewComponent, - map: JsonEditorRecordViewComponent, - set: JsonEditorRecordViewComponent, - }, - redis: { - string: TextRecordViewComponent, - integer: NumberRecordViewComponent, - decimal: NumberRecordViewComponent, - boolean: BooleanRecordViewComponent, - array: JsonEditorRecordViewComponent, - json: JsonEditorRecordViewComponent, - }, - elasticsearch: { - string: TextRecordViewComponent, - number: NumberRecordViewComponent, - boolean: BooleanRecordViewComponent, - date: DateRecordViewComponent, - object: JsonEditorRecordViewComponent, - array: JsonEditorRecordViewComponent, - binary: FileRecordViewComponent, - }, - clickhouse: { - string: TextRecordViewComponent, - uuid: UuidRecordViewComponent, - boolean: BooleanRecordViewComponent, - integer: NumberRecordViewComponent, - bigint: NumberRecordViewComponent, - float: NumberRecordViewComponent, - double: NumberRecordViewComponent, - decimal: NumberRecordViewComponent, - date: DateRecordViewComponent, - datetime: DateTimeRecordViewComponent, - json: JsonEditorRecordViewComponent, - object: JsonEditorRecordViewComponent, - array: JsonEditorRecordViewComponent, - } -} + postgres: { + // numbers (number) + real: NumberRecordViewComponent, + 'double precision': NumberRecordViewComponent, + smallint: NumberRecordViewComponent, + integer: NumberRecordViewComponent, + bigint: NumberRecordViewComponent, + numeric: NumberRecordViewComponent, + + //boolean (checkbox) + boolean: BooleanRecordViewComponent, + + //datetime (datepicker) + 'timestamp without time zone': DateTimeRecordViewComponent, + 'timestamp with time zone': DateTimeRecordViewComponent, + 'time without time zone': TimeRecordViewComponent, + 'time with time zone': TimeRecordViewComponent, + date: DateRecordViewComponent, + abstime: DateTimeRecordViewComponent, + realtime: DateTimeRecordViewComponent, + interval: TimeIntervalRecordViewComponent, + + // short text (text) + 'character varying': TextRecordViewComponent, + macaddr: TextRecordViewComponent, + macaddr8: TextRecordViewComponent, + cidr: TextRecordViewComponent, + inet: TextRecordViewComponent, + uuid: UuidRecordViewComponent, + + //long text (textarea) + text: LongTextRecordViewComponent, + xml: LongTextRecordViewComponent, + + //select (select) + enum: SelectRecordViewComponent, + + // json-editor + json: JsonEditorRecordViewComponent, + jsonb: JsonEditorRecordViewComponent, + ARRAY: JsonEditorRecordViewComponent, + + //file + bytea: FileRecordViewComponent, + + //etc + money: MoneyRecordViewComponent, + + //mess (math) + point: PointRecordViewComponent, + line: TextRecordViewComponent, + circle: TextRecordViewComponent, + path: TextRecordViewComponent, + box: TextRecordViewComponent, + lseg: TextRecordViewComponent, + + 'foreign key': ForeignKeyRecordViewComponent, + }, + + mysql: { + // numbers (number) + tinyint: NumberRecordViewComponent, + smallint: NumberRecordViewComponent, + mediumint: NumberRecordViewComponent, + int: NumberRecordViewComponent, + bigint: NumberRecordViewComponent, + decimal: NumberRecordViewComponent, + float: NumberRecordViewComponent, + double: NumberRecordViewComponent, + year: NumberRecordViewComponent, + + //boolean (radiogroup) + boolean: BooleanRecordViewComponent, + + //datetime (datepicker) + date: DateRecordViewComponent, + time: TimeRecordViewComponent, + datetime: DateTimeRecordViewComponent, + timestamp: DateTimeRecordViewComponent, + + // short text (text) + char: TextRecordViewComponent, + varchar: TextRecordViewComponent, + + //long text (textarea) + text: LongTextRecordViewComponent, + tinytext: LongTextRecordViewComponent, + mediumtext: LongTextRecordViewComponent, + longtext: LongTextRecordViewComponent, + + json: JsonEditorRecordViewComponent, //json-editor + + //select (select) + enum: SelectRecordViewComponent, + + //file + binary: FileRecordViewComponent, + varbinary: FileRecordViewComponent, + blob: FileRecordViewComponent, + tinyblob: FileRecordViewComponent, + mediumblob: FileRecordViewComponent, + longblob: FileRecordViewComponent, + + //etc + set: TextRecordViewComponent, + + 'foreign key': ForeignKeyRecordViewComponent, + }, + + oracledb: { + // numbers (number) + NUMBER: NumberRecordViewComponent, + FLOAT: NumberRecordViewComponent, + BINARY_FLOAT: NumberRecordViewComponent, + BINARY_DOUBLE: NumberRecordViewComponent, + 'INTERVAL YEAR': NumberRecordViewComponent, + 'INTERVAL DAY': NumberRecordViewComponent, + + //datetime (datepicker) + DATE: DateRecordViewComponent, + TIMESTAMP: DateTimeRecordViewComponent, + + // short text (text) + CHAR: TextRecordViewComponent, + NCHAR: TextRecordViewComponent, + CLOB: TextRecordViewComponent, + NCLOB: TextRecordViewComponent, + VARCHAR2: TextRecordViewComponent, + VARCHAR: TextRecordViewComponent, + NVARCHAR2: TextRecordViewComponent, + + //file + BLOB: FileRecordViewComponent, + BFILE: FileRecordViewComponent, + RAW: FileRecordViewComponent, + 'LONG RAW': FileRecordViewComponent, + LONG: FileRecordViewComponent, + + 'foreign key': ForeignKeyRecordViewComponent, + }, + + mssql: { + // numbers (number) + bigint: NumberRecordViewComponent, + int: NumberRecordViewComponent, + smallint: NumberRecordViewComponent, + tinyint: NumberRecordViewComponent, + decimal: NumberRecordViewComponent, + bitdecimal: NumberRecordViewComponent, + numeric: NumberRecordViewComponent, + real: NumberRecordViewComponent, + + // short text (text) + uniqueidentifier: UuidRecordViewComponent, + char: TextRecordViewComponent, + varchar: TextRecordViewComponent, + + //long text (textarea) + text: LongTextRecordViewComponent, + nchar: LongTextRecordViewComponent, + nvarchar: LongTextRecordViewComponent, + ntext: LongTextRecordViewComponent, + + //datetime (datepicker) + date: DateRecordViewComponent, + datetime: DateTimeRecordViewComponent, + smalldatetime: DateTimeRecordViewComponent, + timestamp: DateTimeRecordViewComponent, + + //file + binary: FileRecordViewComponent, + varbinary: FileRecordViewComponent, + image: ImageRecordViewComponent, + + // etc + money: MoneyRecordViewComponent, + smallmoney: MoneyRecordViewComponent, + + 'foreign key': ForeignKeyRecordViewComponent, + }, + mongodb: { + // numbers (number) + number: NumberRecordViewComponent, + double: NumberRecordViewComponent, + int32: NumberRecordViewComponent, + long: NumberRecordViewComponent, + decimal128: NumberRecordViewComponent, + + //boolean (radiogroup) + boolean: BooleanRecordViewComponent, + + //datetime (datepicker) + date: DateRecordViewComponent, + timestamp: DateTimeRecordViewComponent, + + // short text (text) + string: TextRecordViewComponent, + regexp: TextRecordViewComponent, + objectid: TextRecordViewComponent, + + //file + binary: FileRecordViewComponent, + + //json + object: JsonEditorRecordViewComponent, + array: JsonEditorRecordViewComponent, + + //etc + unknown: TextRecordViewComponent, + + 'foreign key': ForeignKeyRecordViewComponent, + }, + dynamodb: { + string: TextRecordViewComponent, + number: NumberRecordViewComponent, + boolean: BooleanRecordViewComponent, + null: StaticTextRecordViewComponent, + array: JsonEditorRecordViewComponent, + json: JsonEditorRecordViewComponent, + binary: FileRecordViewComponent, + }, + cassandra: { + int: NumberRecordViewComponent, + bigint: NumberRecordViewComponent, + varint: NumberRecordViewComponent, + decimal: NumberRecordViewComponent, + float: NumberRecordViewComponent, + double: NumberRecordViewComponent, + + boolean: BooleanRecordViewComponent, + + timeuuid: IdRecordViewComponent, + + timestamp: DateTimeRecordViewComponent, + date: DateRecordViewComponent, + time: TimeRecordViewComponent, + + uuid: UuidRecordViewComponent, + varchar: TextRecordViewComponent, + inet: TextRecordViewComponent, + ascii: TextRecordViewComponent, + text: LongTextRecordViewComponent, + + list: JsonEditorRecordViewComponent, + map: JsonEditorRecordViewComponent, + set: JsonEditorRecordViewComponent, + }, + redis: { + string: TextRecordViewComponent, + integer: NumberRecordViewComponent, + decimal: NumberRecordViewComponent, + boolean: BooleanRecordViewComponent, + array: JsonEditorRecordViewComponent, + json: JsonEditorRecordViewComponent, + }, + elasticsearch: { + string: TextRecordViewComponent, + number: NumberRecordViewComponent, + boolean: BooleanRecordViewComponent, + date: DateRecordViewComponent, + object: JsonEditorRecordViewComponent, + array: JsonEditorRecordViewComponent, + binary: FileRecordViewComponent, + }, + clickhouse: { + string: TextRecordViewComponent, + uuid: UuidRecordViewComponent, + boolean: BooleanRecordViewComponent, + integer: NumberRecordViewComponent, + bigint: NumberRecordViewComponent, + float: NumberRecordViewComponent, + double: NumberRecordViewComponent, + decimal: NumberRecordViewComponent, + date: DateRecordViewComponent, + datetime: DateTimeRecordViewComponent, + json: JsonEditorRecordViewComponent, + object: JsonEditorRecordViewComponent, + array: JsonEditorRecordViewComponent, + }, +}; diff --git a/frontend/src/app/consts/table-display-types.ts b/frontend/src/app/consts/table-display-types.ts index 3d7bd039c..29fd6069c 100644 --- a/frontend/src/app/consts/table-display-types.ts +++ b/frontend/src/app/consts/table-display-types.ts @@ -1,4 +1,6 @@ import { BooleanDisplayComponent } from 'src/app/components/ui-components/table-display-fields/boolean/boolean.component'; +import { LongTextDisplayComponent } from 'src/app/components/ui-components/table-display-fields/long-text/long-text.component'; +import { TextDisplayComponent } from 'src/app/components/ui-components/table-display-fields/text/text.component'; import { CodeDisplayComponent } from '../components/ui-components/table-display-fields/code/code.component'; import { ColorDisplayComponent } from '../components/ui-components/table-display-fields/color/color.component'; import { CountryDisplayComponent } from '../components/ui-components/table-display-fields/country/country.component'; @@ -10,7 +12,6 @@ import { IdDisplayComponent } from '../components/ui-components/table-display-fi import { ImageDisplayComponent } from '../components/ui-components/table-display-fields/image/image.component'; import { JsonEditorDisplayComponent } from '../components/ui-components/table-display-fields/json-editor/json-editor.component'; import { LanguageDisplayComponent } from '../components/ui-components/table-display-fields/language/language.component'; -import { LongTextDisplayComponent } from 'src/app/components/ui-components/table-display-fields/long-text/long-text.component'; import { MarkdownDisplayComponent } from '../components/ui-components/table-display-fields/markdown/markdown.component'; import { MoneyDisplayComponent } from '../components/ui-components/table-display-fields/money/money.component'; import { NumberDisplayComponent } from '../components/ui-components/table-display-fields/number/number.component'; @@ -18,9 +19,9 @@ import { PasswordDisplayComponent } from '../components/ui-components/table-disp import { PhoneDisplayComponent } from '../components/ui-components/table-display-fields/phone/phone.component'; import { PointDisplayComponent } from '../components/ui-components/table-display-fields/point/point.component'; import { RangeDisplayComponent } from '../components/ui-components/table-display-fields/range/range.component'; +import { S3DisplayComponent } from '../components/ui-components/table-display-fields/s3/s3.component'; import { SelectDisplayComponent } from '../components/ui-components/table-display-fields/select/select.component'; import { StaticTextDisplayComponent } from '../components/ui-components/table-display-fields/static-text/static-text.component'; -import { TextDisplayComponent } from 'src/app/components/ui-components/table-display-fields/text/text.component'; import { TimeDisplayComponent } from '../components/ui-components/table-display-fields/time/time.component'; import { TimeIntervalDisplayComponent } from '../components/ui-components/table-display-fields/time-interval/time-interval.component'; import { TimezoneDisplayComponent } from '../components/ui-components/table-display-fields/timezone/timezone.component'; @@ -28,312 +29,313 @@ import { UrlDisplayComponent } from '../components/ui-components/table-display-f import { UuidDisplayComponent } from '../components/ui-components/table-display-fields/uuid/uuid.component'; export const UIwidgets = { - Default: '', - Boolean: BooleanDisplayComponent, - Code: CodeDisplayComponent, - Color: ColorDisplayComponent, - Country: CountryDisplayComponent, - Date: DateDisplayComponent, - DateTime: DateTimeDisplayComponent, - File: FileDisplayComponent, - Foreign_key: ForeignKeyDisplayComponent, - Image: ImageDisplayComponent, - JSON: JsonEditorDisplayComponent, - Language: LanguageDisplayComponent, - Markdown: MarkdownDisplayComponent, - Money: MoneyDisplayComponent, - Number: NumberDisplayComponent, - Password: PasswordDisplayComponent, - Phone: PhoneDisplayComponent, - Range: RangeDisplayComponent, - Readonly: StaticTextDisplayComponent, - Select: SelectDisplayComponent, - String: TextDisplayComponent, - Textarea: LongTextDisplayComponent, - Time: TimeDisplayComponent, - Timezone: TimezoneDisplayComponent, - URL: UrlDisplayComponent, - UUID: UuidDisplayComponent, -} + Default: '', + Boolean: BooleanDisplayComponent, + Code: CodeDisplayComponent, + Color: ColorDisplayComponent, + Country: CountryDisplayComponent, + Date: DateDisplayComponent, + DateTime: DateTimeDisplayComponent, + File: FileDisplayComponent, + Foreign_key: ForeignKeyDisplayComponent, + Image: ImageDisplayComponent, + JSON: JsonEditorDisplayComponent, + Language: LanguageDisplayComponent, + Markdown: MarkdownDisplayComponent, + Money: MoneyDisplayComponent, + Number: NumberDisplayComponent, + Password: PasswordDisplayComponent, + Phone: PhoneDisplayComponent, + Range: RangeDisplayComponent, + Readonly: StaticTextDisplayComponent, + Select: SelectDisplayComponent, + String: TextDisplayComponent, + Textarea: LongTextDisplayComponent, + Time: TimeDisplayComponent, + Timezone: TimezoneDisplayComponent, + URL: UrlDisplayComponent, + UUID: UuidDisplayComponent, + S3: S3DisplayComponent, +}; export const tableDisplayTypes = { - postgres: { - // numbers (number) - real: NumberDisplayComponent, - "double precision": NumberDisplayComponent, - smallint: NumberDisplayComponent, - integer: NumberDisplayComponent, - bigint: NumberDisplayComponent, - numeric: NumberDisplayComponent, - - //boolean (checkbox) - boolean: BooleanDisplayComponent, - - //datetime (datepicker) - "timestamp without time zone": DateTimeDisplayComponent, - "timestamp with time zone": DateTimeDisplayComponent, - "time without time zone": TimeDisplayComponent, - "time with time zone": TimeDisplayComponent, - date: DateDisplayComponent, - abstime: DateTimeDisplayComponent, - realtime: DateTimeDisplayComponent, - interval: TimeIntervalDisplayComponent, - - // short text (text) - "character varying": TextDisplayComponent, - macaddr: TextDisplayComponent, - macaddr8: TextDisplayComponent, - cidr: TextDisplayComponent, - inet: TextDisplayComponent, - uuid: UuidDisplayComponent, - - //long text (textarea) - text: LongTextDisplayComponent, - xml: LongTextDisplayComponent, - - //select (select) - enum: SelectDisplayComponent, - - // json-editor - json: JsonEditorDisplayComponent, - jsonb: JsonEditorDisplayComponent, - ARRAY: JsonEditorDisplayComponent, - - //file - bytea: FileDisplayComponent, - - //etc - money: MoneyDisplayComponent, - - //mess (math) - point: PointDisplayComponent, - line: TextDisplayComponent, - circle: TextDisplayComponent, - path: TextDisplayComponent, - box: TextDisplayComponent, - lseg: TextDisplayComponent, - - "foreign key": ForeignKeyDisplayComponent - }, - - mysql: { - // numbers (number) - tinyint: NumberDisplayComponent, - smallint: NumberDisplayComponent, - mediumint: NumberDisplayComponent, - int: NumberDisplayComponent, - bigint: NumberDisplayComponent, - decimal: NumberDisplayComponent, - float: NumberDisplayComponent, - double: NumberDisplayComponent, - year: NumberDisplayComponent, - - //boolean (radiogroup) - boolean: BooleanDisplayComponent, - - //datetime (datepicker) - date: DateDisplayComponent, - time: TimeDisplayComponent, - datetime: DateTimeDisplayComponent, - timestamp: DateTimeDisplayComponent, - - // short text (text) - char: TextDisplayComponent, - varchar: TextDisplayComponent, - - //long text (textarea) - text: LongTextDisplayComponent, - tinytext: LongTextDisplayComponent, - mediumtext: LongTextDisplayComponent, - longtext: LongTextDisplayComponent, - - json: JsonEditorDisplayComponent, //json-editor - - //select (select) - enum: SelectDisplayComponent, - - //file - binary: FileDisplayComponent, - varbinary: FileDisplayComponent, - blob: FileDisplayComponent, - tinyblob: FileDisplayComponent, - mediumblob: FileDisplayComponent, - longblob: FileDisplayComponent, - - //etc - set: TextDisplayComponent, - - "foreign key": ForeignKeyDisplayComponent - }, - - oracledb: { - // numbers (number) - NUMBER: NumberDisplayComponent, - FLOAT: NumberDisplayComponent, - BINARY_FLOAT: NumberDisplayComponent, - BINARY_DOUBLE: NumberDisplayComponent, - "INTERVAL YEAR": NumberDisplayComponent, - "INTERVAL DAY": NumberDisplayComponent, - - //datetime (datepicker) - DATE: DateDisplayComponent, - TIMESTAMP: DateTimeDisplayComponent, - - // short text (text) - CHAR: TextDisplayComponent, - NCHAR: TextDisplayComponent, - CLOB: TextDisplayComponent, - NCLOB: TextDisplayComponent, - VARCHAR2: TextDisplayComponent, - VARCHAR: TextDisplayComponent, - NVARCHAR2: TextDisplayComponent, - - //file - BLOB: FileDisplayComponent, - BFILE: FileDisplayComponent, - RAW: FileDisplayComponent, - "LONG RAW": FileDisplayComponent, - LONG: FileDisplayComponent, - - "foreign key": ForeignKeyDisplayComponent - }, - - mssql: { - // numbers (number) - bigint: NumberDisplayComponent, - int: NumberDisplayComponent, - smallint: NumberDisplayComponent, - tinyint: NumberDisplayComponent, - decimal: NumberDisplayComponent, - bitdecimal: NumberDisplayComponent, - numeric: NumberDisplayComponent, - real: NumberDisplayComponent, - - // short text (text) - uniqueidentifier: UuidDisplayComponent, - char: TextDisplayComponent, - varchar: TextDisplayComponent, - - //long text (textarea) - text: LongTextDisplayComponent, - nchar: LongTextDisplayComponent, - nvarchar: LongTextDisplayComponent, - ntext: LongTextDisplayComponent, - - //datetime (datepicker) - date: DateDisplayComponent, - datetime: DateTimeDisplayComponent, - smalldatetime: DateTimeDisplayComponent, - timestamp: DateTimeDisplayComponent, - - //file - binary: FileDisplayComponent, - varbinary: FileDisplayComponent, - image: ImageDisplayComponent, - - // etc - money: MoneyDisplayComponent, - smallmoney: MoneyDisplayComponent, - - "foreign key": ForeignKeyDisplayComponent - }, - mongodb: { - // numbers (number) - number: NumberDisplayComponent, - double: NumberDisplayComponent, - int32: NumberDisplayComponent, - long: NumberDisplayComponent, - decimal128: NumberDisplayComponent, - - //boolean (radiogroup) - boolean: BooleanDisplayComponent, - - //datetime (datepicker) - date: DateDisplayComponent, - timestamp: DateTimeDisplayComponent, - - // short text (text) - string: TextDisplayComponent, - regexp: TextDisplayComponent, - objectid: TextDisplayComponent, - - //file - binary: FileDisplayComponent, - - //json - object: JsonEditorDisplayComponent, - array: JsonEditorDisplayComponent, - - //etc - unknown: TextDisplayComponent, - - "foreign key": ForeignKeyDisplayComponent - }, - dynamodb: { - string: TextDisplayComponent, - number: NumberDisplayComponent, - boolean: BooleanDisplayComponent, - null: StaticTextDisplayComponent, - array: JsonEditorDisplayComponent, - json: JsonEditorDisplayComponent, - binary: FileDisplayComponent, - }, - cassandra: { - int: NumberDisplayComponent, - bigint: NumberDisplayComponent, - varint: NumberDisplayComponent, - decimal: NumberDisplayComponent, - float: NumberDisplayComponent, - double: NumberDisplayComponent, - - boolean: BooleanDisplayComponent, - - timeuuid: IdDisplayComponent, - - timestamp: DateTimeDisplayComponent, - date: DateDisplayComponent, - time: TimeDisplayComponent, - - uuid: UuidDisplayComponent, - varchar: TextDisplayComponent, - inet: TextDisplayComponent, - ascii: TextDisplayComponent, - text: LongTextDisplayComponent, - - list: JsonEditorDisplayComponent, - map: JsonEditorDisplayComponent, - set: JsonEditorDisplayComponent, - }, - redis: { - string: TextDisplayComponent, - integer: NumberDisplayComponent, - decimal: NumberDisplayComponent, - boolean: BooleanDisplayComponent, - array: JsonEditorDisplayComponent, - json: JsonEditorDisplayComponent, - }, - elasticsearch: { - string: TextDisplayComponent, - number: NumberDisplayComponent, - boolean: BooleanDisplayComponent, - date: DateDisplayComponent, - object: JsonEditorDisplayComponent, - array: JsonEditorDisplayComponent, - binary: FileDisplayComponent, - }, - clickhouse: { - string: TextDisplayComponent, - uuid: UuidDisplayComponent, - boolean: BooleanDisplayComponent, - integer: NumberDisplayComponent, - bigint: NumberDisplayComponent, - float: NumberDisplayComponent, - double: NumberDisplayComponent, - decimal: NumberDisplayComponent, - date: DateDisplayComponent, - datetime: DateTimeDisplayComponent, - json: JsonEditorDisplayComponent, - object: JsonEditorDisplayComponent, - array: JsonEditorDisplayComponent, - } -} + postgres: { + // numbers (number) + real: NumberDisplayComponent, + 'double precision': NumberDisplayComponent, + smallint: NumberDisplayComponent, + integer: NumberDisplayComponent, + bigint: NumberDisplayComponent, + numeric: NumberDisplayComponent, + + //boolean (checkbox) + boolean: BooleanDisplayComponent, + + //datetime (datepicker) + 'timestamp without time zone': DateTimeDisplayComponent, + 'timestamp with time zone': DateTimeDisplayComponent, + 'time without time zone': TimeDisplayComponent, + 'time with time zone': TimeDisplayComponent, + date: DateDisplayComponent, + abstime: DateTimeDisplayComponent, + realtime: DateTimeDisplayComponent, + interval: TimeIntervalDisplayComponent, + + // short text (text) + 'character varying': TextDisplayComponent, + macaddr: TextDisplayComponent, + macaddr8: TextDisplayComponent, + cidr: TextDisplayComponent, + inet: TextDisplayComponent, + uuid: UuidDisplayComponent, + + //long text (textarea) + text: LongTextDisplayComponent, + xml: LongTextDisplayComponent, + + //select (select) + enum: SelectDisplayComponent, + + // json-editor + json: JsonEditorDisplayComponent, + jsonb: JsonEditorDisplayComponent, + ARRAY: JsonEditorDisplayComponent, + + //file + bytea: FileDisplayComponent, + + //etc + money: MoneyDisplayComponent, + + //mess (math) + point: PointDisplayComponent, + line: TextDisplayComponent, + circle: TextDisplayComponent, + path: TextDisplayComponent, + box: TextDisplayComponent, + lseg: TextDisplayComponent, + + 'foreign key': ForeignKeyDisplayComponent, + }, + + mysql: { + // numbers (number) + tinyint: NumberDisplayComponent, + smallint: NumberDisplayComponent, + mediumint: NumberDisplayComponent, + int: NumberDisplayComponent, + bigint: NumberDisplayComponent, + decimal: NumberDisplayComponent, + float: NumberDisplayComponent, + double: NumberDisplayComponent, + year: NumberDisplayComponent, + + //boolean (radiogroup) + boolean: BooleanDisplayComponent, + + //datetime (datepicker) + date: DateDisplayComponent, + time: TimeDisplayComponent, + datetime: DateTimeDisplayComponent, + timestamp: DateTimeDisplayComponent, + + // short text (text) + char: TextDisplayComponent, + varchar: TextDisplayComponent, + + //long text (textarea) + text: LongTextDisplayComponent, + tinytext: LongTextDisplayComponent, + mediumtext: LongTextDisplayComponent, + longtext: LongTextDisplayComponent, + + json: JsonEditorDisplayComponent, //json-editor + + //select (select) + enum: SelectDisplayComponent, + + //file + binary: FileDisplayComponent, + varbinary: FileDisplayComponent, + blob: FileDisplayComponent, + tinyblob: FileDisplayComponent, + mediumblob: FileDisplayComponent, + longblob: FileDisplayComponent, + + //etc + set: TextDisplayComponent, + + 'foreign key': ForeignKeyDisplayComponent, + }, + + oracledb: { + // numbers (number) + NUMBER: NumberDisplayComponent, + FLOAT: NumberDisplayComponent, + BINARY_FLOAT: NumberDisplayComponent, + BINARY_DOUBLE: NumberDisplayComponent, + 'INTERVAL YEAR': NumberDisplayComponent, + 'INTERVAL DAY': NumberDisplayComponent, + + //datetime (datepicker) + DATE: DateDisplayComponent, + TIMESTAMP: DateTimeDisplayComponent, + + // short text (text) + CHAR: TextDisplayComponent, + NCHAR: TextDisplayComponent, + CLOB: TextDisplayComponent, + NCLOB: TextDisplayComponent, + VARCHAR2: TextDisplayComponent, + VARCHAR: TextDisplayComponent, + NVARCHAR2: TextDisplayComponent, + + //file + BLOB: FileDisplayComponent, + BFILE: FileDisplayComponent, + RAW: FileDisplayComponent, + 'LONG RAW': FileDisplayComponent, + LONG: FileDisplayComponent, + + 'foreign key': ForeignKeyDisplayComponent, + }, + + mssql: { + // numbers (number) + bigint: NumberDisplayComponent, + int: NumberDisplayComponent, + smallint: NumberDisplayComponent, + tinyint: NumberDisplayComponent, + decimal: NumberDisplayComponent, + bitdecimal: NumberDisplayComponent, + numeric: NumberDisplayComponent, + real: NumberDisplayComponent, + + // short text (text) + uniqueidentifier: UuidDisplayComponent, + char: TextDisplayComponent, + varchar: TextDisplayComponent, + + //long text (textarea) + text: LongTextDisplayComponent, + nchar: LongTextDisplayComponent, + nvarchar: LongTextDisplayComponent, + ntext: LongTextDisplayComponent, + + //datetime (datepicker) + date: DateDisplayComponent, + datetime: DateTimeDisplayComponent, + smalldatetime: DateTimeDisplayComponent, + timestamp: DateTimeDisplayComponent, + + //file + binary: FileDisplayComponent, + varbinary: FileDisplayComponent, + image: ImageDisplayComponent, + + // etc + money: MoneyDisplayComponent, + smallmoney: MoneyDisplayComponent, + + 'foreign key': ForeignKeyDisplayComponent, + }, + mongodb: { + // numbers (number) + number: NumberDisplayComponent, + double: NumberDisplayComponent, + int32: NumberDisplayComponent, + long: NumberDisplayComponent, + decimal128: NumberDisplayComponent, + + //boolean (radiogroup) + boolean: BooleanDisplayComponent, + + //datetime (datepicker) + date: DateDisplayComponent, + timestamp: DateTimeDisplayComponent, + + // short text (text) + string: TextDisplayComponent, + regexp: TextDisplayComponent, + objectid: TextDisplayComponent, + + //file + binary: FileDisplayComponent, + + //json + object: JsonEditorDisplayComponent, + array: JsonEditorDisplayComponent, + + //etc + unknown: TextDisplayComponent, + + 'foreign key': ForeignKeyDisplayComponent, + }, + dynamodb: { + string: TextDisplayComponent, + number: NumberDisplayComponent, + boolean: BooleanDisplayComponent, + null: StaticTextDisplayComponent, + array: JsonEditorDisplayComponent, + json: JsonEditorDisplayComponent, + binary: FileDisplayComponent, + }, + cassandra: { + int: NumberDisplayComponent, + bigint: NumberDisplayComponent, + varint: NumberDisplayComponent, + decimal: NumberDisplayComponent, + float: NumberDisplayComponent, + double: NumberDisplayComponent, + + boolean: BooleanDisplayComponent, + + timeuuid: IdDisplayComponent, + + timestamp: DateTimeDisplayComponent, + date: DateDisplayComponent, + time: TimeDisplayComponent, + + uuid: UuidDisplayComponent, + varchar: TextDisplayComponent, + inet: TextDisplayComponent, + ascii: TextDisplayComponent, + text: LongTextDisplayComponent, + + list: JsonEditorDisplayComponent, + map: JsonEditorDisplayComponent, + set: JsonEditorDisplayComponent, + }, + redis: { + string: TextDisplayComponent, + integer: NumberDisplayComponent, + decimal: NumberDisplayComponent, + boolean: BooleanDisplayComponent, + array: JsonEditorDisplayComponent, + json: JsonEditorDisplayComponent, + }, + elasticsearch: { + string: TextDisplayComponent, + number: NumberDisplayComponent, + boolean: BooleanDisplayComponent, + date: DateDisplayComponent, + object: JsonEditorDisplayComponent, + array: JsonEditorDisplayComponent, + binary: FileDisplayComponent, + }, + clickhouse: { + string: TextDisplayComponent, + uuid: UuidDisplayComponent, + boolean: BooleanDisplayComponent, + integer: NumberDisplayComponent, + bigint: NumberDisplayComponent, + float: NumberDisplayComponent, + double: NumberDisplayComponent, + decimal: NumberDisplayComponent, + date: DateDisplayComponent, + datetime: DateTimeDisplayComponent, + json: JsonEditorDisplayComponent, + object: JsonEditorDisplayComponent, + array: JsonEditorDisplayComponent, + }, +};