From 69ce370fe11d711991408278a6e8670b69bbb4e9 Mon Sep 17 00:00:00 2001 From: Lyubov Voloshko Date: Sun, 10 Aug 2025 15:36:26 +0300 Subject: [PATCH 1/2] record view: crate components and data types-components map --- .../base-record-view-field.component.css | 26 ++ .../base-record-view-field.component.html | 1 + .../base-record-view-field.component.ts | 20 ++ .../binary-data-caption.component.html | 3 + .../binary-data-caption.component.ts | 16 + .../boolean/boolean.component.css | 27 ++ .../boolean/boolean.component.html | 7 + .../boolean/boolean.component.ts | 19 ++ .../code/code.component.css | 12 + .../code/code.component.html | 11 + .../record-view-fields/code/code.component.ts | 17 + .../color/color.component.css | 17 + .../color/color.component.html | 18 ++ .../color/color.component.ts | 53 ++++ .../country/country.component.css | 27 ++ .../country/country.component.html | 14 + .../country/country.component.ts | 53 ++++ .../date-time/date-time.component.css | 1 + .../date-time/date-time.component.html | 11 + .../date-time/date-time.component.ts | 37 +++ .../date/date.component.css | 1 + .../date/date.component.html | 11 + .../record-view-fields/date/date.component.ts | 37 +++ .../file/file.component.css | 4 + .../file/file.component.html | 3 + .../record-view-fields/file/file.component.ts | 34 ++ .../foreign-key/foreign-key.component.css | 27 ++ .../foreign-key/foreign-key.component.html | 21 ++ .../foreign-key/foreign-key.component.ts | 37 +++ .../record-view-fields/id/id.component.css | 9 + .../record-view-fields/id/id.component.html | 12 + .../record-view-fields/id/id.component.ts | 18 ++ .../image/image.component.css | 10 + .../image/image.component.html | 15 + .../image/image.component.ts | 26 ++ .../json-editor/json-editor.component.css | 6 + .../json-editor/json-editor.component.html | 11 + .../json-editor/json-editor.component.ts | 27 ++ .../long-text/long-text.component.css | 4 + .../long-text/long-text.component.html | 12 + .../long-text/long-text.component.ts | 19 ++ .../money/money.component.css | 1 + .../money/money.component.html | 13 + .../money/money.component.ts | 62 ++++ .../number/number.component.css | 1 + .../number/number.component.html | 11 + .../number/number.component.ts | 40 +++ .../password/password.component.css | 1 + .../password/password.component.html | 3 + .../password/password.component.ts | 17 + .../phone/phone.component.css | 20 ++ .../phone/phone.component.html | 15 + .../phone/phone.component.ts | 61 ++++ .../point/point.component.css | 21 ++ .../point/point.component.html | 11 + .../point/point.component.ts | 48 +++ .../select/select.component.css | 1 + .../select/select.component.html | 11 + .../select/select.component.ts | 43 +++ .../static-text/static-text.component.css | 1 + .../static-text/static-text.component.html | 11 + .../static-text/static-text.component.ts | 18 ++ .../text/text.component.css | 0 .../text/text.component.html | 11 + .../record-view-fields/text/text.component.ts | 18 ++ .../time-interval/time-interval.component.css | 0 .../time-interval.component.html | 11 + .../time-interval/time-interval.component.ts | 42 +++ .../time/time.component.css | 1 + .../time/time.component.html | 11 + .../record-view-fields/time/time.component.ts | 42 +++ .../record-view-fields/url/url.component.css | 14 + .../record-view-fields/url/url.component.html | 20 ++ .../record-view-fields/url/url.component.ts | 28 ++ .../uuid/uuid.component.css | 40 +++ .../uuid/uuid.component.html | 16 + .../record-view-fields/uuid/uuid.component.ts | 17 + frontend/src/app/consts/record-view-types.ts | 299 ++++++++++++++++++ 78 files changed, 1714 insertions(+) create mode 100644 frontend/src/app/components/ui-components/record-view-fields/base-record-view-field/base-record-view-field.component.css create mode 100644 frontend/src/app/components/ui-components/record-view-fields/base-record-view-field/base-record-view-field.component.html create mode 100644 frontend/src/app/components/ui-components/record-view-fields/base-record-view-field/base-record-view-field.component.ts create mode 100644 frontend/src/app/components/ui-components/record-view-fields/binary-data-caption/binary-data-caption.component.html create mode 100644 frontend/src/app/components/ui-components/record-view-fields/binary-data-caption/binary-data-caption.component.ts create mode 100644 frontend/src/app/components/ui-components/record-view-fields/boolean/boolean.component.css create mode 100644 frontend/src/app/components/ui-components/record-view-fields/boolean/boolean.component.html create mode 100644 frontend/src/app/components/ui-components/record-view-fields/boolean/boolean.component.ts create mode 100644 frontend/src/app/components/ui-components/record-view-fields/code/code.component.css create mode 100644 frontend/src/app/components/ui-components/record-view-fields/code/code.component.html create mode 100644 frontend/src/app/components/ui-components/record-view-fields/code/code.component.ts create mode 100644 frontend/src/app/components/ui-components/record-view-fields/color/color.component.css create mode 100644 frontend/src/app/components/ui-components/record-view-fields/color/color.component.html create mode 100644 frontend/src/app/components/ui-components/record-view-fields/color/color.component.ts create mode 100644 frontend/src/app/components/ui-components/record-view-fields/country/country.component.css create mode 100644 frontend/src/app/components/ui-components/record-view-fields/country/country.component.html create mode 100644 frontend/src/app/components/ui-components/record-view-fields/country/country.component.ts create mode 100644 frontend/src/app/components/ui-components/record-view-fields/date-time/date-time.component.css create mode 100644 frontend/src/app/components/ui-components/record-view-fields/date-time/date-time.component.html create mode 100644 frontend/src/app/components/ui-components/record-view-fields/date-time/date-time.component.ts create mode 100644 frontend/src/app/components/ui-components/record-view-fields/date/date.component.css create mode 100644 frontend/src/app/components/ui-components/record-view-fields/date/date.component.html create mode 100644 frontend/src/app/components/ui-components/record-view-fields/date/date.component.ts create mode 100644 frontend/src/app/components/ui-components/record-view-fields/file/file.component.css create mode 100644 frontend/src/app/components/ui-components/record-view-fields/file/file.component.html create mode 100644 frontend/src/app/components/ui-components/record-view-fields/file/file.component.ts create mode 100644 frontend/src/app/components/ui-components/record-view-fields/foreign-key/foreign-key.component.css create mode 100644 frontend/src/app/components/ui-components/record-view-fields/foreign-key/foreign-key.component.html create mode 100644 frontend/src/app/components/ui-components/record-view-fields/foreign-key/foreign-key.component.ts create mode 100644 frontend/src/app/components/ui-components/record-view-fields/id/id.component.css create mode 100644 frontend/src/app/components/ui-components/record-view-fields/id/id.component.html create mode 100644 frontend/src/app/components/ui-components/record-view-fields/id/id.component.ts create mode 100644 frontend/src/app/components/ui-components/record-view-fields/image/image.component.css create mode 100644 frontend/src/app/components/ui-components/record-view-fields/image/image.component.html create mode 100644 frontend/src/app/components/ui-components/record-view-fields/image/image.component.ts create mode 100644 frontend/src/app/components/ui-components/record-view-fields/json-editor/json-editor.component.css create mode 100644 frontend/src/app/components/ui-components/record-view-fields/json-editor/json-editor.component.html create mode 100644 frontend/src/app/components/ui-components/record-view-fields/json-editor/json-editor.component.ts create mode 100644 frontend/src/app/components/ui-components/record-view-fields/long-text/long-text.component.css create mode 100644 frontend/src/app/components/ui-components/record-view-fields/long-text/long-text.component.html create mode 100644 frontend/src/app/components/ui-components/record-view-fields/long-text/long-text.component.ts create mode 100644 frontend/src/app/components/ui-components/record-view-fields/money/money.component.css create mode 100644 frontend/src/app/components/ui-components/record-view-fields/money/money.component.html create mode 100644 frontend/src/app/components/ui-components/record-view-fields/money/money.component.ts create mode 100644 frontend/src/app/components/ui-components/record-view-fields/number/number.component.css create mode 100644 frontend/src/app/components/ui-components/record-view-fields/number/number.component.html create mode 100644 frontend/src/app/components/ui-components/record-view-fields/number/number.component.ts create mode 100644 frontend/src/app/components/ui-components/record-view-fields/password/password.component.css create mode 100644 frontend/src/app/components/ui-components/record-view-fields/password/password.component.html create mode 100644 frontend/src/app/components/ui-components/record-view-fields/password/password.component.ts create mode 100644 frontend/src/app/components/ui-components/record-view-fields/phone/phone.component.css create mode 100644 frontend/src/app/components/ui-components/record-view-fields/phone/phone.component.html create mode 100644 frontend/src/app/components/ui-components/record-view-fields/phone/phone.component.ts create mode 100644 frontend/src/app/components/ui-components/record-view-fields/point/point.component.css create mode 100644 frontend/src/app/components/ui-components/record-view-fields/point/point.component.html create mode 100644 frontend/src/app/components/ui-components/record-view-fields/point/point.component.ts create mode 100644 frontend/src/app/components/ui-components/record-view-fields/select/select.component.css create mode 100644 frontend/src/app/components/ui-components/record-view-fields/select/select.component.html create mode 100644 frontend/src/app/components/ui-components/record-view-fields/select/select.component.ts create mode 100644 frontend/src/app/components/ui-components/record-view-fields/static-text/static-text.component.css create mode 100644 frontend/src/app/components/ui-components/record-view-fields/static-text/static-text.component.html create mode 100644 frontend/src/app/components/ui-components/record-view-fields/static-text/static-text.component.ts create mode 100644 frontend/src/app/components/ui-components/record-view-fields/text/text.component.css create mode 100644 frontend/src/app/components/ui-components/record-view-fields/text/text.component.html create mode 100644 frontend/src/app/components/ui-components/record-view-fields/text/text.component.ts create mode 100644 frontend/src/app/components/ui-components/record-view-fields/time-interval/time-interval.component.css create mode 100644 frontend/src/app/components/ui-components/record-view-fields/time-interval/time-interval.component.html create mode 100644 frontend/src/app/components/ui-components/record-view-fields/time-interval/time-interval.component.ts create mode 100644 frontend/src/app/components/ui-components/record-view-fields/time/time.component.css create mode 100644 frontend/src/app/components/ui-components/record-view-fields/time/time.component.html create mode 100644 frontend/src/app/components/ui-components/record-view-fields/time/time.component.ts create mode 100644 frontend/src/app/components/ui-components/record-view-fields/url/url.component.css create mode 100644 frontend/src/app/components/ui-components/record-view-fields/url/url.component.html create mode 100644 frontend/src/app/components/ui-components/record-view-fields/url/url.component.ts create mode 100644 frontend/src/app/components/ui-components/record-view-fields/uuid/uuid.component.css create mode 100644 frontend/src/app/components/ui-components/record-view-fields/uuid/uuid.component.html create mode 100644 frontend/src/app/components/ui-components/record-view-fields/uuid/uuid.component.ts create mode 100644 frontend/src/app/consts/record-view-types.ts diff --git a/frontend/src/app/components/ui-components/record-view-fields/base-record-view-field/base-record-view-field.component.css b/frontend/src/app/components/ui-components/record-view-fields/base-record-view-field/base-record-view-field.component.css new file mode 100644 index 000000000..eb518d97e --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/base-record-view-field/base-record-view-field.component.css @@ -0,0 +1,26 @@ +.field-display { + position: relative; + display: flex; + align-items: center; +} + +.field-value { + flex-grow: 1 0 auto; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; +} + +.field-copy-button { + position: absolute; + right: -6px; + top: 50%; + background-color: var(--hover-color); + transform: translate(0, -50%) scale(0.85); + opacity: 0; + transition: opacity 0.1s ease-in-out; +} + +.field-display:hover .field-copy-button { + opacity: 1; +} diff --git a/frontend/src/app/components/ui-components/record-view-fields/base-record-view-field/base-record-view-field.component.html b/frontend/src/app/components/ui-components/record-view-fields/base-record-view-field/base-record-view-field.component.html new file mode 100644 index 000000000..67e1f2808 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/base-record-view-field/base-record-view-field.component.html @@ -0,0 +1 @@ + diff --git a/frontend/src/app/components/ui-components/record-view-fields/base-record-view-field/base-record-view-field.component.ts b/frontend/src/app/components/ui-components/record-view-fields/base-record-view-field/base-record-view-field.component.ts new file mode 100644 index 000000000..fe8eb408e --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/base-record-view-field/base-record-view-field.component.ts @@ -0,0 +1,20 @@ +import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { TableField, WidgetStructure } from 'src/app/models/table'; + +import { CommonModule } from '@angular/common'; + +@Component({ + selector: 'app-base-record-view-field', + templateUrl: './base-record-view-field.component.html', + styleUrls: ['./base-record-view-field.component.css'], + imports: [CommonModule] +}) +export class BaseRecordViewFieldComponent { + @Input() key: string; + @Input() value: any; + @Input() structure: TableField; + @Input() widgetStructure: WidgetStructure; + // @Input() relations: TableForeignKey; + + @Output() onCopyToClipboard = new EventEmitter(); +} diff --git a/frontend/src/app/components/ui-components/record-view-fields/binary-data-caption/binary-data-caption.component.html b/frontend/src/app/components/ui-components/record-view-fields/binary-data-caption/binary-data-caption.component.html new file mode 100644 index 000000000..ea5a639c0 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/binary-data-caption/binary-data-caption.component.html @@ -0,0 +1,3 @@ +
+ {{value || '—'}} +
diff --git a/frontend/src/app/components/ui-components/record-view-fields/binary-data-caption/binary-data-caption.component.ts b/frontend/src/app/components/ui-components/record-view-fields/binary-data-caption/binary-data-caption.component.ts new file mode 100644 index 000000000..f87649a5e --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/binary-data-caption/binary-data-caption.component.ts @@ -0,0 +1,16 @@ +import { CommonModule } from '@angular/common'; +import { Component, Injectable } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; + +@Injectable() +@Component({ + selector: 'app-binary-data-caption-display', + templateUrl: './binary-data-caption.component.html', + styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './binary-data-caption.component.css'], + imports: [CommonModule, MatIconModule, MatButtonModule, MatTooltipModule] +}) +export class BinaryDataCaptionRecordViewComponent extends BaseRecordViewFieldComponent { +} diff --git a/frontend/src/app/components/ui-components/record-view-fields/boolean/boolean.component.css b/frontend/src/app/components/ui-components/record-view-fields/boolean/boolean.component.css new file mode 100644 index 000000000..603046a74 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/boolean/boolean.component.css @@ -0,0 +1,27 @@ +.boolean-icon { + transform: scale(0.85); +} + +@media (prefers-color-scheme: light) { + .boolean-icon-true { + color: #1B5E20; + } + + .boolean-icon-false { + color: #B71C1C; + } +} + +@media (prefers-color-scheme: dark) { + .boolean-icon-true { + color: #4CAF50; + } + + .boolean-icon-false { + color: #E53935; + } +} + + + + diff --git a/frontend/src/app/components/ui-components/record-view-fields/boolean/boolean.component.html b/frontend/src/app/components/ui-components/record-view-fields/boolean/boolean.component.html new file mode 100644 index 000000000..a83870454 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/boolean/boolean.component.html @@ -0,0 +1,7 @@ +
+
+ check_small + close_small + +
+
diff --git a/frontend/src/app/components/ui-components/record-view-fields/boolean/boolean.component.ts b/frontend/src/app/components/ui-components/record-view-fields/boolean/boolean.component.ts new file mode 100644 index 000000000..df2857e78 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/boolean/boolean.component.ts @@ -0,0 +1,19 @@ +import { Component, Injectable } from '@angular/core'; + + +import { ClipboardModule } from '@angular/cdk/clipboard'; +import { CommonModule } from '@angular/common'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; + +@Injectable() +@Component({ + selector: 'app-display-boolean', + templateUrl: './boolean.component.html', + styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './boolean.component.css'], + imports: [ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule, CommonModule] +}) +export class BooleanRecordViewComponent extends BaseRecordViewFieldComponent { +} diff --git a/frontend/src/app/components/ui-components/record-view-fields/code/code.component.css b/frontend/src/app/components/ui-components/record-view-fields/code/code.component.css new file mode 100644 index 000000000..1e61ec077 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/code/code.component.css @@ -0,0 +1,12 @@ +.field-value { + background-color: #EAEAFF; + border-radius: 4px; + font-family: monospace; + padding: 0 8px; +} + +@media (prefers-color-scheme: dark) { + .field-value { + background-color: #2C2C54; + } +} diff --git a/frontend/src/app/components/ui-components/record-view-fields/code/code.component.html b/frontend/src/app/components/ui-components/record-view-fields/code/code.component.html new file mode 100644 index 000000000..acf48b2d5 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/code/code.component.html @@ -0,0 +1,11 @@ +
+ {{value || '—'}} + +
diff --git a/frontend/src/app/components/ui-components/record-view-fields/code/code.component.ts b/frontend/src/app/components/ui-components/record-view-fields/code/code.component.ts new file mode 100644 index 000000000..10ac1a228 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/code/code.component.ts @@ -0,0 +1,17 @@ +import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; +import { ClipboardModule } from '@angular/cdk/clipboard'; +import { CommonModule } from '@angular/common'; +import { Component, Injectable } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { MatTooltipModule } from '@angular/material/tooltip'; + +@Injectable() +@Component({ + selector: 'app-code-display', + templateUrl: './code.component.html', + styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './code.component.css'], + imports: [ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule, CommonModule] +}) +export class CodeRecordViewComponent extends BaseRecordViewFieldComponent { +} diff --git a/frontend/src/app/components/ui-components/record-view-fields/color/color.component.css b/frontend/src/app/components/ui-components/record-view-fields/color/color.component.css new file mode 100644 index 000000000..273272d64 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/color/color.component.css @@ -0,0 +1,17 @@ +.color-display { + display: flex; + align-items: center; + gap: 8px; +} + +.color-swatch { + width: 20px; + height: 20px; + border-radius: 4px; + /* border: 1px solid #ccc; */ + flex-shrink: 0; +} + +.field-value { + font-family: monospace; +} \ No newline at end of file diff --git a/frontend/src/app/components/ui-components/record-view-fields/color/color.component.html b/frontend/src/app/components/ui-components/record-view-fields/color/color.component.html new file mode 100644 index 000000000..f144cacdc --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/color/color.component.html @@ -0,0 +1,18 @@ +
+
+
+ {{value || '—'}} +
+ +
\ No newline at end of file diff --git a/frontend/src/app/components/ui-components/record-view-fields/color/color.component.ts b/frontend/src/app/components/ui-components/record-view-fields/color/color.component.ts new file mode 100644 index 000000000..b40fe6a4c --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/color/color.component.ts @@ -0,0 +1,53 @@ +import { Component, Injectable } from '@angular/core'; + +import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; +import { ClipboardModule } from '@angular/cdk/clipboard'; +import { CommonModule } from '@angular/common'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import colorString from 'color-string'; + +@Injectable() +@Component({ + selector: 'app-display-color', + templateUrl: './color.component.html', + styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './color.component.css'], + imports: [CommonModule, ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule] +}) +export class ColorRecordViewComponent extends BaseRecordViewFieldComponent { + get isValidColor(): boolean { + if (!this.value) return false; + return this.parseColor(this.value) !== null; + } + + get normalizedColorForDisplay(): string { + const parsed = this.parseColor(this.value); + if (parsed) { + const [r, g, b] = parsed.value; + return `#${this.toHex(r)}${this.toHex(g)}${this.toHex(b)}`; + } + return '#000000'; + } + + + private parseColor(color: string): any { + if (!color) return null; + + // Try parsing with color-string + const parsed = colorString.get(color); + if (parsed) return parsed; + + // Try hex without hash + if (/^[A-Fa-f0-9]{6}$|^[A-Fa-f0-9]{3}$/.test(color)) { + return colorString.get('#' + color); + } + + return null; + } + + private toHex(n: number): string { + const hex = n.toString(16); + return hex.length === 1 ? '0' + hex : hex; + } +} \ No newline at end of file diff --git a/frontend/src/app/components/ui-components/record-view-fields/country/country.component.css b/frontend/src/app/components/ui-components/record-view-fields/country/country.component.css new file mode 100644 index 000000000..b3e456f15 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/country/country.component.css @@ -0,0 +1,27 @@ +.field-wrapper { + display: flex; + align-items: center; +} + +.value-wrapper { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + max-width: 300px; + display: flex; + align-items: center; +} + +.country-flag { + margin-right: 6px; + font-size: 1.2em; +} + +.copy-button { + visibility: hidden; + margin-left: 4px; +} + +.field-wrapper:hover .copy-button { + visibility: visible; +} diff --git a/frontend/src/app/components/ui-components/record-view-fields/country/country.component.html b/frontend/src/app/components/ui-components/record-view-fields/country/country.component.html new file mode 100644 index 000000000..54639a23b --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/country/country.component.html @@ -0,0 +1,14 @@ +
+ + {{ countryFlag }} + {{ countryName }} + + +
diff --git a/frontend/src/app/components/ui-components/record-view-fields/country/country.component.ts b/frontend/src/app/components/ui-components/record-view-fields/country/country.component.ts new file mode 100644 index 000000000..c3b24fa86 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/country/country.component.ts @@ -0,0 +1,53 @@ +import { COUNTRIES, getCountryFlag } from '../../../../consts/countries'; +import { Component, Injectable, OnChanges, OnInit, SimpleChanges } from '@angular/core'; + +import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; +import { ClipboardModule } from '@angular/cdk/clipboard'; +import { CommonModule } from '@angular/common'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { MatTooltipModule } from '@angular/material/tooltip'; + +@Injectable() +@Component({ + selector: 'app-country-display', + templateUrl: './country.component.html', + styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './country.component.css'], + imports: [ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule, CommonModule] +}) +export class CountryRecordViewComponent extends BaseRecordViewFieldComponent implements OnInit { + static type = 'country'; + + public countryName: string = ''; + public countryFlag: string = ''; + public showFlag: boolean = true; + + ngOnInit(): void { + this.parseWidgetParams(); + + if (this.value) { + const country = COUNTRIES.find(c => c.code === this.value); + this.countryName = country ? country.name : this.value; + this.countryFlag = getCountryFlag(this.value); + } else { + this.countryName = '—'; + this.countryFlag = ''; + } + } + + private parseWidgetParams(): void { + if (this.widgetStructure?.widget_params) { + try { + const params = typeof this.widgetStructure.widget_params === 'string' + ? JSON.parse(this.widgetStructure.widget_params) + : this.widgetStructure.widget_params; + + if (params.show_flag !== undefined) { + this.showFlag = params.show_flag; + } + } catch (e) { + console.error('Error parsing country widget params:', e); + } + } + } +} diff --git a/frontend/src/app/components/ui-components/record-view-fields/date-time/date-time.component.css b/frontend/src/app/components/ui-components/record-view-fields/date-time/date-time.component.css new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/date-time/date-time.component.css @@ -0,0 +1 @@ + diff --git a/frontend/src/app/components/ui-components/record-view-fields/date-time/date-time.component.html b/frontend/src/app/components/ui-components/record-view-fields/date-time/date-time.component.html new file mode 100644 index 000000000..43432b87e --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/date-time/date-time.component.html @@ -0,0 +1,11 @@ +
+ {{formattedDateTime || '—'}} + +
diff --git a/frontend/src/app/components/ui-components/record-view-fields/date-time/date-time.component.ts b/frontend/src/app/components/ui-components/record-view-fields/date-time/date-time.component.ts new file mode 100644 index 000000000..e36ed1238 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/date-time/date-time.component.ts @@ -0,0 +1,37 @@ +import { Component, Injectable, OnInit } from '@angular/core'; + +import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; +import { ClipboardModule } from '@angular/cdk/clipboard'; +import { CommonModule } from '@angular/common'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { format } from 'date-fns'; + +@Injectable() +@Component({ + selector: 'app-date-time-display', + templateUrl: './date-time.component.html', + styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './date-time.component.css'], + imports: [ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule, CommonModule] +}) +export class DateTimeRecordViewComponent extends BaseRecordViewFieldComponent implements OnInit { + static type = 'datetime'; + + public formattedDateTime: string; + + ngOnInit(): void { + if (this.value) { + try { + const date = new Date(this.value); + if (!isNaN(date.getTime())) { + this.formattedDateTime = format(date, "P p"); + } else { + this.formattedDateTime = this.value; + } + } catch (error) { + this.formattedDateTime = this.value; + } + } + } +} diff --git a/frontend/src/app/components/ui-components/record-view-fields/date/date.component.css b/frontend/src/app/components/ui-components/record-view-fields/date/date.component.css new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/date/date.component.css @@ -0,0 +1 @@ + diff --git a/frontend/src/app/components/ui-components/record-view-fields/date/date.component.html b/frontend/src/app/components/ui-components/record-view-fields/date/date.component.html new file mode 100644 index 000000000..36172b273 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/date/date.component.html @@ -0,0 +1,11 @@ +
+ {{formattedDate || '—'}} + +
diff --git a/frontend/src/app/components/ui-components/record-view-fields/date/date.component.ts b/frontend/src/app/components/ui-components/record-view-fields/date/date.component.ts new file mode 100644 index 000000000..501499cd5 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/date/date.component.ts @@ -0,0 +1,37 @@ +import { Component, Injectable, OnInit } from '@angular/core'; +import { format, parseISO } from 'date-fns'; + +import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; +import { ClipboardModule } from '@angular/cdk/clipboard'; +import { CommonModule } from '@angular/common'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { MatTooltipModule } from '@angular/material/tooltip'; + +@Injectable() +@Component({ + selector: 'app-date-display', + templateUrl: './date.component.html', + styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './date.component.css'], + imports: [ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule, CommonModule] +}) +export class DateRecordViewComponent extends BaseRecordViewFieldComponent implements OnInit { + static type = 'date'; + + public formattedDate: string; + + ngOnInit(): void { + if (this.value) { + try { + const date = new Date(this.value); + if (!isNaN(date.getTime())) { + this.formattedDate = format(date, "P"); + } else { + this.formattedDate = this.value; + } + } catch (error) { + this.formattedDate = this.value; + } + } + } +} diff --git a/frontend/src/app/components/ui-components/record-view-fields/file/file.component.css b/frontend/src/app/components/ui-components/record-view-fields/file/file.component.css new file mode 100644 index 000000000..7f667e698 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/file/file.component.css @@ -0,0 +1,4 @@ +.field-value { + font-style: italic; + color: #666; +} diff --git a/frontend/src/app/components/ui-components/record-view-fields/file/file.component.html b/frontend/src/app/components/ui-components/record-view-fields/file/file.component.html new file mode 100644 index 000000000..e490bcd7b --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/file/file.component.html @@ -0,0 +1,3 @@ +
+ {{displayText}} +
diff --git a/frontend/src/app/components/ui-components/record-view-fields/file/file.component.ts b/frontend/src/app/components/ui-components/record-view-fields/file/file.component.ts new file mode 100644 index 000000000..99a913df2 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/file/file.component.ts @@ -0,0 +1,34 @@ +import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; +import { ClipboardModule } from '@angular/cdk/clipboard'; +import { CommonModule } from '@angular/common'; +import { Component, Injectable } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { MatTooltipModule } from '@angular/material/tooltip'; + +interface Blob { + type: string; + data: any[]; +} + +@Injectable() +@Component({ + selector: 'app-file-display', + templateUrl: './file.component.html', + styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './file.component.css'], + imports: [ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule, CommonModule] +}) +export class FileRecordViewComponent extends BaseRecordViewFieldComponent { + get isBlob(): boolean { + return typeof this.value === 'object' && this.value !== null && 'type' in this.value && 'data' in this.value; + } + + get displayText(): string { + if (this.isBlob) { + return 'Binary Data'; + } else if (typeof this.value === 'string' && this.value.length > 20) { + return 'Binary Data'; + } + return this.value ? String(this.value) : '—'; + } +} diff --git a/frontend/src/app/components/ui-components/record-view-fields/foreign-key/foreign-key.component.css b/frontend/src/app/components/ui-components/record-view-fields/foreign-key/foreign-key.component.css new file mode 100644 index 000000000..e818ae5cc --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/foreign-key/foreign-key.component.css @@ -0,0 +1,27 @@ +.foreign-key-button { + background: transparent; + border: 1px solid transparent; + border-radius: 12px; + color: var(--color-accentedPalette-500); + cursor: pointer; + font-size: inherit; + padding: 2px 8px; + overflow: hidden; + text-overflow: ellipsis; + text-align: left; + max-width: 100%; + transition: background 100ms, border-color 100ms; +} + +.foreign-key-button:hover{ + background-color: var(--color-accentedPalette-100); + border: 1px solid var(--color-accentedPalette-300); +} + +.foreign-key-button_selected { + background-color: var(--color-accentedPalette-100); + border-radius: 12px; + border: 1px solid var(--color-accentedPalette-300); +} + + diff --git a/frontend/src/app/components/ui-components/record-view-fields/foreign-key/foreign-key.component.html b/frontend/src/app/components/ui-components/record-view-fields/foreign-key/foreign-key.component.html new file mode 100644 index 000000000..c4e04ce2f --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/foreign-key/foreign-key.component.html @@ -0,0 +1,21 @@ +
+
+ + {{ value || '—' }} +
+ +
diff --git a/frontend/src/app/components/ui-components/record-view-fields/foreign-key/foreign-key.component.ts b/frontend/src/app/components/ui-components/record-view-fields/foreign-key/foreign-key.component.ts new file mode 100644 index 000000000..03cf9a741 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/foreign-key/foreign-key.component.ts @@ -0,0 +1,37 @@ +import { Component, EventEmitter, Injectable, Input, Output } from '@angular/core'; + +import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; +import { ClipboardModule } from '@angular/cdk/clipboard'; +import { CommonModule } from '@angular/common'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { TableForeignKey } from 'src/app/models/table'; + +@Injectable() +@Component({ + selector: 'app-display-foreign-key', + templateUrl: './foreign-key.component.html', + styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './foreign-key.component.css'], + imports: [ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule, CommonModule] +}) +export class ForeignKeyRecordViewComponent extends BaseRecordViewFieldComponent { + @Input() isSelected: boolean = false; + @Input() relations: TableForeignKey; + + @Output() onForeignKeyClick = new EventEmitter<{foreignKey: any, value: string}>(); + + constructor() { + super(); + } + + handleForeignKeyClick($event): void { + $event.stopPropagation(); + if (this.relations && this.value) { + this.onForeignKeyClick.emit({ + foreignKey: this.relations, + value: this.value + }); + } + } +} diff --git a/frontend/src/app/components/ui-components/record-view-fields/id/id.component.css b/frontend/src/app/components/ui-components/record-view-fields/id/id.component.css new file mode 100644 index 000000000..277f14993 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/id/id.component.css @@ -0,0 +1,9 @@ +.field-display-id { + display: flex; + align-items: center; +} + +.field-value-id { + font-weight: 500; + flex-grow: 1; +} diff --git a/frontend/src/app/components/ui-components/record-view-fields/id/id.component.html b/frontend/src/app/components/ui-components/record-view-fields/id/id.component.html new file mode 100644 index 000000000..1f1908b5a --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/id/id.component.html @@ -0,0 +1,12 @@ +
+ {{value || '—'}} + +
diff --git a/frontend/src/app/components/ui-components/record-view-fields/id/id.component.ts b/frontend/src/app/components/ui-components/record-view-fields/id/id.component.ts new file mode 100644 index 000000000..ff9ce715e --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/id/id.component.ts @@ -0,0 +1,18 @@ +import { Component, Injectable } from '@angular/core'; + +import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; +import { ClipboardModule } from '@angular/cdk/clipboard'; +import { CommonModule } from '@angular/common'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { MatTooltipModule } from '@angular/material/tooltip'; + +@Injectable() +@Component({ + selector: 'app-display-id', + templateUrl: './id.component.html', + styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './id.component.css'], + imports: [ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule, CommonModule] +}) +export class IdRecordViewComponent extends BaseRecordViewFieldComponent { +} diff --git a/frontend/src/app/components/ui-components/record-view-fields/image/image.component.css b/frontend/src/app/components/ui-components/record-view-fields/image/image.component.css new file mode 100644 index 000000000..fad6ddbcf --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/image/image.component.css @@ -0,0 +1,10 @@ +.field-value { + font-style: italic; + color: #666; +} + +.image-thumbnail { + display: block; + height: var(--height); + margin: 12px 0; +} diff --git a/frontend/src/app/components/ui-components/record-view-fields/image/image.component.html b/frontend/src/app/components/ui-components/record-view-fields/image/image.component.html new file mode 100644 index 000000000..dd64c06b4 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/image/image.component.html @@ -0,0 +1,15 @@ +
+ [Image URL] + Image + +
diff --git a/frontend/src/app/components/ui-components/record-view-fields/image/image.component.ts b/frontend/src/app/components/ui-components/record-view-fields/image/image.component.ts new file mode 100644 index 000000000..01aa59bbb --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/image/image.component.ts @@ -0,0 +1,26 @@ +import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; +import { ClipboardModule } from '@angular/cdk/clipboard'; +import { CommonModule } from '@angular/common'; +import { Component, Injectable } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { MatTooltipModule } from '@angular/material/tooltip'; + +@Injectable() +@Component({ + selector: 'app-image-display', + templateUrl: './image.component.html', + styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './image.component.css'], + imports: [ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule, CommonModule] +}) +export class ImageRecordViewComponent extends BaseRecordViewFieldComponent { + get isUrl(): boolean { + if (!this.value) return false; + try { + new URL(this.value); + return true; + } catch { + return false; + } + } +} diff --git a/frontend/src/app/components/ui-components/record-view-fields/json-editor/json-editor.component.css b/frontend/src/app/components/ui-components/record-view-fields/json-editor/json-editor.component.css new file mode 100644 index 000000000..354fa288a --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/json-editor/json-editor.component.css @@ -0,0 +1,6 @@ +.json-display { + background-color: #EAEAFF; + border-radius: 4px; + font-family: monospace; + padding: 0 8px; +} diff --git a/frontend/src/app/components/ui-components/record-view-fields/json-editor/json-editor.component.html b/frontend/src/app/components/ui-components/record-view-fields/json-editor/json-editor.component.html new file mode 100644 index 000000000..4a6211393 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/json-editor/json-editor.component.html @@ -0,0 +1,11 @@ +
+
{{ formattedJson }}
+ +
diff --git a/frontend/src/app/components/ui-components/record-view-fields/json-editor/json-editor.component.ts b/frontend/src/app/components/ui-components/record-view-fields/json-editor/json-editor.component.ts new file mode 100644 index 000000000..ee087edc1 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/json-editor/json-editor.component.ts @@ -0,0 +1,27 @@ +import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; +import { ClipboardModule } from '@angular/cdk/clipboard'; +import { CommonModule } from '@angular/common'; +import { Component, Injectable } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { MatTooltipModule } from '@angular/material/tooltip'; + +@Injectable() +@Component({ + selector: 'app-json-editor-display', + templateUrl: './json-editor.component.html', + styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './json-editor.component.css'], + imports: [ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule, CommonModule] +}) +export class JsonEditorRecordViewComponent extends BaseRecordViewFieldComponent { + get formattedJson(): string { + if (!this.value) return ''; + + try { + const parsedValue = typeof this.value === 'string' ? JSON.parse(this.value) : this.value; + return JSON.stringify(parsedValue, null, 2); + } catch (e) { + return String(this.value); + } + } +} diff --git a/frontend/src/app/components/ui-components/record-view-fields/long-text/long-text.component.css b/frontend/src/app/components/ui-components/record-view-fields/long-text/long-text.component.css new file mode 100644 index 000000000..adb834c90 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/long-text/long-text.component.css @@ -0,0 +1,4 @@ +.field-value { + height: 36px; + line-height: 36px; +} diff --git a/frontend/src/app/components/ui-components/record-view-fields/long-text/long-text.component.html b/frontend/src/app/components/ui-components/record-view-fields/long-text/long-text.component.html new file mode 100644 index 000000000..79e15809d --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/long-text/long-text.component.html @@ -0,0 +1,12 @@ +
+ {{value || '—'}} + +
diff --git a/frontend/src/app/components/ui-components/record-view-fields/long-text/long-text.component.ts b/frontend/src/app/components/ui-components/record-view-fields/long-text/long-text.component.ts new file mode 100644 index 000000000..89894c36a --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/long-text/long-text.component.ts @@ -0,0 +1,19 @@ +import { Component, Injectable } from '@angular/core'; + +import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; +import { ClipboardModule } from '@angular/cdk/clipboard'; +import { CommonModule } from '@angular/common'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { MatTooltipModule } from '@angular/material/tooltip'; + +@Injectable() +@Component({ + selector: 'app-display-long-text', + templateUrl: './long-text.component.html', + styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './long-text.component.css'], + imports: [CommonModule, ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule] +}) +export class LongTextRecordViewComponent extends BaseRecordViewFieldComponent { + +} diff --git a/frontend/src/app/components/ui-components/record-view-fields/money/money.component.css b/frontend/src/app/components/ui-components/record-view-fields/money/money.component.css new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/money/money.component.css @@ -0,0 +1 @@ + diff --git a/frontend/src/app/components/ui-components/record-view-fields/money/money.component.html b/frontend/src/app/components/ui-components/record-view-fields/money/money.component.html new file mode 100644 index 000000000..202929d6b --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/money/money.component.html @@ -0,0 +1,13 @@ +
+ + {{formattedValue || '—'}} + + +
diff --git a/frontend/src/app/components/ui-components/record-view-fields/money/money.component.ts b/frontend/src/app/components/ui-components/record-view-fields/money/money.component.ts new file mode 100644 index 000000000..8c8f380a5 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/money/money.component.ts @@ -0,0 +1,62 @@ +import { Component, Injectable, OnInit } from '@angular/core'; + +import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; +import { ClipboardModule } from '@angular/cdk/clipboard'; +import { CommonModule } from '@angular/common'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { getCurrencyByCode } from 'src/app/consts/currencies'; + +@Injectable() +@Component({ + selector: 'app-money-display', + templateUrl: './money.component.html', + styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './money.component.css'], + imports: [ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule, CommonModule] +}) +export class MoneyRecordViewComponent extends BaseRecordViewFieldComponent implements OnInit { + public displayCurrency: string = ''; + public currencySymbol: string = ''; + + ngOnInit(): void { + // Get currency from widget params + this.displayCurrency = ''; + if (this.widgetStructure && this.widgetStructure.widget_params && this.widgetStructure.widget_params.default_currency) { + this.displayCurrency = this.widgetStructure.widget_params.default_currency; + const currency = getCurrencyByCode(this.displayCurrency); + this.currencySymbol = currency ? currency.symbol : ''; + } + } + + get formattedValue(): string { + if (!this.value) { + return ''; + } + + let amount: number | string; + let currency: string = this.displayCurrency; + + if (typeof this.value === 'object' && this.value.amount !== undefined) { + amount = this.value.amount; + if (this.value.currency) { + currency = this.value.currency; + const currencyObj = getCurrencyByCode(currency); + this.currencySymbol = currencyObj ? currencyObj.symbol : ''; + } + } else { + amount = this.value; + } + + if (typeof amount === 'string') { + amount = parseFloat(amount); + } + + if (isNaN(amount as number)) { + return ''; + } + + const decimalPlaces = this.widgetStructure?.widget_params?.decimal_places ?? 2; + return `${this.currencySymbol}${(amount as number).toFixed(decimalPlaces)}`; + } +} diff --git a/frontend/src/app/components/ui-components/record-view-fields/number/number.component.css b/frontend/src/app/components/ui-components/record-view-fields/number/number.component.css new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/number/number.component.css @@ -0,0 +1 @@ + diff --git a/frontend/src/app/components/ui-components/record-view-fields/number/number.component.html b/frontend/src/app/components/ui-components/record-view-fields/number/number.component.html new file mode 100644 index 000000000..356e592cb --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/number/number.component.html @@ -0,0 +1,11 @@ +
+ {{displayValue}} + +
diff --git a/frontend/src/app/components/ui-components/record-view-fields/number/number.component.ts b/frontend/src/app/components/ui-components/record-view-fields/number/number.component.ts new file mode 100644 index 000000000..7977f5173 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/number/number.component.ts @@ -0,0 +1,40 @@ +import { ClipboardModule } from '@angular/cdk/clipboard'; +import { Component, Injectable } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; +import convert from 'convert'; + +@Injectable() +@Component({ + selector: 'app-display-number', + templateUrl: './number.component.html', + styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './number.component.css'], + imports: [ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule, CommonModule] +}) +export class NumberRecordViewComponent extends BaseRecordViewFieldComponent { + + get displayValue(): string { + if (this.value == null || this.value === '') { + return '—'; + } + + const unit = this.widgetStructure?.widget_params?.unit; + + if (!unit) { + return this.value.toString(); + } + + try { + const convertedValue = convert(parseFloat(this.value), unit).to('best'); + // Format number to max 2 decimal places without trailing zeros + const formattedQuantity = parseFloat(convertedValue.quantity.toFixed(2)).toString(); + return `${formattedQuantity} ${convertedValue.unit}`; + } catch (error) { + console.warn('Unit conversion failed:', error); + return this.value.toString(); + } + } +} diff --git a/frontend/src/app/components/ui-components/record-view-fields/password/password.component.css b/frontend/src/app/components/ui-components/record-view-fields/password/password.component.css new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/password/password.component.css @@ -0,0 +1 @@ + diff --git a/frontend/src/app/components/ui-components/record-view-fields/password/password.component.html b/frontend/src/app/components/ui-components/record-view-fields/password/password.component.html new file mode 100644 index 000000000..bc4098081 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/password/password.component.html @@ -0,0 +1,3 @@ +
+ •••••••• +
diff --git a/frontend/src/app/components/ui-components/record-view-fields/password/password.component.ts b/frontend/src/app/components/ui-components/record-view-fields/password/password.component.ts new file mode 100644 index 000000000..c057fd5c9 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/password/password.component.ts @@ -0,0 +1,17 @@ +import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; +import { ClipboardModule } from '@angular/cdk/clipboard'; +import { CommonModule } from '@angular/common'; +import { Component, Injectable } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { MatTooltipModule } from '@angular/material/tooltip'; + +@Injectable() +@Component({ + selector: 'app-password-display', + templateUrl: './password.component.html', + styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './password.component.css'], + imports: [ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule, CommonModule] +}) +export class PasswordRecordViewComponent extends BaseRecordViewFieldComponent { +} diff --git a/frontend/src/app/components/ui-components/record-view-fields/phone/phone.component.css b/frontend/src/app/components/ui-components/record-view-fields/phone/phone.component.css new file mode 100644 index 000000000..e325e57dd --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/phone/phone.component.css @@ -0,0 +1,20 @@ +.field-display { + padding-right: 24px; +} + +.phone-content { + display: flex; + align-items: center; + gap: 8px; +} + +.country-flag { + font-size: 16px; + cursor: help; + user-select: none; +} + +.phone-link { + text-decoration: none; + color: var(--primary-color); +} \ No newline at end of file diff --git a/frontend/src/app/components/ui-components/record-view-fields/phone/phone.component.html b/frontend/src/app/components/ui-components/record-view-fields/phone/phone.component.html new file mode 100644 index 000000000..bfbc51f33 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/phone/phone.component.html @@ -0,0 +1,15 @@ +
+ + {{ countryFlag }} + {{ formattedNumber || value }} + + + +
diff --git a/frontend/src/app/components/ui-components/record-view-fields/phone/phone.component.ts b/frontend/src/app/components/ui-components/record-view-fields/phone/phone.component.ts new file mode 100644 index 000000000..96d8ecb04 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/phone/phone.component.ts @@ -0,0 +1,61 @@ +import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; +import { ClipboardModule } from '@angular/cdk/clipboard'; +import { CommonModule } from '@angular/common'; +import { Component, Injectable, OnInit } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { parsePhoneNumber } from 'libphonenumber-js'; +import { COUNTRIES, getCountryFlag } from '../../../../consts/countries'; + +@Injectable() +@Component({ + selector: 'app-phone-display', + templateUrl: './phone.component.html', + styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './phone.component.css'], + imports: [ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule, CommonModule] +}) +export class PhoneRecordViewComponent extends BaseRecordViewFieldComponent implements OnInit { + public countryFlag: string = ''; + public countryName: string = ''; + public formattedNumber: string = ''; + + ngOnInit(): void { + this.parsePhoneNumber(); + } + + private parsePhoneNumber(): void { + if (!this.value || typeof this.value !== 'string') { + this.countryFlag = ''; + this.countryName = ''; + this.formattedNumber = ''; + return; + } + + try { + const phoneNumber = parsePhoneNumber(this.value); + + if (phoneNumber && phoneNumber.country) { + const country = COUNTRIES.find(c => c.code === phoneNumber.country); + + if (country) { + this.countryFlag = getCountryFlag(country.code); + this.countryName = country.name; + this.formattedNumber = phoneNumber.formatInternational(); + } else { + this.countryFlag = ''; + this.countryName = ''; + this.formattedNumber = this.value; + } + } else { + this.countryFlag = ''; + this.countryName = ''; + this.formattedNumber = this.value; + } + } catch (error) { + this.countryFlag = ''; + this.countryName = ''; + this.formattedNumber = this.value; + } + } +} diff --git a/frontend/src/app/components/ui-components/record-view-fields/point/point.component.css b/frontend/src/app/components/ui-components/record-view-fields/point/point.component.css new file mode 100644 index 000000000..1296352f2 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/point/point.component.css @@ -0,0 +1,21 @@ +.field-wrapper { + display: flex; + align-items: center; +} + +.value-wrapper { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + max-width: 300px; + font-family: monospace; +} + +.copy-button { + visibility: hidden; + margin-left: 4px; +} + +.field-wrapper:hover .copy-button { + visibility: visible; +} diff --git a/frontend/src/app/components/ui-components/record-view-fields/point/point.component.html b/frontend/src/app/components/ui-components/record-view-fields/point/point.component.html new file mode 100644 index 000000000..2e30aeeca --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/point/point.component.html @@ -0,0 +1,11 @@ +
+ {{ formattedPoint }} + +
diff --git a/frontend/src/app/components/ui-components/record-view-fields/point/point.component.ts b/frontend/src/app/components/ui-components/record-view-fields/point/point.component.ts new file mode 100644 index 000000000..38a3fc0ad --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/point/point.component.ts @@ -0,0 +1,48 @@ +import { Component, Injectable, OnInit } from '@angular/core'; + +import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; +import { ClipboardModule } from '@angular/cdk/clipboard'; +import { CommonModule } from '@angular/common'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { MatTooltipModule } from '@angular/material/tooltip'; + +@Injectable() +@Component({ + selector: 'app-point-display', + templateUrl: './point.component.html', + styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './point.component.css'], + imports: [ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule, CommonModule] +}) +export class PointRecordViewComponent extends BaseRecordViewFieldComponent implements OnInit { + static type = 'point'; + + formattedPoint: string; + + ngOnInit() { + this.formatPoint(); + } + + private formatPoint() { + if (!this.value) { + this.formattedPoint = ''; + return; + } + + try { + if (typeof this.value === 'string') { + // Handle string format like "(x,y)" or "x,y" + const pointStr = this.value.trim().replace(/[()]/g, ''); + const [x, y] = pointStr.split(',').map(coord => parseFloat(coord.trim())); + this.formattedPoint = `(${x}, ${y})`; + } else if (typeof this.value === 'object') { + // Handle object format like {x: 1, y: 2} + const x = this.value.x || this.value[0]; + const y = this.value.y || this.value[1]; + this.formattedPoint = `(${x}, ${y})`; + } + } catch (e) { + this.formattedPoint = String(this.value); + } + } +} diff --git a/frontend/src/app/components/ui-components/record-view-fields/select/select.component.css b/frontend/src/app/components/ui-components/record-view-fields/select/select.component.css new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/select/select.component.css @@ -0,0 +1 @@ + diff --git a/frontend/src/app/components/ui-components/record-view-fields/select/select.component.html b/frontend/src/app/components/ui-components/record-view-fields/select/select.component.html new file mode 100644 index 000000000..58124cc57 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/select/select.component.html @@ -0,0 +1,11 @@ +
+ {{displayValue}} + +
diff --git a/frontend/src/app/components/ui-components/record-view-fields/select/select.component.ts b/frontend/src/app/components/ui-components/record-view-fields/select/select.component.ts new file mode 100644 index 000000000..29d2442d8 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/select/select.component.ts @@ -0,0 +1,43 @@ +import { Component, Injectable, OnInit } from '@angular/core'; + +import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; +import { ClipboardModule } from '@angular/cdk/clipboard'; +import { CommonModule } from '@angular/common'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { MatTooltipModule } from '@angular/material/tooltip'; + +@Injectable() +@Component({ + selector: 'app-select-display', + templateUrl: './select.component.html', + styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './select.component.css'], + imports: [CommonModule, ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule] +}) +export class SelectRecordViewComponent extends BaseRecordViewFieldComponent implements OnInit { + public displayValue: string; + + ngOnInit(): void { + this.setDisplayValue(); + } + + private setDisplayValue(): void { + if (!this.value) { + this.displayValue = '—'; + return; + } + + if (this.widgetStructure?.widget_params?.options) { + // Find the matching option based on value and use its label + const option = this.widgetStructure.widget_params.options.find( + (opt: { value: any, label: string }) => opt.value === this.value + ); + this.displayValue = option ? option.label : this.value; + } else if (this.structure?.data_type_params) { + // If no widget structure but we have data_type_params, just use the value + this.displayValue = this.value; + } else { + this.displayValue = this.value; + } + } +} diff --git a/frontend/src/app/components/ui-components/record-view-fields/static-text/static-text.component.css b/frontend/src/app/components/ui-components/record-view-fields/static-text/static-text.component.css new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/static-text/static-text.component.css @@ -0,0 +1 @@ + diff --git a/frontend/src/app/components/ui-components/record-view-fields/static-text/static-text.component.html b/frontend/src/app/components/ui-components/record-view-fields/static-text/static-text.component.html new file mode 100644 index 000000000..acf48b2d5 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/static-text/static-text.component.html @@ -0,0 +1,11 @@ +
+ {{value || '—'}} + +
diff --git a/frontend/src/app/components/ui-components/record-view-fields/static-text/static-text.component.ts b/frontend/src/app/components/ui-components/record-view-fields/static-text/static-text.component.ts new file mode 100644 index 000000000..c536fa12f --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/static-text/static-text.component.ts @@ -0,0 +1,18 @@ +import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; +import { ClipboardModule } from '@angular/cdk/clipboard'; +import { CommonModule } from '@angular/common'; +import { Component, Injectable } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { MatTooltipModule } from '@angular/material/tooltip'; + +@Injectable() +@Component({ + selector: 'app-display-static-text', + templateUrl: './static-text.component.html', + styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './static-text.component.css'], + imports: [ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule, CommonModule] +}) +export class StaticTextRecordViewComponent extends BaseRecordViewFieldComponent { + static type = 'static-text'; +} diff --git a/frontend/src/app/components/ui-components/record-view-fields/text/text.component.css b/frontend/src/app/components/ui-components/record-view-fields/text/text.component.css new file mode 100644 index 000000000..e69de29bb diff --git a/frontend/src/app/components/ui-components/record-view-fields/text/text.component.html b/frontend/src/app/components/ui-components/record-view-fields/text/text.component.html new file mode 100644 index 000000000..acf48b2d5 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/text/text.component.html @@ -0,0 +1,11 @@ +
+ {{value || '—'}} + +
diff --git a/frontend/src/app/components/ui-components/record-view-fields/text/text.component.ts b/frontend/src/app/components/ui-components/record-view-fields/text/text.component.ts new file mode 100644 index 000000000..d654bc5b8 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/text/text.component.ts @@ -0,0 +1,18 @@ +import { Component, Injectable } from '@angular/core'; + +import { ClipboardModule } from '@angular/cdk/clipboard'; +import { CommonModule } from '@angular/common'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; + +@Injectable() +@Component({ + selector: 'app-display-text', + templateUrl: './text.component.html', + styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './text.component.css'], + imports: [ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule, CommonModule] +}) +export class TextRecordViewComponent extends BaseRecordViewFieldComponent { +} diff --git a/frontend/src/app/components/ui-components/record-view-fields/time-interval/time-interval.component.css b/frontend/src/app/components/ui-components/record-view-fields/time-interval/time-interval.component.css new file mode 100644 index 000000000..e69de29bb diff --git a/frontend/src/app/components/ui-components/record-view-fields/time-interval/time-interval.component.html b/frontend/src/app/components/ui-components/record-view-fields/time-interval/time-interval.component.html new file mode 100644 index 000000000..7a7b4e451 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/time-interval/time-interval.component.html @@ -0,0 +1,11 @@ +
+ {{ formattedInterval }} + +
diff --git a/frontend/src/app/components/ui-components/record-view-fields/time-interval/time-interval.component.ts b/frontend/src/app/components/ui-components/record-view-fields/time-interval/time-interval.component.ts new file mode 100644 index 000000000..f85f2c720 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/time-interval/time-interval.component.ts @@ -0,0 +1,42 @@ +import { Component, Injectable, OnInit } from '@angular/core'; + +import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; +import { ClipboardModule } from '@angular/cdk/clipboard'; +import { CommonModule } from '@angular/common'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { MatTooltipModule } from '@angular/material/tooltip'; + +@Injectable() +@Component({ + selector: 'app-time-interval-display', + templateUrl: './time-interval.component.html', + styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './time-interval.component.css'], + imports: [ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule, CommonModule] +}) +export class TimeIntervalRecordViewComponent extends BaseRecordViewFieldComponent implements OnInit { + + formattedInterval: string; + + ngOnInit() { + if (!this.value) { + this.formattedInterval = '—'; + return; + } + + try { + const interval = typeof this.value === 'string' ? JSON.parse(this.value) : this.value; + let parts = []; + + if (interval.days) parts.push(`${interval.days}d`); + if (interval.hours) parts.push(`${interval.hours}h`); + if (interval.minutes) parts.push(`${interval.minutes}m`); + if (interval.seconds) parts.push(`${interval.seconds}s`); + if (interval.milliseconds) parts.push(`${interval.milliseconds}ms`); + + this.formattedInterval = parts.length > 0 ? parts.join(' ') : '0'; + } catch (e) { + this.formattedInterval = String(this.value); + } + } +} diff --git a/frontend/src/app/components/ui-components/record-view-fields/time/time.component.css b/frontend/src/app/components/ui-components/record-view-fields/time/time.component.css new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/time/time.component.css @@ -0,0 +1 @@ + diff --git a/frontend/src/app/components/ui-components/record-view-fields/time/time.component.html b/frontend/src/app/components/ui-components/record-view-fields/time/time.component.html new file mode 100644 index 000000000..6a8efae37 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/time/time.component.html @@ -0,0 +1,11 @@ +
+ {{formattedTime || '—'}} + +
diff --git a/frontend/src/app/components/ui-components/record-view-fields/time/time.component.ts b/frontend/src/app/components/ui-components/record-view-fields/time/time.component.ts new file mode 100644 index 000000000..27be6b364 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/time/time.component.ts @@ -0,0 +1,42 @@ +import { Component, Injectable, OnInit } from '@angular/core'; + +import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; +import { ClipboardModule } from '@angular/cdk/clipboard'; +import { CommonModule } from '@angular/common'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { format } from 'date-fns'; + +@Injectable() +@Component({ + selector: 'app-time-display', + templateUrl: './time.component.html', + styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './time.component.css'], + imports: [ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule, CommonModule] +}) +export class TimeRecordViewComponent extends BaseRecordViewFieldComponent implements OnInit { + static type = 'time'; + + public formattedTime: string; + + ngOnInit(): void { + if (this.value) { + try { + if (this.value.includes(':')) { + // Handle time string format + this.formattedTime = this.value; + } else { + const date = new Date(this.value); + if (!isNaN(date.getTime())) { + this.formattedTime = format(date, 'HH:mm:ss'); + } else { + this.formattedTime = this.value; + } + } + } catch (error) { + this.formattedTime = this.value; + } + } + } +} diff --git a/frontend/src/app/components/ui-components/record-view-fields/url/url.component.css b/frontend/src/app/components/ui-components/record-view-fields/url/url.component.css new file mode 100644 index 000000000..78c2d730a --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/url/url.component.css @@ -0,0 +1,14 @@ +.url-link { + display: flex; + align-items: center; + gap: 4px; + color: var(--color-primaryPalette-500); +} + +.url-link__icon { + flex-shrink: 0; + margin-bottom: -2px; + width: 16px; + height: 16px; + font-size: 16px; +} diff --git a/frontend/src/app/components/ui-components/record-view-fields/url/url.component.html b/frontend/src/app/components/ui-components/record-view-fields/url/url.component.html new file mode 100644 index 000000000..f2f92fa5d --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/url/url.component.html @@ -0,0 +1,20 @@ +
+ + + link + {{value || '—'}} + + {{value || '—'}} + + +
diff --git a/frontend/src/app/components/ui-components/record-view-fields/url/url.component.ts b/frontend/src/app/components/ui-components/record-view-fields/url/url.component.ts new file mode 100644 index 000000000..205bdfc03 --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/url/url.component.ts @@ -0,0 +1,28 @@ +import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; +import { ClipboardModule } from '@angular/cdk/clipboard'; +import { CommonModule } from '@angular/common'; +import { Component, Injectable } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { MatTooltipModule } from '@angular/material/tooltip'; + +@Injectable() +@Component({ + selector: 'app-url-display', + templateUrl: './url.component.html', + styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './url.component.css'], + imports: [ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule, CommonModule] +}) +export class UrlRecordViewComponent extends BaseRecordViewFieldComponent { + static type = 'url'; + + get isValidUrl(): boolean { + if (!this.value) return false; + try { + new URL(this.value); + return true; + } catch { + return false; + } + } +} diff --git a/frontend/src/app/components/ui-components/record-view-fields/uuid/uuid.component.css b/frontend/src/app/components/ui-components/record-view-fields/uuid/uuid.component.css new file mode 100644 index 000000000..ca96cf31f --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/uuid/uuid.component.css @@ -0,0 +1,40 @@ +.uuid-display { + display: flex; + align-items: center; + gap: 4px; +} + +.uuid-text { + font-family: 'Roboto Condensed', 'Arial Narrow', sans-serif; + font-stretch: condensed; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.copy-button { + width: 24px; + height: 24px; + line-height: 24px; + opacity: 0; + transition: opacity 0.2s; +} + +.field-value:hover .copy-button { + opacity: 0.7; +} + +.copy-button:hover { + opacity: 1 !important; +} + +.copy-button mat-icon { + font-size: 16px; + width: 16px; + height: 16px; +} + +.null-value { + color: var(--mat-grey-500); + font-style: italic; +} diff --git a/frontend/src/app/components/ui-components/record-view-fields/uuid/uuid.component.html b/frontend/src/app/components/ui-components/record-view-fields/uuid/uuid.component.html new file mode 100644 index 000000000..380ffe2eb --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/uuid/uuid.component.html @@ -0,0 +1,16 @@ +
+ @if (value) { + {{ value }} + + } + @else { + NULL + } +
\ No newline at end of file diff --git a/frontend/src/app/components/ui-components/record-view-fields/uuid/uuid.component.ts b/frontend/src/app/components/ui-components/record-view-fields/uuid/uuid.component.ts new file mode 100644 index 000000000..9f79943ad --- /dev/null +++ b/frontend/src/app/components/ui-components/record-view-fields/uuid/uuid.component.ts @@ -0,0 +1,17 @@ +import { Component, Injectable } from '@angular/core'; +import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; +import { ClipboardModule } from '@angular/cdk/clipboard'; +import { CommonModule } from '@angular/common'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { MatTooltipModule } from '@angular/material/tooltip'; + +@Injectable() +@Component({ + selector: 'app-display-uuid', + templateUrl: './uuid.component.html', + styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './uuid.component.css'], + imports: [CommonModule, ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule] +}) +export class UuidRecordViewComponent extends BaseRecordViewFieldComponent { +} \ No newline at end of file diff --git a/frontend/src/app/consts/record-view-types.ts b/frontend/src/app/consts/record-view-types.ts new file mode 100644 index 000000000..67c05afd8 --- /dev/null +++ b/frontend/src/app/consts/record-view-types.ts @@ -0,0 +1,299 @@ +import { BooleanRecordViewComponent } from 'src/app/components/ui-components/record-view-fields/boolean/boolean.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'; +import { DateRecordViewComponent } from '../components/ui-components/record-view-fields/date/date.component'; +import { DateTimeRecordViewComponent } from '../components/ui-components/record-view-fields/date-time/date-time.component'; +import { FileRecordViewComponent } from '../components/ui-components/record-view-fields/file/file.component'; +import { ForeignKeyRecordViewComponent } from '../components/ui-components/record-view-fields/foreign-key/foreign-key.component'; +import { IdRecordViewComponent } from '../components/ui-components/record-view-fields/id/id.component'; +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 { LongTextRecordViewComponent } from 'src/app/components/ui-components/record-view-fields/long-text/long-text.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'; +import { PasswordRecordViewComponent } from '../components/ui-components/record-view-fields/password/password.component'; +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 { 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 { 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 { 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, + 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, +} + +export const tableDisplayTypes = { + 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, + }, +} From 860ebab9344c81feec09059a04a8a3f7b45d8721 Mon Sep 17 00:00:00 2001 From: Lyubov Voloshko Date: Sun, 10 Aug 2025 20:01:06 +0300 Subject: [PATCH 2/2] record view: map and fix record view components --- .../db-table-row-view.component.css | 44 ------------------- .../db-table-row-view.component.html | 43 +++++++++++------- .../db-table-row-view.component.ts | 17 ++++++- .../dashboard/db-table/db-table.component.ts | 11 ++--- .../db-table-row-edit.component.ts | 5 ++- .../base-record-view-field.component.css | 39 ++++++++-------- .../binary-data-caption.component.ts | 2 +- .../boolean/boolean.component.html | 10 ++--- .../boolean/boolean.component.ts | 7 +-- .../code/code.component.css | 26 +++++++---- .../code/code.component.html | 18 ++++---- .../record-view-fields/code/code.component.ts | 37 +++++++++++++--- .../color/color.component.html | 24 +++------- .../color/color.component.ts | 16 +++---- .../country/country.component.css | 23 ---------- .../country/country.component.html | 18 ++------ .../country/country.component.ts | 16 +++---- .../date-time/date-time.component.html | 12 +---- .../date-time/date-time.component.ts | 9 +--- .../date/date.component.html | 12 +---- .../record-view-fields/date/date.component.ts | 9 +--- .../file/file.component.html | 4 +- .../record-view-fields/file/file.component.ts | 9 +--- .../foreign-key/foreign-key.component.css | 36 ++++++--------- .../foreign-key/foreign-key.component.html | 29 ++++-------- .../foreign-key/foreign-key.component.ts | 21 +++------ .../record-view-fields/id/id.component.html | 13 +----- .../record-view-fields/id/id.component.ts | 9 +--- .../image/image.component.css | 12 ++--- .../image/image.component.html | 20 +++------ .../image/image.component.ts | 10 ++--- .../json-editor/json-editor.component.css | 24 +++++++--- .../json-editor/json-editor.component.html | 17 +++---- .../json-editor/json-editor.component.ts | 40 +++++++++++------ .../long-text/long-text.component.css | 4 -- .../long-text/long-text.component.html | 13 +----- .../long-text/long-text.component.ts | 9 +--- .../money/money.component.html | 12 +---- .../money/money.component.ts | 9 +--- .../number/number.component.html | 12 +---- .../number/number.component.ts | 13 ++---- .../password/password.component.html | 4 +- .../password/password.component.ts | 10 ++--- .../phone/phone.component.css | 5 --- .../phone/phone.component.html | 19 ++------ .../phone/phone.component.ts | 17 +++---- .../point/point.component.css | 20 --------- .../point/point.component.html | 16 +++---- .../point/point.component.ts | 8 +--- .../select/select.component.html | 12 +---- .../select/select.component.ts | 9 +--- .../static-text/static-text.component.html | 12 +---- .../static-text/static-text.component.ts | 10 +---- .../text/text.component.html | 12 +---- .../record-view-fields/text/text.component.ts | 9 +--- .../time-interval.component.html | 12 +---- .../time-interval/time-interval.component.ts | 9 +--- .../time/time.component.html | 12 +---- .../record-view-fields/time/time.component.ts | 9 +--- .../record-view-fields/url/url.component.css | 1 + .../record-view-fields/url/url.component.html | 28 ++++-------- .../record-view-fields/url/url.component.ts | 9 ++-- .../uuid/uuid.component.css | 33 -------------- .../uuid/uuid.component.html | 17 +------ .../record-view-fields/uuid/uuid.component.ts | 9 +--- frontend/src/app/consts/record-view-types.ts | 2 +- frontend/src/app/models/table.ts | 1 + 67 files changed, 321 insertions(+), 698 deletions(-) diff --git a/frontend/src/app/components/dashboard/db-table-row-view/db-table-row-view.component.css b/frontend/src/app/components/dashboard/db-table-row-view/db-table-row-view.component.css index f4f887777..aa75def10 100644 --- a/frontend/src/app/components/dashboard/db-table-row-view/db-table-row-view.component.css +++ b/frontend/src/app/components/dashboard/db-table-row-view/db-table-row-view.component.css @@ -67,50 +67,6 @@ } } -.row-preview-sidebar__field-value { - word-wrap: anywhere; - word-break: keep-all; - white-space: break-spaces; - max-width: 100%; -} - -@media (prefers-color-scheme: light) { - .row-preview-sidebar__field-value { - color: rgba(0, 0, 0, 0.64); - } -} - -@media (prefers-color-scheme: dark) { - .row-preview-sidebar__field-value { - color: rgba(255, 255, 255, 0.64); - } -} - -.row-preview-sidebar__field-value_foreign-key { - display: flex; - align-items: center; - text-decoration: none; -} - -@media (prefers-color-scheme: light) { - .row-preview-sidebar__field-value_foreign-key { - border-bottom: 1px solid rgba(0, 0, 0, 0.64); - } -} - -@media (prefers-color-scheme: dark) { - .row-preview-sidebar__field-value_foreign-key { - border-bottom: 1px solid rgba(255, 255, 255, 0.64); - } -} - -.row-preview-sidebar__field-value-icon { - font-size: 16px; - height: 16px; - margin-left: 8px; - width: 16px; -} - .row-preview-sidebar__image { width: 100%; margin-top: 8px; diff --git a/frontend/src/app/components/dashboard/db-table-row-view/db-table-row-view.component.html b/frontend/src/app/components/dashboard/db-table-row-view/db-table-row-view.component.html index 6cd5b71f9..459d95da8 100644 --- a/frontend/src/app/components/dashboard/db-table-row-view/db-table-row-view.component.html +++ b/frontend/src/app/components/dashboard/db-table-row-view/db-table-row-view.component.html @@ -80,26 +80,35 @@

Preview

-
+
{{column.normalizedTitle}} - - {{getForeignKeyValue(column.title)}} - edit - + + + + -
-
- Image -
- {{selectedRow.record[column.title] || '—'}} -
- - {{selectedRow.record[column.title] || '—'}} + + + + +
diff --git a/frontend/src/app/components/dashboard/db-table-row-view/db-table-row-view.component.ts b/frontend/src/app/components/dashboard/db-table-row-view/db-table-row-view.component.ts index 940cc649f..cc96f5e29 100644 --- a/frontend/src/app/components/dashboard/db-table-row-view/db-table-row-view.component.ts +++ b/frontend/src/app/components/dashboard/db-table-row-view/db-table-row-view.component.ts @@ -18,6 +18,9 @@ import { PlaceholderRecordViewComponent } from '../../skeletons/placeholder-reco import { TableStateService } from 'src/app/services/table-state.service'; import { TablesService } from 'src/app/services/tables.service'; import { formatFieldValue } from 'src/app/lib/format-field-value'; +import { ForeignKeyRecordViewComponent } from '../../ui-components/record-view-fields/foreign-key/foreign-key.component'; +import { UIwidgets, recordViewFieldTypes } from 'src/app/consts/record-view-types'; +import { DynamicModule } from 'ng-dynamic-component'; @Component({ selector: 'app-db-table-row-view', @@ -33,7 +36,9 @@ import { formatFieldValue } from 'src/app/lib/format-field-value'; MatListModule, RouterModule, CommonModule, - PlaceholderRecordViewComponent + PlaceholderRecordViewComponent, + ForeignKeyRecordViewComponent, + DynamicModule ] }) export class DbTableRowViewComponent implements OnInit, OnDestroy { @@ -48,19 +53,29 @@ export class DbTableRowViewComponent implements OnInit, OnDestroy { public referencedTables: { table_name: string; displayTableName: string; columns: string[] }[] = []; public referencedTablesURLParams: any; public referencedRecords: {} = {}; + public recordViewComponents; + public widgetsMap: { [key: string]: any } = {}; + public UIwidgets = UIwidgets; constructor( private _tables: TablesService, private _tableState: TableStateService, private _notifications: NotificationsService, + private _connections: ConnectionsService, private route: ActivatedRoute, ) { } ngOnInit(): void { // this.connectionID = this._connections.connectionID; + const connectionType = this._connections.currentConnection.type; + this.recordViewComponents = recordViewFieldTypes[connectionType]; + this.selectedRowCast = this._tableState.cast.subscribe((row) => { this.selectedRow = row; + + console.log('Selected row:', this.selectedRow); + if (row && row.columnsOrder) { const columnsOrder = this.selectedRow.columnsOrder.length ? this.selectedRow.columnsOrder : Object.keys(this.selectedRow.record); diff --git a/frontend/src/app/components/dashboard/db-table/db-table.component.ts b/frontend/src/app/components/dashboard/db-table/db-table.component.ts index b4a586bb5..1610f42ab 100644 --- a/frontend/src/app/components/dashboard/db-table/db-table.component.ts +++ b/frontend/src/app/components/dashboard/db-table/db-table.component.ts @@ -451,6 +451,7 @@ export class DbTableComponent implements OnInit { foreignKeysList: this.tableData.foreignKeysList, widgets: this.tableData.widgets, widgetsList: this.tableData.widgetsList, + fieldsTypes: this.tableData.tableTypes, relatedRecords: this.tableData.relatedRecords || null, link: `/dashboard/${this.connectionID}/${this.name}/entry` }); @@ -469,16 +470,15 @@ export class DbTableComponent implements OnInit { foreignKeysList: null, widgets: null, widgetsList: null, + fieldsTypes: null, relatedRecords: null, link: null }) this._tableRow.fetchTableRow(this.connectionID, foreignKeys.referenced_table_name, {[foreignKeys.referenced_column_name]: row[foreignKeys.referenced_column_name]}) .subscribe(res => { - const filedsTypes = res.structure.reduce((acc, field) => { - acc[field.column_name ] = field.data_type; - return acc; - }, {}); + const foreignKeysList = res.foreignKeys.map((foreignKey: TableForeignKey) => foreignKey.column_name); + const filedsTypes = getTableTypes(res.structure, foreignKeysList); const formattedRecord = Object.entries(res.row).reduce((acc, [key, value]) => { acc[key] = formatFieldValue(value, filedsTypes[key]); @@ -494,7 +494,7 @@ export class DbTableComponent implements OnInit { [foreignKeys.referenced_column_name]: res.row[foreignKeys.referenced_column_name] }, foreignKeys: Object.assign({}, ...res.foreignKeys.map((foreignKey: TableForeignKey) => ({[foreignKey.column_name]: foreignKey}))), - foreignKeysList: res.foreignKeys.map(fk => fk.column_name), + foreignKeysList, widgets: Object.assign({}, ...res.table_widgets.map((widget: Widget) => { let parsedParams; @@ -513,6 +513,7 @@ export class DbTableComponent implements OnInit { }) ), widgetsList: res.table_widgets.map(widget => widget.field_name), + fieldsTypes: filedsTypes, relatedRecords: res.referenced_table_names_and_columns[0], link: `/dashboard/${this.connectionID}/${foreignKeys.referenced_table_name}/entry` }); diff --git a/frontend/src/app/components/db-table-row-edit/db-table-row-edit.component.ts b/frontend/src/app/components/db-table-row-edit/db-table-row-edit.component.ts index 366a08b38..5f71c3e27 100644 --- a/frontend/src/app/components/db-table-row-edit/db-table-row-edit.component.ts +++ b/frontend/src/app/components/db-table-row-edit/db-table-row-edit.component.ts @@ -270,7 +270,7 @@ export class DbTableRowEditComponent implements OnInit { chunkSize: 30, filters }).subscribe((res) => { - + const foreignKeysList = res.foreignKeys.map((foreignKey: TableForeignKey) => foreignKey.column_name); this.relatedRecordsProperties = Object.assign({}, this.relatedRecordsProperties, { [table.table_name]: { connectionID: this.connectionID, @@ -278,7 +278,7 @@ export class DbTableRowEditComponent implements OnInit { columnsOrder: res.list_fields, primaryColumns: res.primaryColumns, foreignKeys: Object.assign({}, ...res.foreignKeys.map((foreignKey: TableForeignKey) => ({[foreignKey.column_name]: foreignKey}))), - foreignKeysList: res.foreignKeys.map(fk => fk.column_name), + foreignKeysList, widgets: Object.assign({}, ...res.widgets.map((widget: Widget) => { let parsedParams; @@ -297,6 +297,7 @@ export class DbTableRowEditComponent implements OnInit { }) ), widgetsList: res.widgets.map(widget => widget.field_name), + fieldsTypes: getTableTypes(res.structure, foreignKeysList), relatedRecords: [], link: `/dashboard/${this.connectionID}/${table.table_name}/entry` } diff --git a/frontend/src/app/components/ui-components/record-view-fields/base-record-view-field/base-record-view-field.component.css b/frontend/src/app/components/ui-components/record-view-fields/base-record-view-field/base-record-view-field.component.css index eb518d97e..967fc930d 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/base-record-view-field/base-record-view-field.component.css +++ b/frontend/src/app/components/ui-components/record-view-fields/base-record-view-field/base-record-view-field.component.css @@ -1,26 +1,25 @@ -.field-display { - position: relative; - display: flex; - align-items: center; +.field-view-value { + word-wrap: anywhere; + word-break: keep-all; + white-space: break-spaces; + max-width: 100%; } -.field-value { - flex-grow: 1 0 auto; - text-overflow: ellipsis; - overflow: hidden; - white-space: nowrap; +@media (prefers-color-scheme: light) { + .field-view-value { + color: rgba(0, 0, 0, 0.64); + } } -.field-copy-button { - position: absolute; - right: -6px; - top: 50%; - background-color: var(--hover-color); - transform: translate(0, -50%) scale(0.85); - opacity: 0; - transition: opacity 0.1s ease-in-out; +@media (prefers-color-scheme: dark) { + .field-view-value { + color: rgba(255, 255, 255, 0.64); + } } -.field-display:hover .field-copy-button { - opacity: 1; -} +.field-view-icon { + font-size: 16px; + height: 16px; + margin-left: 8px; + width: 16px; +} \ No newline at end of file diff --git a/frontend/src/app/components/ui-components/record-view-fields/binary-data-caption/binary-data-caption.component.ts b/frontend/src/app/components/ui-components/record-view-fields/binary-data-caption/binary-data-caption.component.ts index f87649a5e..c377e06d0 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/binary-data-caption/binary-data-caption.component.ts +++ b/frontend/src/app/components/ui-components/record-view-fields/binary-data-caption/binary-data-caption.component.ts @@ -7,7 +7,7 @@ import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-rec @Injectable() @Component({ - selector: 'app-binary-data-caption-display', + selector: 'app-binary-data-caption-record-view', templateUrl: './binary-data-caption.component.html', styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './binary-data-caption.component.css'], imports: [CommonModule, MatIconModule, MatButtonModule, MatTooltipModule] diff --git a/frontend/src/app/components/ui-components/record-view-fields/boolean/boolean.component.html b/frontend/src/app/components/ui-components/record-view-fields/boolean/boolean.component.html index a83870454..6afe2967d 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/boolean/boolean.component.html +++ b/frontend/src/app/components/ui-components/record-view-fields/boolean/boolean.component.html @@ -1,7 +1,3 @@ -
-
- check_small - close_small - -
-
+check_small +close_small + diff --git a/frontend/src/app/components/ui-components/record-view-fields/boolean/boolean.component.ts b/frontend/src/app/components/ui-components/record-view-fields/boolean/boolean.component.ts index df2857e78..0947ac496 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/boolean/boolean.component.ts +++ b/frontend/src/app/components/ui-components/record-view-fields/boolean/boolean.component.ts @@ -1,19 +1,16 @@ import { Component, Injectable } from '@angular/core'; -import { ClipboardModule } from '@angular/cdk/clipboard'; import { CommonModule } from '@angular/common'; -import { MatButtonModule } from '@angular/material/button'; import { MatIconModule } from '@angular/material/icon'; -import { MatTooltipModule } from '@angular/material/tooltip'; import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; @Injectable() @Component({ - selector: 'app-display-boolean', + selector: 'app-boolean-record-view', templateUrl: './boolean.component.html', styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './boolean.component.css'], - imports: [ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule, CommonModule] + imports: [MatIconModule, CommonModule] }) export class BooleanRecordViewComponent extends BaseRecordViewFieldComponent { } diff --git a/frontend/src/app/components/ui-components/record-view-fields/code/code.component.css b/frontend/src/app/components/ui-components/record-view-fields/code/code.component.css index 1e61ec077..103d0c4a3 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/code/code.component.css +++ b/frontend/src/app/components/ui-components/record-view-fields/code/code.component.css @@ -1,12 +1,20 @@ -.field-value { - background-color: #EAEAFF; - border-radius: 4px; - font-family: monospace; - padding: 0 8px; +:host { + width: 100%; } -@media (prefers-color-scheme: dark) { - .field-value { - background-color: #2C2C54; - } +.code-editor-box { + display: block; + border: 1px solid rgba(0, 0, 0, 0.38); + border-radius: 0; + margin-top: 4px; + margin-bottom: 20px; + /* overflow-y: auto; + resize: vertical; */ + overflow: auto; + resize: both; } + +.code-editor-box ::ng-deep .ngs-code-editor { + width: 100%; + height: 100%; +} \ No newline at end of file diff --git a/frontend/src/app/components/ui-components/record-view-fields/code/code.component.html b/frontend/src/app/components/ui-components/record-view-fields/code/code.component.html index acf48b2d5..bc49d5236 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/code/code.component.html +++ b/frontend/src/app/components/ui-components/record-view-fields/code/code.component.html @@ -1,11 +1,9 @@ -
- {{value || '—'}} - +
+ +
+ diff --git a/frontend/src/app/components/ui-components/record-view-fields/code/code.component.ts b/frontend/src/app/components/ui-components/record-view-fields/code/code.component.ts index 10ac1a228..03ddbcbcd 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/code/code.component.ts +++ b/frontend/src/app/components/ui-components/record-view-fields/code/code.component.ts @@ -1,17 +1,40 @@ import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; -import { ClipboardModule } from '@angular/cdk/clipboard'; -import { CommonModule } from '@angular/common'; import { Component, Injectable } from '@angular/core'; -import { MatButtonModule } from '@angular/material/button'; -import { MatIconModule } from '@angular/material/icon'; -import { MatTooltipModule } from '@angular/material/tooltip'; +import { CodeEditorModule } from '@ngstack/code-editor'; +import { UiSettingsService } from 'src/app/services/ui-settings.service'; @Injectable() @Component({ - selector: 'app-code-display', + selector: 'app-code-record-view', templateUrl: './code.component.html', styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './code.component.css'], - imports: [ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule, CommonModule] + imports: [CodeEditorModule] }) export class CodeRecordViewComponent extends BaseRecordViewFieldComponent { + + public codeModel: Object; + public codeEditorOptions = { + minimap: { enabled: false }, + automaticLayout: true, + scrollBeyondLastLine: false, + wordWrap: 'on', + lineNumbers: 'off' + }; + public codeEditorTheme = 'vs-dark'; + + constructor( + private _uiSettings: UiSettingsService, + ) { + super(); + } + + ngOnInit(): void { + this.codeModel = { + language: `${this.widgetStructure.widget_params.language}`, + uri: `${this.key}.json`, + value: this.value, + } + + this.codeEditorTheme = this._uiSettings.editorTheme; + } } diff --git a/frontend/src/app/components/ui-components/record-view-fields/color/color.component.html b/frontend/src/app/components/ui-components/record-view-fields/color/color.component.html index f144cacdc..6e2da6998 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/color/color.component.html +++ b/frontend/src/app/components/ui-components/record-view-fields/color/color.component.html @@ -1,18 +1,8 @@ -
-
-
- {{value || '—'}} -
- +
+
+ {{value || '—'}}
\ No newline at end of file diff --git a/frontend/src/app/components/ui-components/record-view-fields/color/color.component.ts b/frontend/src/app/components/ui-components/record-view-fields/color/color.component.ts index b40fe6a4c..581351e80 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/color/color.component.ts +++ b/frontend/src/app/components/ui-components/record-view-fields/color/color.component.ts @@ -1,19 +1,15 @@ import { Component, Injectable } from '@angular/core'; import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; -import { ClipboardModule } from '@angular/cdk/clipboard'; -import { CommonModule } from '@angular/common'; -import { MatButtonModule } from '@angular/material/button'; -import { MatIconModule } from '@angular/material/icon'; -import { MatTooltipModule } from '@angular/material/tooltip'; import colorString from 'color-string'; +import { CommonModule } from '@angular/common'; @Injectable() @Component({ - selector: 'app-display-color', + selector: 'app-color-record-view', templateUrl: './color.component.html', styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './color.component.css'], - imports: [CommonModule, ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule] + imports: [CommonModule] }) export class ColorRecordViewComponent extends BaseRecordViewFieldComponent { get isValidColor(): boolean { @@ -33,16 +29,16 @@ export class ColorRecordViewComponent extends BaseRecordViewFieldComponent { private parseColor(color: string): any { if (!color) return null; - + // Try parsing with color-string const parsed = colorString.get(color); if (parsed) return parsed; - + // Try hex without hash if (/^[A-Fa-f0-9]{6}$|^[A-Fa-f0-9]{3}$/.test(color)) { return colorString.get('#' + color); } - + return null; } diff --git a/frontend/src/app/components/ui-components/record-view-fields/country/country.component.css b/frontend/src/app/components/ui-components/record-view-fields/country/country.component.css index b3e456f15..cc2400ea0 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/country/country.component.css +++ b/frontend/src/app/components/ui-components/record-view-fields/country/country.component.css @@ -1,27 +1,4 @@ -.field-wrapper { - display: flex; - align-items: center; -} - -.value-wrapper { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - max-width: 300px; - display: flex; - align-items: center; -} - .country-flag { margin-right: 6px; font-size: 1.2em; } - -.copy-button { - visibility: hidden; - margin-left: 4px; -} - -.field-wrapper:hover .copy-button { - visibility: visible; -} diff --git a/frontend/src/app/components/ui-components/record-view-fields/country/country.component.html b/frontend/src/app/components/ui-components/record-view-fields/country/country.component.html index 54639a23b..27895c83a 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/country/country.component.html +++ b/frontend/src/app/components/ui-components/record-view-fields/country/country.component.html @@ -1,14 +1,4 @@ -
- - {{ countryFlag }} - {{ countryName }} - - -
+ + {{ countryFlag }} + {{ countryName }} + diff --git a/frontend/src/app/components/ui-components/record-view-fields/country/country.component.ts b/frontend/src/app/components/ui-components/record-view-fields/country/country.component.ts index c3b24fa86..4b841e4e0 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/country/country.component.ts +++ b/frontend/src/app/components/ui-components/record-view-fields/country/country.component.ts @@ -2,18 +2,14 @@ import { COUNTRIES, getCountryFlag } from '../../../../consts/countries'; import { Component, Injectable, OnChanges, OnInit, SimpleChanges } from '@angular/core'; import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; -import { ClipboardModule } from '@angular/cdk/clipboard'; import { CommonModule } from '@angular/common'; -import { MatButtonModule } from '@angular/material/button'; -import { MatIconModule } from '@angular/material/icon'; -import { MatTooltipModule } from '@angular/material/tooltip'; @Injectable() @Component({ - selector: 'app-country-display', + selector: 'app-country-record-view', templateUrl: './country.component.html', styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './country.component.css'], - imports: [ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule, CommonModule] + imports: [CommonModule] }) export class CountryRecordViewComponent extends BaseRecordViewFieldComponent implements OnInit { static type = 'country'; @@ -24,7 +20,7 @@ export class CountryRecordViewComponent extends BaseRecordViewFieldComponent imp ngOnInit(): void { this.parseWidgetParams(); - + if (this.value) { const country = COUNTRIES.find(c => c.code === this.value); this.countryName = country ? country.name : this.value; @@ -38,10 +34,10 @@ export class CountryRecordViewComponent extends BaseRecordViewFieldComponent imp private parseWidgetParams(): void { if (this.widgetStructure?.widget_params) { try { - const params = typeof this.widgetStructure.widget_params === 'string' - ? JSON.parse(this.widgetStructure.widget_params) + const params = typeof this.widgetStructure.widget_params === 'string' + ? JSON.parse(this.widgetStructure.widget_params) : this.widgetStructure.widget_params; - + if (params.show_flag !== undefined) { this.showFlag = params.show_flag; } diff --git a/frontend/src/app/components/ui-components/record-view-fields/date-time/date-time.component.html b/frontend/src/app/components/ui-components/record-view-fields/date-time/date-time.component.html index 43432b87e..c6ed53b32 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/date-time/date-time.component.html +++ b/frontend/src/app/components/ui-components/record-view-fields/date-time/date-time.component.html @@ -1,11 +1 @@ -
- {{formattedDateTime || '—'}} - -
+{{formattedDateTime || '—'}} diff --git a/frontend/src/app/components/ui-components/record-view-fields/date-time/date-time.component.ts b/frontend/src/app/components/ui-components/record-view-fields/date-time/date-time.component.ts index e36ed1238..1eb0ff15a 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/date-time/date-time.component.ts +++ b/frontend/src/app/components/ui-components/record-view-fields/date-time/date-time.component.ts @@ -1,19 +1,14 @@ import { Component, Injectable, OnInit } from '@angular/core'; import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; -import { ClipboardModule } from '@angular/cdk/clipboard'; -import { CommonModule } from '@angular/common'; -import { MatButtonModule } from '@angular/material/button'; -import { MatIconModule } from '@angular/material/icon'; -import { MatTooltipModule } from '@angular/material/tooltip'; import { format } from 'date-fns'; @Injectable() @Component({ - selector: 'app-date-time-display', + selector: 'app-date-time-record-view', templateUrl: './date-time.component.html', styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './date-time.component.css'], - imports: [ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule, CommonModule] + imports: [] }) export class DateTimeRecordViewComponent extends BaseRecordViewFieldComponent implements OnInit { static type = 'datetime'; diff --git a/frontend/src/app/components/ui-components/record-view-fields/date/date.component.html b/frontend/src/app/components/ui-components/record-view-fields/date/date.component.html index 36172b273..5edf46f97 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/date/date.component.html +++ b/frontend/src/app/components/ui-components/record-view-fields/date/date.component.html @@ -1,11 +1 @@ -
- {{formattedDate || '—'}} - -
+{{formattedDate || '—'}} diff --git a/frontend/src/app/components/ui-components/record-view-fields/date/date.component.ts b/frontend/src/app/components/ui-components/record-view-fields/date/date.component.ts index 501499cd5..846ccd903 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/date/date.component.ts +++ b/frontend/src/app/components/ui-components/record-view-fields/date/date.component.ts @@ -2,18 +2,13 @@ import { Component, Injectable, OnInit } from '@angular/core'; import { format, parseISO } from 'date-fns'; import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; -import { ClipboardModule } from '@angular/cdk/clipboard'; -import { CommonModule } from '@angular/common'; -import { MatButtonModule } from '@angular/material/button'; -import { MatIconModule } from '@angular/material/icon'; -import { MatTooltipModule } from '@angular/material/tooltip'; @Injectable() @Component({ - selector: 'app-date-display', + selector: 'app-date-record-view', templateUrl: './date.component.html', styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './date.component.css'], - imports: [ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule, CommonModule] + imports: [] }) export class DateRecordViewComponent extends BaseRecordViewFieldComponent implements OnInit { static type = 'date'; diff --git a/frontend/src/app/components/ui-components/record-view-fields/file/file.component.html b/frontend/src/app/components/ui-components/record-view-fields/file/file.component.html index e490bcd7b..b05b4f798 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/file/file.component.html +++ b/frontend/src/app/components/ui-components/record-view-fields/file/file.component.html @@ -1,3 +1 @@ -
- {{displayText}} -
+{{displayText}} diff --git a/frontend/src/app/components/ui-components/record-view-fields/file/file.component.ts b/frontend/src/app/components/ui-components/record-view-fields/file/file.component.ts index 99a913df2..77dfad7d5 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/file/file.component.ts +++ b/frontend/src/app/components/ui-components/record-view-fields/file/file.component.ts @@ -1,10 +1,5 @@ import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; -import { ClipboardModule } from '@angular/cdk/clipboard'; -import { CommonModule } from '@angular/common'; import { Component, Injectable } from '@angular/core'; -import { MatButtonModule } from '@angular/material/button'; -import { MatIconModule } from '@angular/material/icon'; -import { MatTooltipModule } from '@angular/material/tooltip'; interface Blob { type: string; @@ -13,10 +8,10 @@ interface Blob { @Injectable() @Component({ - selector: 'app-file-display', + selector: 'app-file-record-view', templateUrl: './file.component.html', styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './file.component.css'], - imports: [ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule, CommonModule] + imports: [] }) export class FileRecordViewComponent extends BaseRecordViewFieldComponent { get isBlob(): boolean { diff --git a/frontend/src/app/components/ui-components/record-view-fields/foreign-key/foreign-key.component.css b/frontend/src/app/components/ui-components/record-view-fields/foreign-key/foreign-key.component.css index e818ae5cc..700cad576 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/foreign-key/foreign-key.component.css +++ b/frontend/src/app/components/ui-components/record-view-fields/foreign-key/foreign-key.component.css @@ -1,27 +1,17 @@ -.foreign-key-button { - background: transparent; - border: 1px solid transparent; - border-radius: 12px; - color: var(--color-accentedPalette-500); - cursor: pointer; - font-size: inherit; - padding: 2px 8px; - overflow: hidden; - text-overflow: ellipsis; - text-align: left; - max-width: 100%; - transition: background 100ms, border-color 100ms; +.foreign-key-link { + display: flex; + align-items: center; + text-decoration: none; } -.foreign-key-button:hover{ - background-color: var(--color-accentedPalette-100); - border: 1px solid var(--color-accentedPalette-300); +@media (prefers-color-scheme: light) { + .foreign-key-link { + border-bottom: 1px solid rgba(0, 0, 0, 0.64); + } } -.foreign-key-button_selected { - background-color: var(--color-accentedPalette-100); - border-radius: 12px; - border: 1px solid var(--color-accentedPalette-300); -} - - +@media (prefers-color-scheme: dark) { + .foreign-key-link { + border-bottom: 1px solid rgba(255, 255, 255, 0.64); + } +} \ No newline at end of file diff --git a/frontend/src/app/components/ui-components/record-view-fields/foreign-key/foreign-key.component.html b/frontend/src/app/components/ui-components/record-view-fields/foreign-key/foreign-key.component.html index c4e04ce2f..9eaaa8314 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/foreign-key/foreign-key.component.html +++ b/frontend/src/app/components/ui-components/record-view-fields/foreign-key/foreign-key.component.html @@ -1,21 +1,8 @@ -
-
- - {{ value || '—' }} -
- -
+ + {{displayValue}} + edit + diff --git a/frontend/src/app/components/ui-components/record-view-fields/foreign-key/foreign-key.component.ts b/frontend/src/app/components/ui-components/record-view-fields/foreign-key/foreign-key.component.ts index 03cf9a741..569dff91e 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/foreign-key/foreign-key.component.ts +++ b/frontend/src/app/components/ui-components/record-view-fields/foreign-key/foreign-key.component.ts @@ -6,32 +6,23 @@ import { CommonModule } from '@angular/common'; import { MatButtonModule } from '@angular/material/button'; import { MatIconModule } from '@angular/material/icon'; import { MatTooltipModule } from '@angular/material/tooltip'; -import { TableForeignKey } from 'src/app/models/table'; +import { RouterModule } from '@angular/router'; @Injectable() @Component({ - selector: 'app-display-foreign-key', + selector: 'app-foreign-key-record-view', templateUrl: './foreign-key.component.html', styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './foreign-key.component.css'], - imports: [ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule, CommonModule] + imports: [MatIconModule, RouterModule, CommonModule] }) export class ForeignKeyRecordViewComponent extends BaseRecordViewFieldComponent { - @Input() isSelected: boolean = false; - @Input() relations: TableForeignKey; + @Input() link: string; + @Input() primaryKeysParams: any; + @Input() displayValue: string; @Output() onForeignKeyClick = new EventEmitter<{foreignKey: any, value: string}>(); constructor() { super(); } - - handleForeignKeyClick($event): void { - $event.stopPropagation(); - if (this.relations && this.value) { - this.onForeignKeyClick.emit({ - foreignKey: this.relations, - value: this.value - }); - } - } } diff --git a/frontend/src/app/components/ui-components/record-view-fields/id/id.component.html b/frontend/src/app/components/ui-components/record-view-fields/id/id.component.html index 1f1908b5a..a7259d1fb 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/id/id.component.html +++ b/frontend/src/app/components/ui-components/record-view-fields/id/id.component.html @@ -1,12 +1 @@ -
- {{value || '—'}} - -
+{{value || '—'}} diff --git a/frontend/src/app/components/ui-components/record-view-fields/id/id.component.ts b/frontend/src/app/components/ui-components/record-view-fields/id/id.component.ts index ff9ce715e..0289f4b78 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/id/id.component.ts +++ b/frontend/src/app/components/ui-components/record-view-fields/id/id.component.ts @@ -1,18 +1,13 @@ import { Component, Injectable } from '@angular/core'; import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; -import { ClipboardModule } from '@angular/cdk/clipboard'; -import { CommonModule } from '@angular/common'; -import { MatButtonModule } from '@angular/material/button'; -import { MatIconModule } from '@angular/material/icon'; -import { MatTooltipModule } from '@angular/material/tooltip'; @Injectable() @Component({ - selector: 'app-display-id', + selector: 'app-id-record-view', templateUrl: './id.component.html', styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './id.component.css'], - imports: [ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule, CommonModule] + imports: [] }) export class IdRecordViewComponent extends BaseRecordViewFieldComponent { } diff --git a/frontend/src/app/components/ui-components/record-view-fields/image/image.component.css b/frontend/src/app/components/ui-components/record-view-fields/image/image.component.css index fad6ddbcf..5decf8e34 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/image/image.component.css +++ b/frontend/src/app/components/ui-components/record-view-fields/image/image.component.css @@ -1,10 +1,4 @@ -.field-value { - font-style: italic; - color: #666; -} - -.image-thumbnail { - display: block; - height: var(--height); - margin: 12px 0; +.image-preview { + width: 100%; + height: auto; } diff --git a/frontend/src/app/components/ui-components/record-view-fields/image/image.component.html b/frontend/src/app/components/ui-components/record-view-fields/image/image.component.html index dd64c06b4..f4f494885 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/image/image.component.html +++ b/frontend/src/app/components/ui-components/record-view-fields/image/image.component.html @@ -1,15 +1,5 @@ -
- [Image URL] - Image - -
+[Image URL] +Image +{{value || '—'}} diff --git a/frontend/src/app/components/ui-components/record-view-fields/image/image.component.ts b/frontend/src/app/components/ui-components/record-view-fields/image/image.component.ts index 01aa59bbb..e2d9f7df4 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/image/image.component.ts +++ b/frontend/src/app/components/ui-components/record-view-fields/image/image.component.ts @@ -1,17 +1,13 @@ -import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; -import { ClipboardModule } from '@angular/cdk/clipboard'; import { CommonModule } from '@angular/common'; +import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; import { Component, Injectable } from '@angular/core'; -import { MatButtonModule } from '@angular/material/button'; -import { MatIconModule } from '@angular/material/icon'; -import { MatTooltipModule } from '@angular/material/tooltip'; @Injectable() @Component({ - selector: 'app-image-display', + selector: 'app-image-record-view', templateUrl: './image.component.html', styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './image.component.css'], - imports: [ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule, CommonModule] + imports: [CommonModule] }) export class ImageRecordViewComponent extends BaseRecordViewFieldComponent { get isUrl(): boolean { diff --git a/frontend/src/app/components/ui-components/record-view-fields/json-editor/json-editor.component.css b/frontend/src/app/components/ui-components/record-view-fields/json-editor/json-editor.component.css index 354fa288a..103d0c4a3 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/json-editor/json-editor.component.css +++ b/frontend/src/app/components/ui-components/record-view-fields/json-editor/json-editor.component.css @@ -1,6 +1,20 @@ -.json-display { - background-color: #EAEAFF; - border-radius: 4px; - font-family: monospace; - padding: 0 8px; +:host { + width: 100%; } + +.code-editor-box { + display: block; + border: 1px solid rgba(0, 0, 0, 0.38); + border-radius: 0; + margin-top: 4px; + margin-bottom: 20px; + /* overflow-y: auto; + resize: vertical; */ + overflow: auto; + resize: both; +} + +.code-editor-box ::ng-deep .ngs-code-editor { + width: 100%; + height: 100%; +} \ No newline at end of file diff --git a/frontend/src/app/components/ui-components/record-view-fields/json-editor/json-editor.component.html b/frontend/src/app/components/ui-components/record-view-fields/json-editor/json-editor.component.html index 4a6211393..d89f394c2 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/json-editor/json-editor.component.html +++ b/frontend/src/app/components/ui-components/record-view-fields/json-editor/json-editor.component.html @@ -1,11 +1,8 @@ -
-
{{ formattedJson }}
- +
+ +
diff --git a/frontend/src/app/components/ui-components/record-view-fields/json-editor/json-editor.component.ts b/frontend/src/app/components/ui-components/record-view-fields/json-editor/json-editor.component.ts index ee087edc1..e6fb6fa3c 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/json-editor/json-editor.component.ts +++ b/frontend/src/app/components/ui-components/record-view-fields/json-editor/json-editor.component.ts @@ -1,27 +1,39 @@ import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; -import { ClipboardModule } from '@angular/cdk/clipboard'; -import { CommonModule } from '@angular/common'; import { Component, Injectable } from '@angular/core'; -import { MatButtonModule } from '@angular/material/button'; -import { MatIconModule } from '@angular/material/icon'; -import { MatTooltipModule } from '@angular/material/tooltip'; +import { CodeEditorModule } from '@ngstack/code-editor'; +import { UiSettingsService } from 'src/app/services/ui-settings.service'; @Injectable() @Component({ - selector: 'app-json-editor-display', + selector: 'app-json-editor-record-view', templateUrl: './json-editor.component.html', styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './json-editor.component.css'], - imports: [ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule, CommonModule] + imports: [CodeEditorModule] }) export class JsonEditorRecordViewComponent extends BaseRecordViewFieldComponent { - get formattedJson(): string { - if (!this.value) return ''; + public codeModel: Object; + public codeEditorOptions = { + minimap: { enabled: false }, + automaticLayout: true, + scrollBeyondLastLine: false, + wordWrap: 'on', + lineNumbers: 'off' + }; + public codeEditorTheme = 'vs-dark'; - try { - const parsedValue = typeof this.value === 'string' ? JSON.parse(this.value) : this.value; - return JSON.stringify(parsedValue, null, 2); - } catch (e) { - return String(this.value); + constructor( + private _uiSettings: UiSettingsService, + ) { + super(); + } + + ngOnInit(): void { + this.codeModel = { + language: 'json', + uri: `${this.key}.json`, + value: this.value } + + this.codeEditorTheme = this._uiSettings.editorTheme; } } diff --git a/frontend/src/app/components/ui-components/record-view-fields/long-text/long-text.component.css b/frontend/src/app/components/ui-components/record-view-fields/long-text/long-text.component.css index adb834c90..e69de29bb 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/long-text/long-text.component.css +++ b/frontend/src/app/components/ui-components/record-view-fields/long-text/long-text.component.css @@ -1,4 +0,0 @@ -.field-value { - height: 36px; - line-height: 36px; -} diff --git a/frontend/src/app/components/ui-components/record-view-fields/long-text/long-text.component.html b/frontend/src/app/components/ui-components/record-view-fields/long-text/long-text.component.html index 79e15809d..7dfcb3f4b 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/long-text/long-text.component.html +++ b/frontend/src/app/components/ui-components/record-view-fields/long-text/long-text.component.html @@ -1,12 +1 @@ -
- {{value || '—'}} - -
+{{value || '—'}} diff --git a/frontend/src/app/components/ui-components/record-view-fields/long-text/long-text.component.ts b/frontend/src/app/components/ui-components/record-view-fields/long-text/long-text.component.ts index 89894c36a..84c4f8733 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/long-text/long-text.component.ts +++ b/frontend/src/app/components/ui-components/record-view-fields/long-text/long-text.component.ts @@ -1,18 +1,13 @@ import { Component, Injectable } from '@angular/core'; import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; -import { ClipboardModule } from '@angular/cdk/clipboard'; -import { CommonModule } from '@angular/common'; -import { MatButtonModule } from '@angular/material/button'; -import { MatIconModule } from '@angular/material/icon'; -import { MatTooltipModule } from '@angular/material/tooltip'; @Injectable() @Component({ - selector: 'app-display-long-text', + selector: 'app-long-text-record-view', templateUrl: './long-text.component.html', styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './long-text.component.css'], - imports: [CommonModule, ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule] + imports: [] }) export class LongTextRecordViewComponent extends BaseRecordViewFieldComponent { diff --git a/frontend/src/app/components/ui-components/record-view-fields/money/money.component.html b/frontend/src/app/components/ui-components/record-view-fields/money/money.component.html index 202929d6b..cba669daf 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/money/money.component.html +++ b/frontend/src/app/components/ui-components/record-view-fields/money/money.component.html @@ -1,13 +1,3 @@ -
- + {{formattedValue || '—'}} - -
diff --git a/frontend/src/app/components/ui-components/record-view-fields/money/money.component.ts b/frontend/src/app/components/ui-components/record-view-fields/money/money.component.ts index 8c8f380a5..f0154db66 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/money/money.component.ts +++ b/frontend/src/app/components/ui-components/record-view-fields/money/money.component.ts @@ -1,19 +1,14 @@ import { Component, Injectable, OnInit } from '@angular/core'; import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; -import { ClipboardModule } from '@angular/cdk/clipboard'; -import { CommonModule } from '@angular/common'; -import { MatButtonModule } from '@angular/material/button'; -import { MatIconModule } from '@angular/material/icon'; -import { MatTooltipModule } from '@angular/material/tooltip'; import { getCurrencyByCode } from 'src/app/consts/currencies'; @Injectable() @Component({ - selector: 'app-money-display', + selector: 'app-money-record-view', templateUrl: './money.component.html', styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './money.component.css'], - imports: [ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule, CommonModule] + imports: [] }) export class MoneyRecordViewComponent extends BaseRecordViewFieldComponent implements OnInit { public displayCurrency: string = ''; diff --git a/frontend/src/app/components/ui-components/record-view-fields/number/number.component.html b/frontend/src/app/components/ui-components/record-view-fields/number/number.component.html index 356e592cb..8f3bd4c32 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/number/number.component.html +++ b/frontend/src/app/components/ui-components/record-view-fields/number/number.component.html @@ -1,11 +1 @@ -
- {{displayValue}} - -
+{{displayValue}} diff --git a/frontend/src/app/components/ui-components/record-view-fields/number/number.component.ts b/frontend/src/app/components/ui-components/record-view-fields/number/number.component.ts index 7977f5173..bb3773ddf 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/number/number.component.ts +++ b/frontend/src/app/components/ui-components/record-view-fields/number/number.component.ts @@ -1,28 +1,23 @@ -import { ClipboardModule } from '@angular/cdk/clipboard'; import { Component, Injectable } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { MatButtonModule } from '@angular/material/button'; -import { MatIconModule } from '@angular/material/icon'; -import { MatTooltipModule } from '@angular/material/tooltip'; import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; import convert from 'convert'; @Injectable() @Component({ - selector: 'app-display-number', + selector: 'app-number-record-view', templateUrl: './number.component.html', styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './number.component.css'], - imports: [ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule, CommonModule] + imports: [] }) export class NumberRecordViewComponent extends BaseRecordViewFieldComponent { - + get displayValue(): string { if (this.value == null || this.value === '') { return '—'; } const unit = this.widgetStructure?.widget_params?.unit; - + if (!unit) { return this.value.toString(); } diff --git a/frontend/src/app/components/ui-components/record-view-fields/password/password.component.html b/frontend/src/app/components/ui-components/record-view-fields/password/password.component.html index bc4098081..a1e3ab35b 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/password/password.component.html +++ b/frontend/src/app/components/ui-components/record-view-fields/password/password.component.html @@ -1,3 +1 @@ -
- •••••••• -
+•••••••• diff --git a/frontend/src/app/components/ui-components/record-view-fields/password/password.component.ts b/frontend/src/app/components/ui-components/record-view-fields/password/password.component.ts index c057fd5c9..a61eac033 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/password/password.component.ts +++ b/frontend/src/app/components/ui-components/record-view-fields/password/password.component.ts @@ -1,17 +1,13 @@ import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; -import { ClipboardModule } from '@angular/cdk/clipboard'; -import { CommonModule } from '@angular/common'; import { Component, Injectable } from '@angular/core'; -import { MatButtonModule } from '@angular/material/button'; -import { MatIconModule } from '@angular/material/icon'; -import { MatTooltipModule } from '@angular/material/tooltip'; + @Injectable() @Component({ - selector: 'app-password-display', + selector: 'app-password-record-view', templateUrl: './password.component.html', styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './password.component.css'], - imports: [ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule, CommonModule] + imports: [] }) export class PasswordRecordViewComponent extends BaseRecordViewFieldComponent { } diff --git a/frontend/src/app/components/ui-components/record-view-fields/phone/phone.component.css b/frontend/src/app/components/ui-components/record-view-fields/phone/phone.component.css index e325e57dd..094c8843b 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/phone/phone.component.css +++ b/frontend/src/app/components/ui-components/record-view-fields/phone/phone.component.css @@ -1,7 +1,3 @@ -.field-display { - padding-right: 24px; -} - .phone-content { display: flex; align-items: center; @@ -15,6 +11,5 @@ } .phone-link { - text-decoration: none; color: var(--primary-color); } \ No newline at end of file diff --git a/frontend/src/app/components/ui-components/record-view-fields/phone/phone.component.html b/frontend/src/app/components/ui-components/record-view-fields/phone/phone.component.html index bfbc51f33..c7aad71e8 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/phone/phone.component.html +++ b/frontend/src/app/components/ui-components/record-view-fields/phone/phone.component.html @@ -1,15 +1,4 @@ -
- - {{ countryFlag }} - {{ formattedNumber || value }} - - - -
+ + {{ countryFlag }} + {{ formattedNumber || value }} + \ No newline at end of file diff --git a/frontend/src/app/components/ui-components/record-view-fields/phone/phone.component.ts b/frontend/src/app/components/ui-components/record-view-fields/phone/phone.component.ts index 96d8ecb04..133a663d9 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/phone/phone.component.ts +++ b/frontend/src/app/components/ui-components/record-view-fields/phone/phone.component.ts @@ -1,25 +1,22 @@ import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; -import { ClipboardModule } from '@angular/cdk/clipboard'; -import { CommonModule } from '@angular/common'; import { Component, Injectable, OnInit } from '@angular/core'; -import { MatButtonModule } from '@angular/material/button'; -import { MatIconModule } from '@angular/material/icon'; -import { MatTooltipModule } from '@angular/material/tooltip'; import { parsePhoneNumber } from 'libphonenumber-js'; import { COUNTRIES, getCountryFlag } from '../../../../consts/countries'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { CommonModule } from '@angular/common'; @Injectable() @Component({ - selector: 'app-phone-display', + selector: 'app-phone-record-view', templateUrl: './phone.component.html', styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './phone.component.css'], - imports: [ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule, CommonModule] + imports: [MatTooltipModule, CommonModule] }) export class PhoneRecordViewComponent extends BaseRecordViewFieldComponent implements OnInit { public countryFlag: string = ''; public countryName: string = ''; public formattedNumber: string = ''; - + ngOnInit(): void { this.parsePhoneNumber(); } @@ -34,10 +31,10 @@ export class PhoneRecordViewComponent extends BaseRecordViewFieldComponent imple try { const phoneNumber = parsePhoneNumber(this.value); - + if (phoneNumber && phoneNumber.country) { const country = COUNTRIES.find(c => c.code === phoneNumber.country); - + if (country) { this.countryFlag = getCountryFlag(country.code); this.countryName = country.name; diff --git a/frontend/src/app/components/ui-components/record-view-fields/point/point.component.css b/frontend/src/app/components/ui-components/record-view-fields/point/point.component.css index 1296352f2..8b1378917 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/point/point.component.css +++ b/frontend/src/app/components/ui-components/record-view-fields/point/point.component.css @@ -1,21 +1 @@ -.field-wrapper { - display: flex; - align-items: center; -} -.value-wrapper { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - max-width: 300px; - font-family: monospace; -} - -.copy-button { - visibility: hidden; - margin-left: 4px; -} - -.field-wrapper:hover .copy-button { - visibility: visible; -} diff --git a/frontend/src/app/components/ui-components/record-view-fields/point/point.component.html b/frontend/src/app/components/ui-components/record-view-fields/point/point.component.html index 2e30aeeca..5ea1fcb37 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/point/point.component.html +++ b/frontend/src/app/components/ui-components/record-view-fields/point/point.component.html @@ -1,11 +1,5 @@ -
- {{ formattedPoint }} - -
+ + {{ formattedPoint }} + diff --git a/frontend/src/app/components/ui-components/record-view-fields/point/point.component.ts b/frontend/src/app/components/ui-components/record-view-fields/point/point.component.ts index 38a3fc0ad..28aa20ea1 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/point/point.component.ts +++ b/frontend/src/app/components/ui-components/record-view-fields/point/point.component.ts @@ -1,18 +1,14 @@ import { Component, Injectable, OnInit } from '@angular/core'; import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; -import { ClipboardModule } from '@angular/cdk/clipboard'; -import { CommonModule } from '@angular/common'; -import { MatButtonModule } from '@angular/material/button'; -import { MatIconModule } from '@angular/material/icon'; import { MatTooltipModule } from '@angular/material/tooltip'; @Injectable() @Component({ - selector: 'app-point-display', + selector: 'app-point-record-view', templateUrl: './point.component.html', styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './point.component.css'], - imports: [ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule, CommonModule] + imports: [MatTooltipModule] }) export class PointRecordViewComponent extends BaseRecordViewFieldComponent implements OnInit { static type = 'point'; diff --git a/frontend/src/app/components/ui-components/record-view-fields/select/select.component.html b/frontend/src/app/components/ui-components/record-view-fields/select/select.component.html index 58124cc57..8f3bd4c32 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/select/select.component.html +++ b/frontend/src/app/components/ui-components/record-view-fields/select/select.component.html @@ -1,11 +1 @@ -
- {{displayValue}} - -
+{{displayValue}} diff --git a/frontend/src/app/components/ui-components/record-view-fields/select/select.component.ts b/frontend/src/app/components/ui-components/record-view-fields/select/select.component.ts index 29d2442d8..7b196d05f 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/select/select.component.ts +++ b/frontend/src/app/components/ui-components/record-view-fields/select/select.component.ts @@ -1,18 +1,13 @@ import { Component, Injectable, OnInit } from '@angular/core'; import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; -import { ClipboardModule } from '@angular/cdk/clipboard'; -import { CommonModule } from '@angular/common'; -import { MatButtonModule } from '@angular/material/button'; -import { MatIconModule } from '@angular/material/icon'; -import { MatTooltipModule } from '@angular/material/tooltip'; @Injectable() @Component({ - selector: 'app-select-display', + selector: 'app-select-record-view', templateUrl: './select.component.html', styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './select.component.css'], - imports: [CommonModule, ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule] + imports: [] }) export class SelectRecordViewComponent extends BaseRecordViewFieldComponent implements OnInit { public displayValue: string; diff --git a/frontend/src/app/components/ui-components/record-view-fields/static-text/static-text.component.html b/frontend/src/app/components/ui-components/record-view-fields/static-text/static-text.component.html index acf48b2d5..7dfcb3f4b 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/static-text/static-text.component.html +++ b/frontend/src/app/components/ui-components/record-view-fields/static-text/static-text.component.html @@ -1,11 +1 @@ -
- {{value || '—'}} - -
+{{value || '—'}} diff --git a/frontend/src/app/components/ui-components/record-view-fields/static-text/static-text.component.ts b/frontend/src/app/components/ui-components/record-view-fields/static-text/static-text.component.ts index c536fa12f..6af39d952 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/static-text/static-text.component.ts +++ b/frontend/src/app/components/ui-components/record-view-fields/static-text/static-text.component.ts @@ -1,18 +1,12 @@ import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; -import { ClipboardModule } from '@angular/cdk/clipboard'; -import { CommonModule } from '@angular/common'; import { Component, Injectable } from '@angular/core'; -import { MatButtonModule } from '@angular/material/button'; -import { MatIconModule } from '@angular/material/icon'; -import { MatTooltipModule } from '@angular/material/tooltip'; @Injectable() @Component({ - selector: 'app-display-static-text', + selector: 'app-static-text-record-view', templateUrl: './static-text.component.html', styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './static-text.component.css'], - imports: [ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule, CommonModule] + imports: [] }) export class StaticTextRecordViewComponent extends BaseRecordViewFieldComponent { - static type = 'static-text'; } diff --git a/frontend/src/app/components/ui-components/record-view-fields/text/text.component.html b/frontend/src/app/components/ui-components/record-view-fields/text/text.component.html index acf48b2d5..7dfcb3f4b 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/text/text.component.html +++ b/frontend/src/app/components/ui-components/record-view-fields/text/text.component.html @@ -1,11 +1 @@ -
- {{value || '—'}} - -
+{{value || '—'}} diff --git a/frontend/src/app/components/ui-components/record-view-fields/text/text.component.ts b/frontend/src/app/components/ui-components/record-view-fields/text/text.component.ts index d654bc5b8..788c2c8fb 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/text/text.component.ts +++ b/frontend/src/app/components/ui-components/record-view-fields/text/text.component.ts @@ -1,18 +1,13 @@ import { Component, Injectable } from '@angular/core'; -import { ClipboardModule } from '@angular/cdk/clipboard'; -import { CommonModule } from '@angular/common'; -import { MatButtonModule } from '@angular/material/button'; -import { MatIconModule } from '@angular/material/icon'; -import { MatTooltipModule } from '@angular/material/tooltip'; import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; @Injectable() @Component({ - selector: 'app-display-text', + selector: 'app-text-record-view', templateUrl: './text.component.html', styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './text.component.css'], - imports: [ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule, CommonModule] + imports: [] }) export class TextRecordViewComponent extends BaseRecordViewFieldComponent { } diff --git a/frontend/src/app/components/ui-components/record-view-fields/time-interval/time-interval.component.html b/frontend/src/app/components/ui-components/record-view-fields/time-interval/time-interval.component.html index 7a7b4e451..0f4b46264 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/time-interval/time-interval.component.html +++ b/frontend/src/app/components/ui-components/record-view-fields/time-interval/time-interval.component.html @@ -1,11 +1 @@ -
- {{ formattedInterval }} - -
+{{ formattedInterval }} diff --git a/frontend/src/app/components/ui-components/record-view-fields/time-interval/time-interval.component.ts b/frontend/src/app/components/ui-components/record-view-fields/time-interval/time-interval.component.ts index f85f2c720..278f1c60f 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/time-interval/time-interval.component.ts +++ b/frontend/src/app/components/ui-components/record-view-fields/time-interval/time-interval.component.ts @@ -1,18 +1,13 @@ import { Component, Injectable, OnInit } from '@angular/core'; import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; -import { ClipboardModule } from '@angular/cdk/clipboard'; -import { CommonModule } from '@angular/common'; -import { MatButtonModule } from '@angular/material/button'; -import { MatIconModule } from '@angular/material/icon'; -import { MatTooltipModule } from '@angular/material/tooltip'; @Injectable() @Component({ - selector: 'app-time-interval-display', + selector: 'app-time-interval-record-view', templateUrl: './time-interval.component.html', styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './time-interval.component.css'], - imports: [ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule, CommonModule] + imports: [] }) export class TimeIntervalRecordViewComponent extends BaseRecordViewFieldComponent implements OnInit { diff --git a/frontend/src/app/components/ui-components/record-view-fields/time/time.component.html b/frontend/src/app/components/ui-components/record-view-fields/time/time.component.html index 6a8efae37..5016beffb 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/time/time.component.html +++ b/frontend/src/app/components/ui-components/record-view-fields/time/time.component.html @@ -1,11 +1 @@ -
- {{formattedTime || '—'}} - -
+{{formattedTime || '—'}} diff --git a/frontend/src/app/components/ui-components/record-view-fields/time/time.component.ts b/frontend/src/app/components/ui-components/record-view-fields/time/time.component.ts index 27be6b364..ac284dbd9 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/time/time.component.ts +++ b/frontend/src/app/components/ui-components/record-view-fields/time/time.component.ts @@ -1,19 +1,14 @@ import { Component, Injectable, OnInit } from '@angular/core'; import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; -import { ClipboardModule } from '@angular/cdk/clipboard'; -import { CommonModule } from '@angular/common'; -import { MatButtonModule } from '@angular/material/button'; -import { MatIconModule } from '@angular/material/icon'; -import { MatTooltipModule } from '@angular/material/tooltip'; import { format } from 'date-fns'; @Injectable() @Component({ - selector: 'app-time-display', + selector: 'app-time-record-view', templateUrl: './time.component.html', styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './time.component.css'], - imports: [ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule, CommonModule] + imports: [] }) export class TimeRecordViewComponent extends BaseRecordViewFieldComponent implements OnInit { static type = 'time'; diff --git a/frontend/src/app/components/ui-components/record-view-fields/url/url.component.css b/frontend/src/app/components/ui-components/record-view-fields/url/url.component.css index 78c2d730a..d8c64e6f6 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/url/url.component.css +++ b/frontend/src/app/components/ui-components/record-view-fields/url/url.component.css @@ -3,6 +3,7 @@ align-items: center; gap: 4px; color: var(--color-primaryPalette-500); + word-break: break-all; } .url-link__icon { diff --git a/frontend/src/app/components/ui-components/record-view-fields/url/url.component.html b/frontend/src/app/components/ui-components/record-view-fields/url/url.component.html index f2f92fa5d..51fae391e 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/url/url.component.html +++ b/frontend/src/app/components/ui-components/record-view-fields/url/url.component.html @@ -1,20 +1,8 @@ -
- - - link - {{value || '—'}} - - {{value || '—'}} - - -
+ + link + {{value || '—'}} + +{{value || '—'}} diff --git a/frontend/src/app/components/ui-components/record-view-fields/url/url.component.ts b/frontend/src/app/components/ui-components/record-view-fields/url/url.component.ts index 205bdfc03..df4d3187f 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/url/url.component.ts +++ b/frontend/src/app/components/ui-components/record-view-fields/url/url.component.ts @@ -1,21 +1,18 @@ import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; -import { ClipboardModule } from '@angular/cdk/clipboard'; import { CommonModule } from '@angular/common'; import { Component, Injectable } from '@angular/core'; -import { MatButtonModule } from '@angular/material/button'; import { MatIconModule } from '@angular/material/icon'; -import { MatTooltipModule } from '@angular/material/tooltip'; @Injectable() @Component({ - selector: 'app-url-display', + selector: 'app-url-record-view', templateUrl: './url.component.html', styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './url.component.css'], - imports: [ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule, CommonModule] + imports: [CommonModule, MatIconModule] }) export class UrlRecordViewComponent extends BaseRecordViewFieldComponent { static type = 'url'; - + get isValidUrl(): boolean { if (!this.value) return false; try { diff --git a/frontend/src/app/components/ui-components/record-view-fields/uuid/uuid.component.css b/frontend/src/app/components/ui-components/record-view-fields/uuid/uuid.component.css index ca96cf31f..50c4ef509 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/uuid/uuid.component.css +++ b/frontend/src/app/components/ui-components/record-view-fields/uuid/uuid.component.css @@ -1,9 +1,3 @@ -.uuid-display { - display: flex; - align-items: center; - gap: 4px; -} - .uuid-text { font-family: 'Roboto Condensed', 'Arial Narrow', sans-serif; font-stretch: condensed; @@ -11,30 +5,3 @@ text-overflow: ellipsis; white-space: nowrap; } - -.copy-button { - width: 24px; - height: 24px; - line-height: 24px; - opacity: 0; - transition: opacity 0.2s; -} - -.field-value:hover .copy-button { - opacity: 0.7; -} - -.copy-button:hover { - opacity: 1 !important; -} - -.copy-button mat-icon { - font-size: 16px; - width: 16px; - height: 16px; -} - -.null-value { - color: var(--mat-grey-500); - font-style: italic; -} diff --git a/frontend/src/app/components/ui-components/record-view-fields/uuid/uuid.component.html b/frontend/src/app/components/ui-components/record-view-fields/uuid/uuid.component.html index 380ffe2eb..2034cc2c5 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/uuid/uuid.component.html +++ b/frontend/src/app/components/ui-components/record-view-fields/uuid/uuid.component.html @@ -1,16 +1 @@ -
- @if (value) { - {{ value }} - - } - @else { - NULL - } -
\ No newline at end of file +{{ value || 'Null' }} \ No newline at end of file diff --git a/frontend/src/app/components/ui-components/record-view-fields/uuid/uuid.component.ts b/frontend/src/app/components/ui-components/record-view-fields/uuid/uuid.component.ts index 9f79943ad..226fcadf2 100644 --- a/frontend/src/app/components/ui-components/record-view-fields/uuid/uuid.component.ts +++ b/frontend/src/app/components/ui-components/record-view-fields/uuid/uuid.component.ts @@ -1,17 +1,12 @@ import { Component, Injectable } from '@angular/core'; import { BaseRecordViewFieldComponent } from '../base-record-view-field/base-record-view-field.component'; -import { ClipboardModule } from '@angular/cdk/clipboard'; -import { CommonModule } from '@angular/common'; -import { MatButtonModule } from '@angular/material/button'; -import { MatIconModule } from '@angular/material/icon'; -import { MatTooltipModule } from '@angular/material/tooltip'; @Injectable() @Component({ - selector: 'app-display-uuid', + selector: 'app-uuid-record-view', templateUrl: './uuid.component.html', styleUrls: ['../base-record-view-field/base-record-view-field.component.css', './uuid.component.css'], - imports: [CommonModule, ClipboardModule, MatIconModule, MatButtonModule, MatTooltipModule] + imports: [] }) export class UuidRecordViewComponent extends BaseRecordViewFieldComponent { } \ No newline at end of file diff --git a/frontend/src/app/consts/record-view-types.ts b/frontend/src/app/consts/record-view-types.ts index 67c05afd8..e0598c62d 100644 --- a/frontend/src/app/consts/record-view-types.ts +++ b/frontend/src/app/consts/record-view-types.ts @@ -48,7 +48,7 @@ export const UIwidgets = { UUID: UuidRecordViewComponent, } -export const tableDisplayTypes = { +export const recordViewFieldTypes = { postgres: { // numbers (number) real: NumberRecordViewComponent, diff --git a/frontend/src/app/models/table.ts b/frontend/src/app/models/table.ts index 8abf1eef1..43fe6504d 100644 --- a/frontend/src/app/models/table.ts +++ b/frontend/src/app/models/table.ts @@ -48,6 +48,7 @@ export interface TableRow { foreignKeysList: string[], widgets: Widget[], widgetsList: string[], + fieldsTypes: { [key: string]: string }, relatedRecords: { referenced_on_column_name: string, referenced_by: []