From b1f89a82d3d245640156de944e0b459a5e3d7995 Mon Sep 17 00:00:00 2001 From: VitaliyHrabovych Date: Mon, 12 May 2025 11:54:17 +0300 Subject: [PATCH 01/46] Replace resources links with quick start buttons to create APIs that navigate them directly ito the creation process --- .../df-welcome-page.component.html | 68 ++++++++----------- .../df-welcome-page.component.scss | 9 +++ .../df-welcome-page.component.ts | 12 ++++ src/assets/i18n/home/en.json | 11 ++- 4 files changed, 59 insertions(+), 41 deletions(-) diff --git a/src/app/adf-home/df-welcome-page/df-welcome-page.component.html b/src/app/adf-home/df-welcome-page/df-welcome-page.component.html index b70f3c3c..500c4c3f 100644 --- a/src/app/adf-home/df-welcome-page/df-welcome-page.component.html +++ b/src/app/adf-home/df-welcome-page/df-welcome-page.component.html @@ -1,11 +1,8 @@ -
-
+

@@ -14,40 +11,39 @@

-
    -
  • - - - - - - -
  • -
+
+ + + + + +

diff --git a/src/app/adf-api-docs/df-api-docs/df-api-docs.component.scss b/src/app/adf-api-docs/df-api-docs/df-api-docs.component.scss index d2f0639d..4351fb83 100644 --- a/src/app/adf-api-docs/df-api-docs/df-api-docs.component.scss +++ b/src/app/adf-api-docs/df-api-docs/df-api-docs.component.scss @@ -141,24 +141,6 @@ } } -.curl-command-text { - white-space: pre; - font-family: monospace; - font-size: 0.9em; - margin: 0; - color: var(--df-script-editor-text-color); - overflow-x: auto; -} - .custom-swagger-content-wrapper { width: 100%; -} - -.curl-commands-container { - display: flex; - flex-direction: column; - gap: 8px; - .actions-container { - padding: 0px 8px; - } -} +} \ No newline at end of file diff --git a/src/app/adf-api-docs/df-api-docs/df-api-docs.component.ts b/src/app/adf-api-docs/df-api-docs/df-api-docs.component.ts index 70788022..aa447b87 100644 --- a/src/app/adf-api-docs/df-api-docs/df-api-docs.component.ts +++ b/src/app/adf-api-docs/df-api-docs/df-api-docs.component.ts @@ -48,6 +48,8 @@ import { import { HttpClient, HttpErrorResponse } from '@angular/common/http'; import { BASE_URL } from 'src/app/shared/constants/urls'; import { Subscription, of, forkJoin } from 'rxjs'; +import { DfCurlCommandComponent } from '../df-curl-command/df-curl-command.component'; +import { ApiDocJson } from '../../shared/types/files'; interface ServiceResponse { resource: Array<{ @@ -57,19 +59,6 @@ interface ServiceResponse { }>; } -interface ApiDocJson { - info: { - description: string | undefined; - title: string; - version: string | undefined; - group: string; - }; - paths: { - [key: string]: any; - }; - [key: string]: any; -} - interface HealthCheckResult { endpoint: string; success?: boolean; @@ -98,6 +87,7 @@ interface HealthCheckResult { MatTooltipModule, MatExpansionModule, MatCardModule, + DfCurlCommandComponent, ], }) export class DfApiDocsComponent implements OnInit, AfterContentInit, OnDestroy { @@ -113,16 +103,37 @@ export class DfApiDocsComponent implements OnInit, AfterContentInit, OnDestroy { apiDocJson: ApiDocJson; apiKeys: ApiKeyInfo[] = []; faCopy = faCopy; - curlCommands: { text: string }[] = []; // Will be populated dynamically + private subscriptions: Subscription[] = []; healthStatus: 'loading' | 'healthy' | 'unhealthy' | 'warning' = 'loading'; healthError: string | null = null; serviceName: string | null = null; showUnhealthyErrorDetails = false; // Mapping of service types to their corresponding endpoints, probably would be better to move to the back-end - healthCheckEndpointsMap: { [key: string]: string[] } = { - Database: ['/_schema', '/_table'], - File: ['/'], + healthCheckEndpointsInfo: { + [key: string]: { endpoint: string; title: string; description: string }[]; + } = { + Database: [ + { + endpoint: '/_schema', + title: 'View Available Schemas', + description: + 'This command fetches a list of schemas from your connected database', + }, + { + endpoint: '/_table', + title: 'View Tables in Your Database', + description: 'This command lists all tables in your database', + }, + ], + File: [ + { + endpoint: '/', + title: 'View Available Folders', + description: + 'This command fetches a list of folders from your connected file storage', + }, + ], }; constructor( @@ -213,8 +224,6 @@ export class DfApiDocsComponent implements OnInit, AfterContentInit, OnDestroy { }, showMutatedRequest: true, onComplete: () => { - this.prepareCurlCommands(); - if ( this.apiDocElement && this.apiDocElement.nativeElement && @@ -245,11 +254,11 @@ export class DfApiDocsComponent implements OnInit, AfterContentInit, OnDestroy { } private checkApiHealth(): void { - let endpointsToValidate = - this.healthCheckEndpointsMap[this.apiDocJson.info.group]; - if (this.serviceName && endpointsToValidate) { + let endpointsInfoToValidate = + this.healthCheckEndpointsInfo[this.apiDocJson.info.group]; + if (this.serviceName && endpointsInfoToValidate) { // Perform health check - this.performHealthCheck(endpointsToValidate[0]); + this.performHealthCheck(endpointsInfoToValidate[0].endpoint); } else { this.setHealthState('warning'); } @@ -309,32 +318,10 @@ export class DfApiDocsComponent implements OnInit, AfterContentInit, OnDestroy { }); } - copyCurlCommand(commandText: string) { - this.clipboard.copy(commandText); - } - toggleUnhealthyErrorDetails(): void { this.showUnhealthyErrorDetails = !this.showUnhealthyErrorDetails; } - private prepareCurlCommands(): void { - this.curlCommands = []; - if (!this.serviceName || !this.apiDocJson?.info?.group) { - return; - } - - const endpoints = this.healthCheckEndpointsMap[this.apiDocJson.info.group]; - if (endpoints && endpoints.length > 0) { - endpoints.forEach(endpoint => { - const sessionToken = this.userDataService.token - ? this.userDataService.token - : 'YOUR_SESSION_TOKEN'; - const command = `curl -X 'GET' '${window.location.origin}${BASE_URL}/${this.serviceName}${endpoint}' -H 'accept: application/json' -H '${SESSION_TOKEN_HEADER}: ${sessionToken}'`; - this.curlCommands.push({ text: command }); - }); - } - } - private injectCustomContent( swaggerContainer: HTMLElement, infoContainer: HTMLElement | null, diff --git a/src/app/adf-api-docs/df-curl-command/df-curl-command.component.html b/src/app/adf-api-docs/df-curl-command/df-curl-command.component.html new file mode 100644 index 00000000..88b5969c --- /dev/null +++ b/src/app/adf-api-docs/df-curl-command/df-curl-command.component.html @@ -0,0 +1,52 @@ + + + + + {{ 'apiBasicCurlCommands.title' | transloco }} + + + + +

+ {{ 'apiBasicCurlCommands.quickStartDetails' | transloco }} +

+
+

+ {{ i + 1 }}. {{ command.title }} +

+

+ {{ command.description }} +

+ + +
{{ command.text }}
+
+ + + +
+

{{ command.note }}

+
+ +

+ {{ + 'apiBasicCurlCommands.nextStepFooter.header' | transloco + }} + {{ 'apiBasicCurlCommands.nextStepFooter.body' | transloco }} +

+
+
+
\ No newline at end of file diff --git a/src/app/adf-api-docs/df-curl-command/df-curl-command.component.scss b/src/app/adf-api-docs/df-curl-command/df-curl-command.component.scss new file mode 100644 index 00000000..b43548a0 --- /dev/null +++ b/src/app/adf-api-docs/df-curl-command/df-curl-command.component.scss @@ -0,0 +1,26 @@ +.curl-command-text { + white-space: pre; + font-family: monospace; + font-size: 0.9em; + margin: 0; + color: var(--df-script-editor-text-color); + overflow-x: auto; +} + +.curl-commands-container { + display: flex; + flex-direction: column; + gap: 8px; + .actions-container { + padding: 0px 8px; + } +} + +.curl-command-title { + margin: 0; + font-weight: bold; +} + +.curl-command-note { + color: gray !important; +} diff --git a/src/app/adf-api-docs/df-curl-command/df-curl-command.component.ts b/src/app/adf-api-docs/df-curl-command/df-curl-command.component.ts new file mode 100644 index 00000000..cd507b53 --- /dev/null +++ b/src/app/adf-api-docs/df-curl-command/df-curl-command.component.ts @@ -0,0 +1,126 @@ +import { Component, Input, OnChanges, SimpleChanges } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { TranslocoModule } from '@ngneat/transloco'; +import { MatExpansionModule } from '@angular/material/expansion'; +import { MatCardModule } from '@angular/material/card'; +import { MatIconModule } from '@angular/material/icon'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { MatButtonModule } from '@angular/material/button'; +import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; +import { faCopy } from '@fortawesome/free-solid-svg-icons'; +import { Clipboard } from '@angular/cdk/clipboard'; +import { MatSnackBar } from '@angular/material/snack-bar'; +import { DfUserDataService } from 'src/app/shared/services/df-user-data.service'; +import { BASE_URL } from 'src/app/shared/constants/urls'; +import { SESSION_TOKEN_HEADER } from 'src/app/shared/constants/http-headers'; +import { ApiDocJson } from 'src/app/shared/types/files'; +import { MatDividerModule } from '@angular/material/divider'; + +interface CurlCommand { + title: string; + description: string; + text: string; + note: string; +} + +const healthCheckEndpointsInfo: { + [key: string]: { endpoint: string; title: string; description: string }[]; +} = { + Database: [ + { + endpoint: '/_schema', + title: 'View Available Schemas', + description: + 'This command fetches a list of schemas from your connected database', + }, + { + endpoint: '/_table', + title: 'View Tables in Your Database', + description: 'This command lists all tables in your database', + }, + ], + File: [ + { + endpoint: '/', + title: 'View Available Folders', + description: + 'This command fetches a list of folders from your connected file storage', + }, + ], +}; + +@Component({ + selector: 'df-curl-command', + templateUrl: './df-curl-command.component.html', + styleUrls: ['./df-curl-command.component.scss'], + standalone: true, + imports: [ + CommonModule, + TranslocoModule, + MatExpansionModule, + MatCardModule, + MatIconModule, + MatTooltipModule, + FontAwesomeModule, + MatDividerModule, + MatButtonModule + ], +}) +export class DfCurlCommandComponent implements OnChanges { + @Input() apiDocJson: ApiDocJson; + @Input() serviceName: string; + + curlCommands: CurlCommand[] = []; + faCopy = faCopy; + + constructor( + private clipboard: Clipboard, + private snackBar: MatSnackBar, + private userDataService: DfUserDataService + ) {} + + ngOnChanges(changes: SimpleChanges): void { + if ( + (changes['apiDocJson'] || changes['serviceName']) && + this.apiDocJson && + this.serviceName + ) { + this.prepareCurlCommands(); + } + } + + copyCurlCommand(commandText: string) { + this.clipboard.copy(commandText); + this.snackBar.open('CURL command copied to clipboard.', 'Close', { + duration: 2000, + }); + } + + private prepareCurlCommands(): void { + this.curlCommands = []; + if (!this.serviceName || !this.apiDocJson?.info?.group) { + return; + } + + const endpointsInfo = + healthCheckEndpointsInfo[this.apiDocJson.info.group]; + if (endpointsInfo?.length > 0) { + endpointsInfo.forEach(endpointInfo => { + const sessionToken = + this.userDataService.token || 'YOUR_SESSION_TOKEN'; + const command = `curl -X 'GET' '${window.location.origin}${BASE_URL}/${this.serviceName}${endpointInfo.endpoint}' -H 'accept: application/json' -H '${SESSION_TOKEN_HEADER}: ${sessionToken}'`; + + this.curlCommands.push({ + title: endpointInfo.title, + description: endpointInfo.description, + text: command, + note: this.apiDocJson.paths[endpointInfo.endpoint]?.['get']?.summary, + }); + }); + } + } + + trackByCommand(index: number, item: CurlCommand): string { + return item.text; + } +} \ No newline at end of file diff --git a/src/app/shared/types/files.ts b/src/app/shared/types/files.ts index a6e25dba..ba4c0541 100644 --- a/src/app/shared/types/files.ts +++ b/src/app/shared/types/files.ts @@ -36,3 +36,24 @@ export interface FileType { } type EntityType = 'file' | 'folder'; + +export interface ApiDocJson { + info: { + description?: string; + title: string; + version?: string; + group: string; + }; + paths: { + [endpoint: string]: { + [method: string]: { + operationId: string; + description: string; + summary: string; + tags: string[]; + [key: string]: any; + }; + }; + }; + [key: string]: any; +} diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 524ca228..2d837f75 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -126,8 +126,10 @@ "warningDefault": "Warning: This type of API currently does not support automatic health checks." }, "apiBasicCurlCommands": { - "title": "Test api yourself with this simple curl commads here:", - "copyTooltip": "Copy" + "title": "Quickstart: Test Your API Connection:", + "quickStartDetails": "Start by testing your API with these sample curl commands. They return real data and confirm your connection is active.", + "copyTooltip": "Copy", + "nextStepFooter": {"header": "Next Step:", "body": "Scroll below to explore more endpoints that allow you to read, write, and filter your data via generated REST"} }, "nav": { "error": { diff --git a/src/dark-style.scss b/src/dark-style.scss index f361b0a5..aa651f21 100644 --- a/src/dark-style.scss +++ b/src/dark-style.scss @@ -95,7 +95,8 @@ $df-purple-palette: mat.define-palette(theme.$df-purple-palette); input, textarea, button, - span { + span, + .themed-text { color: white !important; } .mat-mdc-form-field-required-marker { From 99f96f0fce41e147c1df6a40b09c4758c3b4fbc8 Mon Sep 17 00:00:00 2001 From: VitaliyHrabovych Date: Mon, 9 Jun 2025 15:20:04 +0300 Subject: [PATCH 27/46] Used a prittier --- .../df-api-docs/df-api-docs.component.scss | 2 +- .../df-curl-command/df-curl-command.component.html | 6 ++---- .../df-curl-command/df-curl-command.component.ts | 10 ++++------ 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/app/adf-api-docs/df-api-docs/df-api-docs.component.scss b/src/app/adf-api-docs/df-api-docs/df-api-docs.component.scss index 4351fb83..f2cbf028 100644 --- a/src/app/adf-api-docs/df-api-docs/df-api-docs.component.scss +++ b/src/app/adf-api-docs/df-api-docs/df-api-docs.component.scss @@ -143,4 +143,4 @@ .custom-swagger-content-wrapper { width: 100%; -} \ No newline at end of file +} diff --git a/src/app/adf-api-docs/df-curl-command/df-curl-command.component.html b/src/app/adf-api-docs/df-curl-command/df-curl-command.component.html index 88b5969c..6d8682b0 100644 --- a/src/app/adf-api-docs/df-curl-command/df-curl-command.component.html +++ b/src/app/adf-api-docs/df-curl-command/df-curl-command.component.html @@ -31,9 +31,7 @@

@@ -49,4 +47,4 @@

- \ No newline at end of file + diff --git a/src/app/adf-api-docs/df-curl-command/df-curl-command.component.ts b/src/app/adf-api-docs/df-curl-command/df-curl-command.component.ts index cd507b53..ba3bf4ce 100644 --- a/src/app/adf-api-docs/df-curl-command/df-curl-command.component.ts +++ b/src/app/adf-api-docs/df-curl-command/df-curl-command.component.ts @@ -63,7 +63,7 @@ const healthCheckEndpointsInfo: { MatTooltipModule, FontAwesomeModule, MatDividerModule, - MatButtonModule + MatButtonModule, ], }) export class DfCurlCommandComponent implements OnChanges { @@ -102,12 +102,10 @@ export class DfCurlCommandComponent implements OnChanges { return; } - const endpointsInfo = - healthCheckEndpointsInfo[this.apiDocJson.info.group]; + const endpointsInfo = healthCheckEndpointsInfo[this.apiDocJson.info.group]; if (endpointsInfo?.length > 0) { endpointsInfo.forEach(endpointInfo => { - const sessionToken = - this.userDataService.token || 'YOUR_SESSION_TOKEN'; + const sessionToken = this.userDataService.token || 'YOUR_SESSION_TOKEN'; const command = `curl -X 'GET' '${window.location.origin}${BASE_URL}/${this.serviceName}${endpointInfo.endpoint}' -H 'accept: application/json' -H '${SESSION_TOKEN_HEADER}: ${sessionToken}'`; this.curlCommands.push({ @@ -123,4 +121,4 @@ export class DfCurlCommandComponent implements OnChanges { trackByCommand(index: number, item: CurlCommand): string { return item.text; } -} \ No newline at end of file +} From cdddb7d7430f2bc83d2ba145ca31a06a6952769d Mon Sep 17 00:00:00 2001 From: VitaliyHrabovych Date: Mon, 9 Jun 2025 16:11:41 +0300 Subject: [PATCH 28/46] Renamed a component --- .../df-api-docs/df-api-docs.component.html | 4 +- .../df-api-docs/df-api-docs.component.ts | 6 +- .../df-api-quickstart.component.html | 55 ++++++++++++++++ .../df-api-quickstart.component.scss | 62 +++++++++++++++++++ .../df-api-quickstart.component.ts} | 31 +++++----- .../df-curl-command.component.html | 50 --------------- .../df-curl-command.component.scss | 26 -------- src/assets/i18n/en.json | 2 +- 8 files changed, 140 insertions(+), 96 deletions(-) create mode 100644 src/app/adf-api-docs/df-api-quickstart/df-api-quickstart.component.html create mode 100644 src/app/adf-api-docs/df-api-quickstart/df-api-quickstart.component.scss rename src/app/adf-api-docs/{df-curl-command/df-curl-command.component.ts => df-api-quickstart/df-api-quickstart.component.ts} (79%) delete mode 100644 src/app/adf-api-docs/df-curl-command/df-curl-command.component.html delete mode 100644 src/app/adf-api-docs/df-curl-command/df-curl-command.component.scss diff --git a/src/app/adf-api-docs/df-api-docs/df-api-docs.component.html b/src/app/adf-api-docs/df-api-docs/df-api-docs.component.html index 396bd261..9003c18f 100644 --- a/src/app/adf-api-docs/df-api-docs/df-api-docs.component.html +++ b/src/app/adf-api-docs/df-api-docs/df-api-docs.component.html @@ -76,10 +76,10 @@ - + [serviceName]="serviceName">
diff --git a/src/app/adf-api-docs/df-api-docs/df-api-docs.component.ts b/src/app/adf-api-docs/df-api-docs/df-api-docs.component.ts index aa447b87..26a293fa 100644 --- a/src/app/adf-api-docs/df-api-docs/df-api-docs.component.ts +++ b/src/app/adf-api-docs/df-api-docs/df-api-docs.component.ts @@ -48,8 +48,8 @@ import { import { HttpClient, HttpErrorResponse } from '@angular/common/http'; import { BASE_URL } from 'src/app/shared/constants/urls'; import { Subscription, of, forkJoin } from 'rxjs'; -import { DfCurlCommandComponent } from '../df-curl-command/df-curl-command.component'; -import { ApiDocJson } from '../../shared/types/files'; +import { DfApiQuickstartComponent } from '../df-api-quickstart/df-api-quickstart.component'; +import { ApiDocJson } from 'src/app/shared/types/files'; interface ServiceResponse { resource: Array<{ @@ -87,7 +87,7 @@ interface HealthCheckResult { MatTooltipModule, MatExpansionModule, MatCardModule, - DfCurlCommandComponent, + DfApiQuickstartComponent, ], }) export class DfApiDocsComponent implements OnInit, AfterContentInit, OnDestroy { diff --git a/src/app/adf-api-docs/df-api-quickstart/df-api-quickstart.component.html b/src/app/adf-api-docs/df-api-quickstart/df-api-quickstart.component.html new file mode 100644 index 00000000..0d73cff7 --- /dev/null +++ b/src/app/adf-api-docs/df-api-quickstart/df-api-quickstart.component.html @@ -0,0 +1,55 @@ + + + + + {{ 'apiBasicCurlCommands.title' | transloco }} + + + +
+

+ {{ 'apiBasicCurlCommands.quickStartDetails' | transloco }} +

+
+

+ {{ i + 1 }}. {{ command.title }} +

+

+ {{ command.description }} +

+ + +
{{ command.textForDisplay }}
+
+ + + +
+

{{ command.note }}

+
+ +
+

+ {{ + 'apiBasicCurlCommands.nextStepFooter.header' | transloco + }} + {{ 'apiBasicCurlCommands.nextStepFooter.body' | transloco }} +

+
+
+
diff --git a/src/app/adf-api-docs/df-api-quickstart/df-api-quickstart.component.scss b/src/app/adf-api-docs/df-api-quickstart/df-api-quickstart.component.scss new file mode 100644 index 00000000..d6e9a152 --- /dev/null +++ b/src/app/adf-api-docs/df-api-quickstart/df-api-quickstart.component.scss @@ -0,0 +1,62 @@ +mat-expansion-panel-header { + padding: 0 12px; +} +.curl-command-text { + white-space: pre; + font-family: monospace; + font-size: 0.9em; + margin: 0; + color: var(--df-script-editor-text-color); + overflow-x: auto; +} + +.curl-commands-container { + display: flex; + flex-direction: column; + gap: 8px; + .actions-container { + padding: 0px 8px; + } +} + +.curl-command-title { + margin: 0; + font-weight: bold; +} + +.curl-command-note { + color: gray !important; +} + +.no-commands-container { + ul { + padding-left: 20px; + li { + margin-bottom: 10px; + } + } + + span[class^='method-'] { + font-weight: bold; + font-family: monospace; + padding: 2px 6px; + border-radius: 4px; + color: white; + } + + .method-get { + background-color: #61affe; // blue + } + .method-post { + background-color: #49cc90; // green + } + .method-put { + background-color: #fca130; // orange + } + .method-patch { + background-color: #fca130; // orange + } + .method-delete { + background-color: #f93e3e; // red + } +} diff --git a/src/app/adf-api-docs/df-curl-command/df-curl-command.component.ts b/src/app/adf-api-docs/df-api-quickstart/df-api-quickstart.component.ts similarity index 79% rename from src/app/adf-api-docs/df-curl-command/df-curl-command.component.ts rename to src/app/adf-api-docs/df-api-quickstart/df-api-quickstart.component.ts index ba3bf4ce..6a97d20e 100644 --- a/src/app/adf-api-docs/df-curl-command/df-curl-command.component.ts +++ b/src/app/adf-api-docs/df-api-quickstart/df-api-quickstart.component.ts @@ -9,17 +9,18 @@ import { MatButtonModule } from '@angular/material/button'; import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; import { faCopy } from '@fortawesome/free-solid-svg-icons'; import { Clipboard } from '@angular/cdk/clipboard'; -import { MatSnackBar } from '@angular/material/snack-bar'; import { DfUserDataService } from 'src/app/shared/services/df-user-data.service'; import { BASE_URL } from 'src/app/shared/constants/urls'; import { SESSION_TOKEN_HEADER } from 'src/app/shared/constants/http-headers'; import { ApiDocJson } from 'src/app/shared/types/files'; import { MatDividerModule } from '@angular/material/divider'; +import { MatSnackBar } from '@angular/material/snack-bar'; interface CurlCommand { title: string; description: string; - text: string; + textForDisplay: string; + textForCopy: string; note: string; } @@ -50,9 +51,9 @@ const healthCheckEndpointsInfo: { }; @Component({ - selector: 'df-curl-command', - templateUrl: './df-curl-command.component.html', - styleUrls: ['./df-curl-command.component.scss'], + selector: 'df-api-quickstart', + templateUrl: './df-api-quickstart.component.html', + styleUrls: ['./df-api-quickstart.component.scss'], standalone: true, imports: [ CommonModule, @@ -66,7 +67,7 @@ const healthCheckEndpointsInfo: { MatButtonModule, ], }) -export class DfCurlCommandComponent implements OnChanges { +export class DfApiQuickstartComponent implements OnChanges { @Input() apiDocJson: ApiDocJson; @Input() serviceName: string; @@ -75,8 +76,8 @@ export class DfCurlCommandComponent implements OnChanges { constructor( private clipboard: Clipboard, - private snackBar: MatSnackBar, - private userDataService: DfUserDataService + private userDataService: DfUserDataService, + private snackBar: MatSnackBar ) {} ngOnChanges(changes: SimpleChanges): void { @@ -91,9 +92,6 @@ export class DfCurlCommandComponent implements OnChanges { copyCurlCommand(commandText: string) { this.clipboard.copy(commandText); - this.snackBar.open('CURL command copied to clipboard.', 'Close', { - duration: 2000, - }); } private prepareCurlCommands(): void { @@ -106,12 +104,17 @@ export class DfCurlCommandComponent implements OnChanges { if (endpointsInfo?.length > 0) { endpointsInfo.forEach(endpointInfo => { const sessionToken = this.userDataService.token || 'YOUR_SESSION_TOKEN'; - const command = `curl -X 'GET' '${window.location.origin}${BASE_URL}/${this.serviceName}${endpointInfo.endpoint}' -H 'accept: application/json' -H '${SESSION_TOKEN_HEADER}: ${sessionToken}'`; + const baseUrl = `${window.location.origin}${BASE_URL}/${this.serviceName}${endpointInfo.endpoint}`; + const headers = `-H 'accept: application/json' -H '${SESSION_TOKEN_HEADER}: ${sessionToken}'`; + + const commandForDisplay = `curl -X 'GET' '${baseUrl}' \\\n ${headers}`; + const commandForCopy = `curl -X 'GET' '${baseUrl}' ${headers}`; this.curlCommands.push({ title: endpointInfo.title, description: endpointInfo.description, - text: command, + textForDisplay: commandForDisplay, + textForCopy: commandForCopy, note: this.apiDocJson.paths[endpointInfo.endpoint]?.['get']?.summary, }); }); @@ -119,6 +122,6 @@ export class DfCurlCommandComponent implements OnChanges { } trackByCommand(index: number, item: CurlCommand): string { - return item.text; + return item.textForCopy; } } diff --git a/src/app/adf-api-docs/df-curl-command/df-curl-command.component.html b/src/app/adf-api-docs/df-curl-command/df-curl-command.component.html deleted file mode 100644 index 6d8682b0..00000000 --- a/src/app/adf-api-docs/df-curl-command/df-curl-command.component.html +++ /dev/null @@ -1,50 +0,0 @@ - - - - - {{ 'apiBasicCurlCommands.title' | transloco }} - - - - -

- {{ 'apiBasicCurlCommands.quickStartDetails' | transloco }} -

-
-

- {{ i + 1 }}. {{ command.title }} -

-

- {{ command.description }} -

- - -
{{ command.text }}
-
- - - -
-

{{ command.note }}

-
- -

- {{ - 'apiBasicCurlCommands.nextStepFooter.header' | transloco - }} - {{ 'apiBasicCurlCommands.nextStepFooter.body' | transloco }} -

-
-
-
diff --git a/src/app/adf-api-docs/df-curl-command/df-curl-command.component.scss b/src/app/adf-api-docs/df-curl-command/df-curl-command.component.scss deleted file mode 100644 index b43548a0..00000000 --- a/src/app/adf-api-docs/df-curl-command/df-curl-command.component.scss +++ /dev/null @@ -1,26 +0,0 @@ -.curl-command-text { - white-space: pre; - font-family: monospace; - font-size: 0.9em; - margin: 0; - color: var(--df-script-editor-text-color); - overflow-x: auto; -} - -.curl-commands-container { - display: flex; - flex-direction: column; - gap: 8px; - .actions-container { - padding: 0px 8px; - } -} - -.curl-command-title { - margin: 0; - font-weight: bold; -} - -.curl-command-note { - color: gray !important; -} diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 2d837f75..8b00adbf 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -129,7 +129,7 @@ "title": "Quickstart: Test Your API Connection:", "quickStartDetails": "Start by testing your API with these sample curl commands. They return real data and confirm your connection is active.", "copyTooltip": "Copy", - "nextStepFooter": {"header": "Next Step:", "body": "Scroll below to explore more endpoints that allow you to read, write, and filter your data via generated REST"} + "nextStepFooter": {"header": "Next Step:", "body": "Scroll below to explore generated endpoints that allow you to read, write, and filter your data via REST"} }, "nav": { "error": { From 27784c7f223be723a85d57bb8e0ab3a544b5663f Mon Sep 17 00:00:00 2001 From: VitaliyHrabovych Date: Tue, 17 Jun 2025 09:37:44 +0300 Subject: [PATCH 29/46] Correcting a typo in the api docs route --- src/app/adf-home/df-welcome-page/df-welcome-page.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/adf-home/df-welcome-page/df-welcome-page.component.ts b/src/app/adf-home/df-welcome-page/df-welcome-page.component.ts index 7988a94d..a5d6ff9b 100644 --- a/src/app/adf-home/df-welcome-page/df-welcome-page.component.ts +++ b/src/app/adf-home/df-welcome-page/df-welcome-page.component.ts @@ -82,7 +82,7 @@ export class DfWelcomePageComponent { fpNetworkRoute = `/${ROUTES.API_CONNECTIONS}/${ROUTES.API_TYPES}/${ROUTES.NETWORK}/${ROUTES.CREATE}`; fpFileRoute = `/${ROUTES.API_CONNECTIONS}/${ROUTES.API_TYPES}/${ROUTES.FILE}/${ROUTES.CREATE}`; fpUtilityRoute = `/${ROUTES.API_CONNECTIONS}/${ROUTES.API_TYPES}/${ROUTES.UTILITY}/${ROUTES.CREATE}`; - fpApiDocsRoute = `/${ROUTES.API_DOCS}`; + fpApiDocsRoute = `/${ROUTES.API_CONNECTIONS}/${ROUTES.API_DOCS}`; public generateApiCardsData: any[]; From 9e8b7f012c1f971b3fa9b4c6bb3c3b3b59c13da7 Mon Sep 17 00:00:00 2001 From: VitaliyHrabovych Date: Tue, 24 Jun 2025 18:18:51 +0300 Subject: [PATCH 30/46] Adding image for trino service provider component --- src/assets/img/databaseImages.json | 5 +++++ src/assets/img/trino.svg | 1 + 2 files changed, 6 insertions(+) create mode 100644 src/assets/img/trino.svg diff --git a/src/assets/img/databaseImages.json b/src/assets/img/databaseImages.json index 14313403..5531a4e7 100644 --- a/src/assets/img/databaseImages.json +++ b/src/assets/img/databaseImages.json @@ -128,5 +128,10 @@ "src": "assets/img/sap.svg", "alt": "hana", "label": "hana" + }, + { + "src": "assets/img/trino.svg", + "alt": "Trino", + "label": "trino" } ] diff --git a/src/assets/img/trino.svg b/src/assets/img/trino.svg new file mode 100644 index 00000000..40cdce24 --- /dev/null +++ b/src/assets/img/trino.svg @@ -0,0 +1 @@ + \ No newline at end of file From 258d2ff5a8faf4d69c29d29f518a12fb72d17374 Mon Sep 17 00:00:00 2001 From: Kevin McGahey Date: Sun, 29 Jun 2025 16:31:01 -0700 Subject: [PATCH 31/46] AI tab addition --- .gitignore | 2 + src/app/ai/ai.component.ts | 211 ++++++++++++++++++ src/app/routes.ts | 7 + .../df-side-nav/df-side-nav.component.html | 1 + .../df-side-nav/df-side-nav.component.scss | 79 +++++++ src/app/shared/types/routes.ts | 1 + src/app/shared/utilities/route.ts | 3 +- src/assets/i18n/en.json | 4 + src/assets/img/nav/ai.svg | 14 ++ src/environments/environment.ts | 1 + 10 files changed, 322 insertions(+), 1 deletion(-) create mode 100644 src/app/ai/ai.component.ts create mode 100644 src/assets/img/nav/ai.svg diff --git a/.gitignore b/.gitignore index 7a4a8630..58f8ab12 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,5 @@ testem.log # System files .DS_Store Thumbs.db + +.config/ diff --git a/src/app/ai/ai.component.ts b/src/app/ai/ai.component.ts new file mode 100644 index 00000000..5d0e4e2e --- /dev/null +++ b/src/app/ai/ai.component.ts @@ -0,0 +1,211 @@ +import { Component } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { ActivatedRoute } from '@angular/router'; +import { DfPaywallComponent } from '../shared/components/df-paywall/df-paywall.component'; +import { NgIf } from '@angular/common'; + +@Component({ + selector: 'app-ai', + standalone: true, + imports: [CommonModule, DfPaywallComponent, NgIf], + template: ` +
+
+
+

AI Gateway Data Platform

+
+

+ Unlock the power of AI with your data! Our upcoming AI capabilities will enable you to: +

+
    +
  • Secure Dataset Exposure: Safely expose your datasets to AI clients with full RBAC protections
  • +
  • 🔐 Enterprise-Grade Security: Maintain complete control over data access and permissions
  • +
  • 🚀 Seamless Integration: Connect popular AI platforms and tools directly to your DreamFactory APIs
  • +
  • 📊 Intelligent Analytics: Generate insights and recommendations powered by machine learning
  • +
+
+

🎯 Ready to Get Started?

+

Contact us below to join our exclusive AI beta program and be among the first to experience these cutting-edge capabilities!

+
+
+
+
+ +
+ +
+

AI Assistant

+

Welcome to the AI section! This is where AI-powered features will be implemented.

+
+
+

Smart Analytics

+

AI-powered data insights and analytics

+
+
+

Automated Tasks

+

Intelligent automation and task management

+
+
+

Predictive Modeling

+

Advanced machine learning predictions

+
+
+
+
+ `, + styles: [` + .ai-paywall-container { + min-height: 100vh; + background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); + } + + .ai-intro-section { + padding: 3rem 2rem; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: white; + position: relative; + overflow: hidden; + } + + .ai-intro-section::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: url('data:image/svg+xml,'); + opacity: 0.3; + } + + .ai-intro-content { + max-width: 800px; + margin: 0 auto; + position: relative; + z-index: 1; + } + + .ai-title { + font-size: 2.5rem; + font-weight: 700; + margin-bottom: 1.5rem; + text-align: center; + color: #000; + } + + @keyframes rainbow-text { + 0%, 100% { background-position: 0% 50%; } + 50% { background-position: 100% 50%; } + } + + .lead-text { + font-size: 1.2rem; + font-weight: 500; + margin-bottom: 2rem; + text-align: center; + opacity: 0.95; + } + + .feature-list { + list-style: none; + padding: 0; + margin: 2rem 0; + } + + .feature-list li { + padding: 0.8rem 0; + font-size: 1.1rem; + display: flex; + align-items: center; + border-bottom: 1px solid rgba(255, 255, 255, 0.2); + opacity: 0.9; + } + + .feature-list li:last-child { + border-bottom: none; + } + + .beta-callout { + background: rgba(255, 255, 255, 0.1); + padding: 1.5rem; + border-radius: 12px; + margin-top: 2rem; + text-align: center; + backdrop-filter: blur(10px); + border: 1px solid rgba(255, 255, 255, 0.2); + } + + .beta-callout h3 { + margin-bottom: 0.5rem; + font-size: 1.3rem; + color: #ffd700; + } + + .beta-callout p { + margin: 0; + font-size: 1rem; + opacity: 0.9; + } + + .ai-container { + padding: 2rem; + max-width: 1200px; + margin: 0 auto; + } + + h1 { + color: #333; + margin-bottom: 1rem; + background: linear-gradient(45deg, #dc143c, #ff4500, #ffa500, #32cd32, #1e90ff, #8a2be2); + background-size: 300% 300%; + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; + animation: rainbow-text 3s ease-in-out infinite; + font-weight: 700; + text-shadow: 0 0 15px rgba(0, 0, 0, 0.2); + filter: drop-shadow(0 0 8px rgba(0, 0, 0, 0.1)); + } + + .ai-content { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + gap: 2rem; + margin-top: 2rem; + } + + .feature-card { + background: #f8f9fa; + padding: 1.5rem; + border-radius: 8px; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); + transition: transform 0.2s ease; + } + + .feature-card:hover { + transform: translateY(-2px); + box-shadow: 0 4px 8px rgba(0,0,0,0.15); + } + + .feature-card h3 { + margin-bottom: 0.5rem; + color: #333; + } + + .feature-card p { + color: #666; + line-height: 1.5; + } + `] +}) +export class AiComponent { + paywall = false; + + constructor(private activatedRoute: ActivatedRoute) { + this.activatedRoute.data.subscribe(({ showPaywall }) => { + if (showPaywall) { + this.paywall = true; + } + }); + } +} \ No newline at end of file diff --git a/src/app/routes.ts b/src/app/routes.ts index ae260047..7c6f1e02 100644 --- a/src/app/routes.ts +++ b/src/app/routes.ts @@ -799,6 +799,13 @@ export const routes: Routes = [ ], canActivate: [loggedInGuard, licenseGuard], }, + { + path: ROUTES.AI, + loadComponent: () => + import('./ai/ai.component').then(m => m.AiComponent), + canActivate: [loggedInGuard, licenseGuard], + data: { showPaywall: true }, + }, { path: ROUTES.PROFILE, loadComponent: () => diff --git a/src/app/shared/components/df-side-nav/df-side-nav.component.html b/src/app/shared/components/df-side-nav/df-side-nav.component.html index c8ded1a4..2a1e316e 100644 --- a/src/app/shared/components/df-side-nav/df-side-nav.component.html +++ b/src/app/shared/components/df-side-nav/df-side-nav.component.html @@ -154,6 +154,7 @@

class="nav-item" [class.active]="isActive(item)" [class.commercial-feature]="isFeatureLocked(item.path, licenseType)" + [class.ai-nav-item]="item.path === '/ai'" (click)="handleNavClick(item)"> diff --git a/src/app/shared/components/df-side-nav/df-side-nav.component.scss b/src/app/shared/components/df-side-nav/df-side-nav.component.scss index 3d3ebe4f..0a6055ae 100644 --- a/src/app/shared/components/df-side-nav/df-side-nav.component.scss +++ b/src/app/shared/components/df-side-nav/df-side-nav.component.scss @@ -159,6 +159,85 @@ $red-palette: mat.define-palette(mat.$red-palette); ::ng-deep .mat-mdc-button-touch-target { background-color: #f6f2fa; } + + // Special styling for AI navigation item + &.ai-nav-item { + position: relative; + overflow: hidden; + + &::before { + content: ''; + position: absolute; + top: 0; + left: -100%; + width: 100%; + height: 100%; + background: linear-gradient(90deg, + transparent, + rgba(220, 20, 60, 0.15), + rgba(255, 69, 0, 0.15), + rgba(255, 165, 0, 0.15), + rgba(50, 205, 50, 0.15), + rgba(30, 144, 255, 0.15), + rgba(138, 43, 226, 0.15), + transparent + ); + animation: rainbow-slide 3s ease-in-out infinite; + } + + span { + background: linear-gradient(45deg, #dc143c, #ff4500, #ffa500, #32cd32, #1e90ff, #8a2be2); + background-size: 300% 300%; + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; + animation: rainbow-text 2s ease-in-out infinite; + font-weight: 700; + text-shadow: 0 0 15px rgba(0, 0, 0, 0.3); + filter: drop-shadow(0 0 8px rgba(0, 0, 0, 0.2)); + } + + img { + filter: hue-rotate(0deg) saturate(2) brightness(0.8) contrast(1.3); + animation: rainbow-icon 4s linear infinite; + drop-shadow: 0 0 6px rgba(0, 0, 0, 0.3); + } + + &:hover { + &::before { + animation-duration: 1s; + } + + span { + animation-duration: 1s; + } + + img { + animation-duration: 2s; + } + } + } + + @keyframes rainbow-slide { + 0% { left: -100%; } + 50% { left: 100%; } + 100% { left: -100%; } + } + + @keyframes rainbow-text { + 0%, 100% { background-position: 0% 50%; } + 50% { background-position: 100% 50%; } + } + + @keyframes rainbow-icon { + 0% { filter: hue-rotate(0deg) saturate(2) brightness(0.8) contrast(1.3) drop-shadow(0 0 6px rgba(220, 20, 60, 0.4)); } + 16.66% { filter: hue-rotate(60deg) saturate(2.2) brightness(0.7) contrast(1.4) drop-shadow(0 0 6px rgba(255, 69, 0, 0.4)); } + 33.33% { filter: hue-rotate(120deg) saturate(2.4) brightness(0.6) contrast(1.5) drop-shadow(0 0 6px rgba(255, 165, 0, 0.4)); } + 50% { filter: hue-rotate(180deg) saturate(2.2) brightness(0.7) contrast(1.4) drop-shadow(0 0 6px rgba(50, 205, 50, 0.4)); } + 66.66% { filter: hue-rotate(240deg) saturate(2) brightness(0.8) contrast(1.3) drop-shadow(0 0 6px rgba(30, 144, 255, 0.4)); } + 83.33% { filter: hue-rotate(300deg) saturate(2.2) brightness(0.7) contrast(1.4) drop-shadow(0 0 6px rgba(138, 43, 226, 0.4)); } + 100% { filter: hue-rotate(360deg) saturate(2) brightness(0.8) contrast(1.3) drop-shadow(0 0 6px rgba(220, 20, 60, 0.4)); } + } &.active { ::ng-deep .mat-mdc-button-touch-target { background-color: #e3dfff; diff --git a/src/app/shared/types/routes.ts b/src/app/shared/types/routes.ts index 768263d9..3794b4b8 100644 --- a/src/app/shared/types/routes.ts +++ b/src/app/shared/types/routes.ts @@ -16,6 +16,7 @@ export enum ROUTES { QUICKSTART = 'quickstart', RESOURCES = 'resources', DOWNLOAD = 'download', + AI = 'ai', API_CONNECTIONS = 'api-connections', API_TYPES = 'api-types', DATABASE = 'database', diff --git a/src/app/shared/utilities/route.ts b/src/app/shared/utilities/route.ts index 3ea19119..5b04e1c1 100644 --- a/src/app/shared/utilities/route.ts +++ b/src/app/shared/utilities/route.ts @@ -15,6 +15,7 @@ const filteredFromNav = [ const navIcons = [ 'home', + 'ai', 'admin-settings', 'api-connections', 'api-security', @@ -62,7 +63,7 @@ export function accessibleRoutes( navs: Array