Skip to content

Commit faa460b

Browse files
authored
Merge pull request #483 from dreamfactorysoftware/feature/custom-tool-unsaved-guard
add guard to interrupt saving mcp service if custom mcp tools are not…
2 parents 569506c + ba223a3 commit faa460b

5 files changed

Lines changed: 88 additions & 6 deletions

File tree

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@
1010
<body class="mat-typography">
1111
<df-root></df-root>
1212
<script type="text/javascript" src="https://assets.calendly.com/assets/external/widget.js"></script>
13-
<script src="runtime.6ff9cce765026bb8.js" type="module"></script><script src="polyfills.def0190516b19e6b.js" type="module"></script><script src="main.9dba73d7b14cb3b1.js" type="module"></script></body>
13+
<script src="runtime.855e89e805f57b48.js" type="module"></script><script src="polyfills.def0190516b19e6b.js" type="module"></script><script src="main.9dba73d7b14cb3b1.js" type="module"></script></body>
1414
</html>
Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/app/adf-services/df-service-details/df-service-details.component.html

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1088,8 +1088,8 @@ <h4>
10881088
</button>
10891089
</mat-menu>
10901090
<mat-hint
1091-
>Use &#123;LOOKUP_NAME&#125; for secrets or
1092-
&#123;param&#125; for path parameters</mat-hint
1091+
>Use &#123;LOOKUP_NAME&#125; for secrets or &#123;param&#125;
1092+
for path parameters</mat-hint
10931093
>
10941094
</mat-form-field>
10951095

@@ -1415,3 +1415,34 @@ <h5>Parameters</h5>
14151415
*ngIf="subscriptionRequired"
14161416
[serviceName]="selectedServiceTypeLable || 'Unable to fetch service name'">
14171417
</df-paywall>
1418+
1419+
<ng-template #unsavedToolDialog>
1420+
<h1 mat-dialog-title>Unsaved custom tool</h1>
1421+
<div mat-dialog-content>
1422+
You have unsaved changes in the custom tool editor. Saving the service now
1423+
will discard those changes unless you add/update the tool first.
1424+
</div>
1425+
<div mat-dialog-actions align="end">
1426+
<button
1427+
mat-flat-button
1428+
type="button"
1429+
(click)="closeUnsavedToolDialog('cancel')">
1430+
Keep editing
1431+
</button>
1432+
<button
1433+
mat-flat-button
1434+
color="warn"
1435+
type="button"
1436+
(click)="closeUnsavedToolDialog('discard')">
1437+
Discard tool changes
1438+
</button>
1439+
<button
1440+
mat-flat-button
1441+
color="primary"
1442+
cdkFocusInitial
1443+
type="button"
1444+
(click)="closeUnsavedToolDialog('save')">
1445+
Add/Update tool, then save
1446+
</button>
1447+
</div>
1448+
</ng-template>

src/app/adf-services/df-service-details/df-service-details.component.ts

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
Inject,
66
Input,
77
OnInit,
8+
TemplateRef,
89
ViewChild,
910
} from '@angular/core';
1011
import {
@@ -72,7 +73,11 @@ import { DfPaywallComponent } from 'src/app/shared/components/df-paywall/df-payw
7273
import { CommonModule } from '@angular/common';
7374
import { MatIconModule } from '@angular/material/icon';
7475
import { HttpClient } from '@angular/common/http';
75-
import { MatDialog, MatDialogModule } from '@angular/material/dialog';
76+
import {
77+
MatDialog,
78+
MatDialogModule,
79+
MatDialogRef,
80+
} from '@angular/material/dialog';
7681
import { MatMenuModule } from '@angular/material/menu';
7782
import { DfThemeService } from 'src/app/shared/services/df-theme.service';
7883
import { MatButtonToggleModule } from '@angular/material/button-toggle';
@@ -94,6 +99,8 @@ import { DfSystemService } from 'src/app/shared/services/df-system.service';
9499
import { DfPaywallModal } from 'src/app/shared/components/df-paywall-modal/df-paywall-modal.component';
95100
import { DfAnalyticsService } from 'src/app/shared/services/df-analytics.service';
96101

102+
type UnsavedToolChoice = 'save' | 'discard' | 'cancel';
103+
97104
// Add these interfaces at the bottom of the file with the other interfaces
98105
interface RoleResponse {
99106
resource: Array<{
@@ -159,6 +166,7 @@ interface ServiceResponse {
159166
MatDividerModule,
160167
DfSecurityConfigComponent,
161168
MatMenuModule,
169+
MatDialogModule,
162170
],
163171
})
164172
export class DfServiceDetailsComponent implements OnInit {
@@ -255,6 +263,10 @@ export class DfServiceDetailsComponent implements OnInit {
255263
availableLookups: Array<{ name: string }> = [];
256264
@ViewChild('functionEditor') functionEditor: DfAceEditorComponent;
257265
@ViewChild('headersEditor') headersEditor: DfAceEditorComponent;
266+
@ViewChild('unsavedToolDialog')
267+
unsavedToolDialogTpl!: TemplateRef<unknown>;
268+
private unsavedToolDialogRef: MatDialogRef<unknown, UnsavedToolChoice> | null =
269+
null;
258270
private liveHeadersValue: string | null = null;
259271
private liveFunctionValue: string | null = null;
260272

@@ -1155,6 +1167,14 @@ export class DfServiceDetailsComponent implements OnInit {
11551167
this.editingToolIndex = null;
11561168
}
11571169

1170+
hasUnsavedCustomTool(): boolean {
1171+
return this.editingToolIndex !== null && this.customToolForm.dirty;
1172+
}
1173+
1174+
closeUnsavedToolDialog(choice: UnsavedToolChoice) {
1175+
this.unsavedToolDialogRef?.close(choice);
1176+
}
1177+
11581178
toggleCustomTool(index: number, enabled: boolean) {
11591179
this.customTools[index].enabled = enabled;
11601180
}
@@ -1450,6 +1470,37 @@ export class DfServiceDetailsComponent implements OnInit {
14501470
warnings: string[] = [];
14511471

14521472
save(Cache: boolean, Continue: boolean) {
1473+
if (this.hasUnsavedCustomTool()) {
1474+
if (this.unsavedToolDialogRef) return;
1475+
this.unsavedToolDialogRef = this.dialog.open<
1476+
unknown,
1477+
unknown,
1478+
UnsavedToolChoice
1479+
>(this.unsavedToolDialogTpl, {
1480+
width: '440px',
1481+
disableClose: true,
1482+
});
1483+
this.unsavedToolDialogRef.afterClosed().subscribe(choice => {
1484+
this.unsavedToolDialogRef = null;
1485+
if (!choice || choice === 'cancel') return;
1486+
if (choice === 'save') {
1487+
if (this.customToolForm.invalid) {
1488+
this.snackbarService.openSnackBar(
1489+
'Custom tool has invalid fields. Fix them or discard the edit before saving the service.',
1490+
'error'
1491+
);
1492+
return;
1493+
}
1494+
this.saveCustomTool();
1495+
} else {
1496+
this.cancelCustomToolEdit();
1497+
}
1498+
this.customToolForm.markAsPristine();
1499+
this.save(Cache, Continue);
1500+
});
1501+
return;
1502+
}
1503+
14531504
const data = this.serviceForm.getRawValue();
14541505
if (data.type === '' || data.name === '') {
14551506
return;

0 commit comments

Comments
 (0)