Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
8eb9293
fix(services): stop scoring API Health on docs and rate limits
codyllord Aug 12, 2026
607960f
fix(nav): show the record's name, not its id, on detail pages
codyllord Aug 12, 2026
2e9d4d7
chore: rebuild dist
codyllord Aug 12, 2026
2d9131f
fix(home): stop the KPI tiles spilling onto the exposure strip
codyllord Aug 12, 2026
0cf2346
chore: rebuild dist
codyllord Aug 12, 2026
ee96778
Rebuild dist with suggestion chips and task cost estimator
Aug 12, 2026
fbcbb9a
feat(services): render a service's health issues on its own page
codyllord Aug 12, 2026
22ed60b
chore: rebuild dist
codyllord Aug 12, 2026
8d3eee6
feat(services): probe the connection, and stop calling governance "he…
codyllord Aug 12, 2026
cac6392
chore: rebuild dist
codyllord Aug 12, 2026
094fdd2
feat(services): the Health column checks the connection for the rows …
codyllord Aug 12, 2026
31306dd
chore: rebuild dist
codyllord Aug 12, 2026
9916438
fix(services): drop the Health column from the Platform APIs list
codyllord Aug 12, 2026
ddf9b82
chore: rebuild dist
codyllord Aug 12, 2026
5c086ab
fix(schema-contracts): legible muted text in dark mode
codyllord Aug 12, 2026
b63a254
chore: rebuild dist
codyllord Aug 12, 2026
39aa7c6
fix(schema-contracts): theme the dialogs, not just the page
codyllord Aug 12, 2026
8fa98ac
chore: rebuild dist
codyllord Aug 12, 2026
42a357d
Merge pull request #513 from dreamfactorysoftware/fix/service-health-…
codyllord Aug 12, 2026
3bacf3e
Merge remote-tracking branch 'origin/7.7' into ui-dist-l13-77merge
codyllord Aug 12, 2026
9de16ca
fix(api-docs): let a path token fall back to typing when nothing enum…
codyllord Aug 12, 2026
3be5224
chore: rebuild dist
codyllord Aug 12, 2026
506e160
Merge pull request #514 from dreamfactorysoftware/fix/api-docs-token-…
codyllord Aug 12, 2026
0ed9e44
Merge remote-tracking branch 'origin/7.7' into ui-dist-l13-77merge
codyllord Aug 12, 2026
ee6cb84
Paywall catalog: list AI Connection, AI Chat, and Agents as Silver fe…
Aug 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions dist/1253.3400258b24ebe59d.js

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion dist/1253.ed342192b50aefed.js

This file was deleted.

1 change: 0 additions & 1 deletion dist/175.3c14a1e2f6298dfa.js

This file was deleted.

1 change: 1 addition & 0 deletions dist/2043.4bdd2413d0ee95ec.js

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion dist/2043.548e75e6cfa0dfc3.js

This file was deleted.

1 change: 1 addition & 0 deletions dist/244.d0b627b6ad16c7c7.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions dist/2816.732a28513a2ef47e.js

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion dist/2816.76ef700252bf4617.js

This file was deleted.

1 change: 1 addition & 0 deletions dist/2830.834124b37a055da8.js

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion dist/2830.fdb32583ec23eca4.js

This file was deleted.

1 change: 0 additions & 1 deletion dist/2841.332af07c62d25a89.js

This file was deleted.

1 change: 1 addition & 0 deletions dist/2841.a98cbf0354191c0c.js

Large diffs are not rendered by default.

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion dist/3386.7f7bf384a0fa636c.js

This file was deleted.

1 change: 1 addition & 0 deletions dist/3386.a7a425ab6245602a.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions dist/3587.279d2d3a66efb79e.js

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion dist/3587.5f4b155c3354ab45.js

This file was deleted.

1 change: 0 additions & 1 deletion dist/3696.f11f1d0814d9d189.js

This file was deleted.

1 change: 0 additions & 1 deletion dist/3710.13615836fc5c6264.js

This file was deleted.

1 change: 1 addition & 0 deletions dist/3710.b6d536d2648cfc64.js

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion dist/372.7caf8d90bc2d82ff.js

This file was deleted.

1 change: 1 addition & 0 deletions dist/4440.3124ccc9eb8403e8.js

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion dist/4440.ee586646d4ac9f82.js

This file was deleted.

1 change: 1 addition & 0 deletions dist/4721.76271d2a5c5f49a2.js

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion dist/4721.7cec5d45400c273e.js

This file was deleted.

1 change: 0 additions & 1 deletion dist/5632.269eb71d4aee5a8e.js

This file was deleted.

1 change: 1 addition & 0 deletions dist/5632.efcc0a0f173eb8ac.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions dist/582.4b1eda425d5188db.js

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion dist/582.78f0576b7c8af839.js

This file was deleted.

1 change: 1 addition & 0 deletions dist/6049.8ccee7f6f6820d11.js

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion dist/6049.d35cbebd8d72f2b0.js

This file was deleted.

1 change: 1 addition & 0 deletions dist/6234.28f311c7cb27269e.js

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion dist/6755.1e50d089bbb9fa19.js

This file was deleted.

1 change: 1 addition & 0 deletions dist/6755.3fe9a6af80c0a3a1.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions dist/7632.b15be87648835134.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions dist/7649.918c444314eb1310.js

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion dist/7649.b0118eab35c79277.js

This file was deleted.

1 change: 0 additions & 1 deletion dist/8270.51a3ab5135ed85c2.js

This file was deleted.

1 change: 1 addition & 0 deletions dist/8270.ba07a82722ac15d2.js

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion dist/849.f5cc5867134e2d56.js

This file was deleted.

1 change: 1 addition & 0 deletions dist/9864.6c389c5e29898e1d.js

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion dist/987.2f862bf67c276885.js

This file was deleted.

1 change: 1 addition & 0 deletions dist/987.de33e41bbe272af4.js

Large diffs are not rendered by default.

19 changes: 16 additions & 3 deletions dist/assets/i18n/services/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,24 @@
"warning": "Needs attention",
"danger": "Action required"
},
"panelAria": "Health issues for this service",
"probe": {
"checking": "Checking the connection…",
"ok": "Connected. No issues found.",
"failed": "Cannot reach this service.",
"unsupported": "No issues found. This API type has no automatic connection check."
},
"rules": {
"noAccess": "No role grants access. This service is unreachable by any key.",
"noRateLimit": "No rate limit. Requests are uncapped.",
"noDocs": "No API docs. Consumers have no reference to call it.",
"deprecated": "Marked deprecated. Migrate consumers off this service."
"deprecated": "Marked deprecated. Migrate consumers off this service.",
"cannotConnect": "Cannot reach this service. Check its host and credentials."
},
"fix": {
"noAccess": "Create a role"
},
"chip": {
"checking": "Checking…",
"notChecked": "Not checked"
}
},
"details": "Details",
Expand Down
1 change: 1 addition & 0 deletions dist/common.00ccefaeda6de209.js

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion dist/common.9644b132939e7cd4.js

This file was deleted.

2 changes: 1 addition & 1 deletion dist/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@
<body class="mat-typography">
<df-root></df-root>
<script type="text/javascript" src="https://assets.calendly.com/assets/external/widget.js"></script>
<script src="runtime.c9d3559367041dba.js" type="module"></script><script src="polyfills.cb64ea9d35bc0a9e.js" type="module"></script><script src="main.2326f54e436cf17e.js" type="module"></script></body>
<script src="runtime.e938efa51f89e24f.js" type="module"></script><script src="polyfills.cb64ea9d35bc0a9e.js" type="module"></script><script src="main.721fb9d555625343.js" type="module"></script></body>
</html>
1 change: 0 additions & 1 deletion dist/main.2326f54e436cf17e.js

This file was deleted.

1 change: 1 addition & 0 deletions dist/main.721fb9d555625343.js

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion dist/runtime.c9d3559367041dba.js

This file was deleted.

1 change: 1 addition & 0 deletions dist/runtime.e938efa51f89e24f.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@
<span *ngIf="!seg.token" class="rb-seg">{{ seg.text }}</span>
<ng-container *ngIf="seg.token as tk">
<select
*ngIf="isEnumerableToken(tk); else segText"
*ngIf="usePicker(tk); else segText"
class="rb-token"
[class.rb-token--empty]="!tokenValues[tk.token]"
[ngModel]="tokenValues[tk.token] || ''"
Expand Down
72 changes: 66 additions & 6 deletions src/app/adf-api-docs/df-api-docs/df-api-docs.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,41 @@ import { DfApiDocsComponent } from './df-api-docs.component';
import { createTestBedConfig } from 'src/app/shared/utilities/testbed-config';
import { mockApiDocsData } from './test-utilities/df-api-docs.mock';
import { Router } from '@angular/router';
import { MatSnackBar } from '@angular/material/snack-bar';

const snackBarStub = {
provide: MatSnackBar,
useValue: { open: jest.fn(), dismiss: jest.fn() },
};

describe('DfApiDocsComponent', () => {
let component: DfApiDocsComponent;
let fixture: ComponentFixture<DfApiDocsComponent>;
let router: Router;

beforeEach(() => {
TestBed.configureTestingModule(
createTestBedConfig(DfApiDocsComponent, [], {
data: {
...mockApiDocsData,
TestBed.configureTestingModule({
...createTestBedConfig(
DfApiDocsComponent,
// The component injects MatSnackBar directly; without a provider every
// test fails at createComponent with a NullInjectorError, before it
// reaches its assertion.
[snackBarStub],
{
data: {
...mockApiDocsData,
},
},
})
);
[],
// ngOnInit reads the service name off the route snapshot; without it
// the component throws before the fixture is usable.
{ name: 'db' }
),
// The swagger-ui host this component renders into throws while jsdom
// tears the fixture down, which fails otherwise-passing tests during
// cleanup rather than in their own body.
teardown: { destroyAfterEach: false },
});

router = TestBed.inject(Router);

Expand All @@ -30,6 +51,45 @@ describe('DfApiDocsComponent', () => {
expect(component).toBeTruthy();
});

describe('path token pickers', () => {
const tableToken = {
token: 'table_name',
kind: 'table' as const,
labelKey: 'apiDocs.token.table',
};
const freeToken = {
token: 'id',
kind: 'text' as const,
labelKey: null,
};

it('keeps the picker while the lookup is still in flight', () => {
component.tokenOptions = {};

expect(component.usePicker(tableToken)).toBe(true);
});

it('keeps the picker once options arrive', () => {
component.tokenOptions = { table_name: ['customers', 'orders'] };

expect(component.usePicker(tableToken)).toBe(true);
});

it('falls back to typing when nothing can be enumerated', () => {
// Empty covers both an honestly empty list (a service with no stored
// procedures) and a failed lookup, which the loaders swallow into [].
component.tokenOptions = { table_name: [] };

expect(component.usePicker(tableToken)).toBe(false);
});

it('never renders a picker for a free-text token', () => {
component.tokenOptions = { id: ['1', '2'] };

expect(component.usePicker(freeToken)).toBe(false);
});
});

it('should navigate away to api docs table successfully when the back button is clicked', () => {
const navigateSpy = jest.spyOn(router, 'navigate');

Expand Down
23 changes: 23 additions & 0 deletions src/app/adf-api-docs/df-api-docs/df-api-docs.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,29 @@ export class DfApiDocsComponent implements OnInit, OnDestroy {
return t.kind !== 'text';
}

/**
* Whether this token renders as a picker rather than a text box.
*
* A `{table_name}` / `{procedure_name}` / `{function_name}` token is only
* enumerable if something came back to enumerate. The lookup can legitimately
* return nothing - a service with no stored procedures - and it can fail
* outright (RBAC on the listing endpoint, a backend the service cannot
* reach); loadTableOptions/loadResourceOptions swallow that into an empty
* list. A <select> with no options and a disabled placeholder leaves the
* operation unrunnable with nothing to type into, so an empty list falls back
* to free text.
*
* `undefined` means the request is still in flight: keep the picker so the
* control does not flip from input to select underneath the user.
*/
usePicker(t: PathToken): boolean {
if (!this.isEnumerableToken(t)) {
return false;
}
const options = this.tokenOptions[t.token];
return options === undefined || options.length > 0;
}

/** A human label for a free-text token: its name with spaces for underscores.
* Bound as data, not a hardcoded UI string. */
humanizeToken(token: string): string {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ import { UntilDestroy } from '@ngneat/until-destroy';
import { LimitTableRowData } from '../types';
import { Actions } from 'src/app/shared/types/table';

/** Shown when a limit is not scoped to a user, service, or role. */
const PLACEHOLDER = '-';

@UntilDestroy({ checkProperties: true })
@Component({
selector: 'df-manage-limits-table',
Expand Down Expand Up @@ -116,9 +119,14 @@ export class DfManageLimitsTableComponent extends DfManageTableComponent<LimitTa
limitType: limit.type,
limitRate: `${limit.rate} / ${limit.period}`,
limitCounter: `${limit.limitCacheByLimitId[0].attempts} / ${limit.limitCacheByLimitId[0].max}`,
user: limit.userId,
service: limit.serviceId,
role: limit.roleId,
// The user/service/role columns show the related record's name. The
// relations come back on every fetch (see refreshTable's `related`);
// a limit that is not scoped to one has a null relation, not a
// missing name, so fall back to '-' rather than printing the raw id.
user:
limit.userByUserId?.name ?? limit.userByUserId?.email ?? PLACEHOLDER,
service: limit.serviceByServiceId?.name ?? PLACEHOLDER,
role: limit.roleByRoleId?.name ?? PLACEHOLDER,
active: limit.isActive,
};
});
Expand Down
12 changes: 6 additions & 6 deletions src/app/adf-limits/df-manage-limits/mocks/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,9 @@ export const mockTableData: LimitTableRowData[] = [
limitType: 'instance.user',
limitRate: '22 / minute',
limitCounter: '0 / 22',
user: 3,
service: null,
role: null,
user: 'Test User',
service: '-',
role: '-',
active: false,
},
{
Expand All @@ -80,9 +80,9 @@ export const mockTableData: LimitTableRowData[] = [
limitType: 'instance',
limitRate: '10000000 / day',
limitCounter: '0 / 10000000',
user: null,
service: null,
role: null,
user: '-',
service: '-',
role: '-',
active: false,
},
];
8 changes: 5 additions & 3 deletions src/app/adf-limits/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ export type LimitTableRowData = {
limitType: string;
limitRate: string;
limitCounter: string;
user: number | null;
service: number | null;
role: number | null;
// Display strings, not ids: the table resolves each relation to its name and
// falls back to '-' when the limit is not scoped to one.
user: string;
service: string;
role: string;
active: boolean;
};
Loading
Loading