@truenas/ui-components 0.7.5 → 0.7.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/truenas-ui-components.mjs +228 -20
- package/fesm2022/truenas-ui-components.mjs.map +1 -1
- package/package.json +1 -1
- package/scripts/jest.config.ts +9 -5
- package/scripts/release-config/commit-header-pattern.spec.ts +189 -0
- package/scripts/release-config/jest.config.ts +14 -0
- package/scripts/release-config/tsconfig.json +14 -0
- package/types/truenas-ui-components.d.ts +116 -5
package/package.json
CHANGED
package/scripts/jest.config.ts
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
import type { Config } from 'jest';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* `yarn test:scripts` — every build script under this
|
|
4
|
+
* `yarn test:scripts` — the repo's node-environment tests: every build script under this
|
|
5
|
+
* directory that has tests, plus `release-config`, which tests repo-root configuration
|
|
6
|
+
* rather than a script and lives here because this is where a node-environment Jest
|
|
7
|
+
* project already runs.
|
|
5
8
|
*
|
|
6
|
-
* One Jest project per
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
9
|
+
* One Jest project per package rather than one config rooted here, because `<rootDir>`
|
|
10
|
+
* inside a project config resolves to that project's own directory: each package keeps
|
|
11
|
+
* pointing ts-jest at its own `tsconfig.json`, and adding the next one costs a line here
|
|
12
|
+
* rather than a merge of compiler options.
|
|
10
13
|
*/
|
|
11
14
|
const config: Config = {
|
|
12
15
|
projects: [
|
|
13
16
|
'<rootDir>/harness-docs/jest.config.ts',
|
|
14
17
|
'<rootDir>/icon-sprite/jest.config.ts',
|
|
18
|
+
'<rootDir>/release-config/jest.config.ts',
|
|
15
19
|
],
|
|
16
20
|
};
|
|
17
21
|
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The PR title check and the release step both decide what a commit header means, from
|
|
3
|
+
* two patterns written in two files, and nothing made them agree. A scope naming two
|
|
4
|
+
* components with a comma — `feat(autocomplete,chip-input): …` — passed the title check,
|
|
5
|
+
* merged, and then matched no header pattern at all, so the commit analyzer read it as
|
|
6
|
+
* having no type: it triggered no release and appeared in no changelog (#315).
|
|
7
|
+
*
|
|
8
|
+
* These tests read both files rather than restating either pattern, so drift in either
|
|
9
|
+
* one fails here instead of silently dropping a merged commit from the next release.
|
|
10
|
+
*
|
|
11
|
+
* They live under the library's script tests because `yarn test:scripts` is where this
|
|
12
|
+
* repo runs Jest in a node environment; what they cover is repo-root release
|
|
13
|
+
* configuration, which is why they reach four directories up.
|
|
14
|
+
*/
|
|
15
|
+
import { readFileSync } from 'node:fs';
|
|
16
|
+
import { join } from 'node:path';
|
|
17
|
+
|
|
18
|
+
const repoRoot = join(__dirname, '..', '..', '..', '..');
|
|
19
|
+
|
|
20
|
+
interface ParserOpts {
|
|
21
|
+
headerPattern: string;
|
|
22
|
+
headerCorrespondence: string[];
|
|
23
|
+
breakingHeaderPattern: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
type PluginEntry = string | [string, { parserOpts?: ParserOpts }];
|
|
27
|
+
|
|
28
|
+
const releaseConfig = JSON.parse(
|
|
29
|
+
readFileSync(join(repoRoot, '.releaserc.json'), 'utf8')
|
|
30
|
+
) as { plugins: PluginEntry[] };
|
|
31
|
+
|
|
32
|
+
/** Every semantic-release plugin that parses commit headers, with its plugin name. */
|
|
33
|
+
const parsingPlugins: [string, ParserOpts][] = [];
|
|
34
|
+
|
|
35
|
+
for (const plugin of releaseConfig.plugins) {
|
|
36
|
+
if (Array.isArray(plugin)) {
|
|
37
|
+
const [name, options] = plugin;
|
|
38
|
+
|
|
39
|
+
if (options.parserOpts) {
|
|
40
|
+
parsingPlugins.push([name, options.parserOpts]);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The Bash pattern the PR title check runs, lifted from the workflow that runs it.
|
|
47
|
+
*
|
|
48
|
+
* `[[ =~ ]]` and `RegExp` both leave the end unanchored and the pattern anchors its own
|
|
49
|
+
* start, so a JS `RegExp` accepts what the check accepts for the constructs it uses:
|
|
50
|
+
* groups, alternation, character classes and `?`.
|
|
51
|
+
*/
|
|
52
|
+
function readPrTitlePattern(): RegExp {
|
|
53
|
+
const workflow = readFileSync(join(repoRoot, '.github/workflows/pr-title.yml'), 'utf8');
|
|
54
|
+
const assignment = /^\s*pattern='([^']+)'\s*$/m.exec(workflow);
|
|
55
|
+
|
|
56
|
+
if (!assignment) {
|
|
57
|
+
throw new Error('no `pattern=<...>` assignment found in .github/workflows/pr-title.yml');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return new RegExp(assignment[1]);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const prTitleCheck = readPrTitlePattern();
|
|
64
|
+
|
|
65
|
+
/** What the release step reads out of a header, or null when it matches nothing. */
|
|
66
|
+
function parseHeader(opts: ParserOpts, header: string): Record<string, string | undefined> | null {
|
|
67
|
+
const match = new RegExp(opts.headerPattern).exec(header);
|
|
68
|
+
|
|
69
|
+
if (!match) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return Object.fromEntries(
|
|
74
|
+
opts.headerCorrespondence.map((field, index) => [field, match[index + 1]])
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const commaScopeHeader =
|
|
79
|
+
'NAS-142381 / 27.0.0-BETA.1 / feat(autocomplete,chip-input): drive options from an async [dataSource] (#312)';
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Headers the PR title check accepts. Every one is asserted to pass the check as well as
|
|
83
|
+
* to parse, so a case that stops being realistic fails rather than passing vacuously.
|
|
84
|
+
*/
|
|
85
|
+
const acceptedHeaders: { name: string; header: string; type: string; scope?: string }[] = [
|
|
86
|
+
{
|
|
87
|
+
name: 'a single-word scope',
|
|
88
|
+
header: 'feat(table): let a selection survive a dataSource change',
|
|
89
|
+
type: 'feat',
|
|
90
|
+
scope: 'table',
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
name: 'the ticket and version prefix a squash commit carries',
|
|
94
|
+
header: 'NAS-143108 / 27.0.0-BETA.1 / fix(table): stop the pager aliasing pagination',
|
|
95
|
+
type: 'fix',
|
|
96
|
+
scope: 'table',
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
name: 'no scope at all',
|
|
100
|
+
header: 'chore: bump the toolchain',
|
|
101
|
+
type: 'chore',
|
|
102
|
+
scope: undefined,
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
name: 'two components separated by a comma (#315)',
|
|
106
|
+
header: commaScopeHeader,
|
|
107
|
+
type: 'feat',
|
|
108
|
+
scope: 'autocomplete,chip-input',
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
name: 'a comma and a space between components',
|
|
112
|
+
header: 'feat(autocomplete, chip-input): drive options from an async [dataSource]',
|
|
113
|
+
type: 'feat',
|
|
114
|
+
scope: 'autocomplete, chip-input',
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
name: 'a scope with a slash',
|
|
118
|
+
header: 'refactor(a11y/labels): fold the fallback into one helper',
|
|
119
|
+
type: 'refactor',
|
|
120
|
+
scope: 'a11y/labels',
|
|
121
|
+
},
|
|
122
|
+
];
|
|
123
|
+
|
|
124
|
+
describe('.releaserc.json', () => {
|
|
125
|
+
it('has more than one plugin parsing commit headers, one of them the commit analyzer', () => {
|
|
126
|
+
expect(parsingPlugins.length).toBeGreaterThan(1);
|
|
127
|
+
expect(parsingPlugins.map(([name]) => name)).toContain('@semantic-release/commit-analyzer');
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('gives all of them the same parser options, so notes and version bumps agree', () => {
|
|
131
|
+
const [[, first]] = parsingPlugins;
|
|
132
|
+
|
|
133
|
+
// The plugin name rides along in the assertion so a failure says which one drifted.
|
|
134
|
+
for (const [name, opts] of parsingPlugins) {
|
|
135
|
+
expect([name, opts]).toEqual([name, first]);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
describe.each(parsingPlugins)('%s', (_pluginName, opts) => {
|
|
141
|
+
it.each(acceptedHeaders)('parses $name', ({ header, type, scope }) => {
|
|
142
|
+
expect(parseHeader(opts, header)).toMatchObject({ type, scope, subject: expect.any(String) });
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it('reads a comma scope as one scope, leaving the subject whole', () => {
|
|
146
|
+
expect(parseHeader(opts, commaScopeHeader)?.subject).toBe(
|
|
147
|
+
'drive options from an async [dataSource] (#312)'
|
|
148
|
+
);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it('recognises a breaking change whose scope contains a comma', () => {
|
|
152
|
+
const breaking = new RegExp(opts.breakingHeaderPattern).exec(
|
|
153
|
+
'feat(autocomplete,chip-input)!: options are now a dataSource'
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
expect(breaking?.[1]).toBe('feat');
|
|
157
|
+
expect(breaking?.[2]).toBe('autocomplete,chip-input');
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
describe('the PR title check and the release step', () => {
|
|
162
|
+
it.each(acceptedHeaders)('agree on $name', ({ header, type }) => {
|
|
163
|
+
expect(prTitleCheck.test(header)).toBe(true);
|
|
164
|
+
|
|
165
|
+
for (const [, opts] of parsingPlugins) {
|
|
166
|
+
expect(parseHeader(opts, header)).toMatchObject({ type });
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it('agree on every scope character the check allows, not a narrower set', () => {
|
|
171
|
+
// The check's scope is `\([^)]+\)`. A release pattern with a narrower scope class is
|
|
172
|
+
// what produced #315: the title passed, the commit merged, the release dropped it.
|
|
173
|
+
const scopes = ['a,b', 'a, b', 'a/b', 'a.b', 'a-b', 'a b', 'a:b', 'a+b', 'a&b', 'a#b', '@scope/pkg'];
|
|
174
|
+
|
|
175
|
+
for (const scope of scopes) {
|
|
176
|
+
const header = `feat(${scope}): a subject`;
|
|
177
|
+
|
|
178
|
+
expect(prTitleCheck.test(header)).toBe(true);
|
|
179
|
+
|
|
180
|
+
for (const [, opts] of parsingPlugins) {
|
|
181
|
+
expect(parseHeader(opts, header)).toEqual({
|
|
182
|
+
type: 'feat',
|
|
183
|
+
scope,
|
|
184
|
+
subject: 'a subject',
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Config } from 'jest';
|
|
2
|
+
|
|
3
|
+
const config: Config = {
|
|
4
|
+
testEnvironment: 'node',
|
|
5
|
+
transform: {
|
|
6
|
+
'^.+\\.tsx?$': ['ts-jest', {
|
|
7
|
+
tsconfig: '<rootDir>/tsconfig.json',
|
|
8
|
+
}],
|
|
9
|
+
},
|
|
10
|
+
testMatch: ['<rootDir>/**/*.spec.ts'],
|
|
11
|
+
moduleFileExtensions: ['ts', 'js', 'json'],
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export default config;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "Node16",
|
|
5
|
+
"moduleResolution": "Node16",
|
|
6
|
+
"esModuleInterop": true,
|
|
7
|
+
"isolatedModules": true,
|
|
8
|
+
"strict": true,
|
|
9
|
+
"types": ["jest", "node"],
|
|
10
|
+
"rootDir": ".",
|
|
11
|
+
"outDir": "../../dist/out-tsc/scripts"
|
|
12
|
+
},
|
|
13
|
+
"include": ["**/*.ts"]
|
|
14
|
+
}
|
|
@@ -9686,6 +9686,63 @@ declare class TnTableComponent<T = unknown> implements OnInit {
|
|
|
9686
9686
|
* full list it holds, and call {@link clearSelection} once a batch action is done.
|
|
9687
9687
|
*/
|
|
9688
9688
|
selectionKey: _angular_core.InputSignal<((row: T) => unknown) | undefined>;
|
|
9689
|
+
/**
|
|
9690
|
+
* Identifies a row for EXPANSION, so an open detail row survives a `dataSource` change.
|
|
9691
|
+
*
|
|
9692
|
+
* Detail rows are held by object identity, and a consumer that re-fetches hands back new
|
|
9693
|
+
* objects for the same rows — so without a key a background reload closes the row the
|
|
9694
|
+
* user opened, which is usually the moment its contents are worth watching (a running
|
|
9695
|
+
* job's logs, say). With a key set, the table re-points the open rows at the new objects
|
|
9696
|
+
* instead of collapsing them.
|
|
9697
|
+
*
|
|
9698
|
+
* A row the new `data()` does not carry — another page, another tab, filtered out — is
|
|
9699
|
+
* kept, not dropped, and re-opens on its own once that row is listed again. Retention is
|
|
9700
|
+
* unconditional for the same reason it is for {@link selectionKey}: the table sees one
|
|
9701
|
+
* page and cannot tell a row that moved off-screen from one that is gone for good. Call
|
|
9702
|
+
* {@link clearExpansion} when the consumer knows it is gone.
|
|
9703
|
+
*
|
|
9704
|
+
* Without it the table keeps its historical behaviour — any `dataSource` reference change
|
|
9705
|
+
* collapses every open row.
|
|
9706
|
+
*
|
|
9707
|
+
* With a key set, drive expansion through {@link toggleRowExpansion}, {@link expandRow}
|
|
9708
|
+
* and {@link clearExpansion} rather than writing {@link expandedRows} directly, or the
|
|
9709
|
+
* retained set and the visible set drift apart.
|
|
9710
|
+
*
|
|
9711
|
+
* Pass a key that identifies the ROW, not its position, and bind a stable member rather
|
|
9712
|
+
* than writing the function in the template: `[expansionKey]="rowKey"` for a
|
|
9713
|
+
* `rowKey = (row: Job) => row.id` on the host.
|
|
9714
|
+
*/
|
|
9715
|
+
expansionKey: _angular_core.InputSignal<((row: T) => unknown) | undefined>;
|
|
9716
|
+
/**
|
|
9717
|
+
* Test id for each ROW, as a function of the row and its index.
|
|
9718
|
+
*
|
|
9719
|
+
* The table writes no id on a `<tr>` of its own, and a cell body is free to be bare
|
|
9720
|
+
* interpolation — `{{ row.username }}` renders no element the consumer can bind to. A list
|
|
9721
|
+
* built that way is unaddressable: an automated suite that has to open, select or delete one
|
|
9722
|
+
* specific row has nothing to select it by but position or cell text, both of which change
|
|
9723
|
+
* under the test. Set this and every row carries `row-<base>` on the `<tr>`, and on its card
|
|
9724
|
+
* in card mode, through the same {@link TnTestIdDirective} as every other id the library
|
|
9725
|
+
* emits — so it honours {@link TN_TEST_ATTR} and is kebab-cased by {@link composeTestId}.
|
|
9726
|
+
*
|
|
9727
|
+
* Pass the base only, not the `row-` prefix, and identify the ROW rather than its position,
|
|
9728
|
+
* the way {@link selectionKey} and {@link expansionKey} do — an index-derived id renames every
|
|
9729
|
+
* row below the one that was deleted. The index is passed for the case where the data genuinely
|
|
9730
|
+
* has nothing unique in it.
|
|
9731
|
+
*
|
|
9732
|
+
* Bind a stable member rather than writing the function in the template, since Angular's
|
|
9733
|
+
* expression grammar has no arrow functions:
|
|
9734
|
+
* `[rowTestId]="rowTestId"` for a `rowTestId = (row: User) => row.username` on the host.
|
|
9735
|
+
*
|
|
9736
|
+
* ```html
|
|
9737
|
+
* <tn-table [dataSource]="users" [rowTestId]="rowTestId" />
|
|
9738
|
+
* <!-- <tr data-testid="row-jane-doe"> -->
|
|
9739
|
+
* ```
|
|
9740
|
+
*
|
|
9741
|
+
* Cells are not covered by this: a suite that has to read one cell of a row still needs an id
|
|
9742
|
+
* on the element that cell renders. Tagging the row is what makes the row itself reachable —
|
|
9743
|
+
* which is the part a consumer cannot add from the outside.
|
|
9744
|
+
*/
|
|
9745
|
+
rowTestId: _angular_core.InputSignal<((row: T, index: number) => TnTestIdValue) | undefined>;
|
|
9689
9746
|
emptyMessage: _angular_core.InputSignal<string>;
|
|
9690
9747
|
/**
|
|
9691
9748
|
* Optional second line under `emptyMessage`, for empty states that carry both a headline and an
|
|
@@ -9897,12 +9954,25 @@ declare class TnTableComponent<T = unknown> implements OnInit {
|
|
|
9897
9954
|
sortColumn: _angular_core.ModelSignal<string>;
|
|
9898
9955
|
sortDirection: _angular_core.ModelSignal<"" | "desc" | "asc">;
|
|
9899
9956
|
/**
|
|
9900
|
-
*
|
|
9901
|
-
*
|
|
9902
|
-
*
|
|
9903
|
-
*
|
|
9957
|
+
* The rows of the CURRENT `data()` whose detail row is open, by object identity.
|
|
9958
|
+
*
|
|
9959
|
+
* Replacing the data array collapses everything unless {@link expansionKey} is set, in
|
|
9960
|
+
* which case this is the visible slice of {@link expandedByKey} and survives the swap.
|
|
9961
|
+
*
|
|
9962
|
+
* Writable for consumers that predate {@link expansionKey}. **Adding a key to a consumer
|
|
9963
|
+
* that writes this signal directly is a migration, not a drop-in**: a write here closes
|
|
9964
|
+
* what is on screen but never touches the retained map, so every row whose key is still in
|
|
9965
|
+
* it re-opens on the next reconcile — the one it just closed included. Move those writes to
|
|
9966
|
+
* {@link expandRow}, {@link toggleRowExpansion} and {@link clearExpansion}, which keep the
|
|
9967
|
+
* two in step.
|
|
9904
9968
|
*/
|
|
9905
9969
|
expandedRows: _angular_core.WritableSignal<Set<unknown>>;
|
|
9970
|
+
/**
|
|
9971
|
+
* Every open detail row keyed by {@link expansionKey}, including rows no longer in
|
|
9972
|
+
* `data()`. Empty (and unused) when no key is set. Holds the row objects so a row that
|
|
9973
|
+
* comes back can be re-pointed at the object the new data carries.
|
|
9974
|
+
*/
|
|
9975
|
+
private expandedByKey;
|
|
9906
9976
|
private static instanceCount;
|
|
9907
9977
|
private readonly instanceId;
|
|
9908
9978
|
/**
|
|
@@ -9948,6 +10018,16 @@ declare class TnTableComponent<T = unknown> implements OnInit {
|
|
|
9948
10018
|
/** True when the layout should keep the table but pin edge columns and scroll. */
|
|
9949
10019
|
isScrollMode: Signal<boolean>;
|
|
9950
10020
|
data: Signal<T[]>;
|
|
10021
|
+
/**
|
|
10022
|
+
* The resolved base for each row, by index.
|
|
10023
|
+
*
|
|
10024
|
+
* Computed once per `data()` change rather than called per row per change-detection pass: a
|
|
10025
|
+
* base is usually an array, every call builds a new one, and a new reference restarts the
|
|
10026
|
+
* directive's effect — so binding the call directly would rewrite every row's attribute on
|
|
10027
|
+
* every pass. Recomputing here on the signal the rows are rendered from keeps the value
|
|
10028
|
+
* identical between passes, and correct after a reload hands back new row objects.
|
|
10029
|
+
*/
|
|
10030
|
+
protected readonly rowTestIds: Signal<TnTestIdValue[]>;
|
|
9951
10031
|
effectiveDisplayedColumns: Signal<string[]>;
|
|
9952
10032
|
/**
|
|
9953
10033
|
* Every column the table actually renders, including the trailing actions column, which
|
|
@@ -9999,6 +10079,26 @@ declare class TnTableComponent<T = unknown> implements OnInit {
|
|
|
9999
10079
|
*/
|
|
10000
10080
|
canExpandRow(row: T): boolean;
|
|
10001
10081
|
toggleRowExpansion(row: T): void;
|
|
10082
|
+
/**
|
|
10083
|
+
* Whether `row`'s detail row counts as open for a toggle. With {@link expansionKey} that is
|
|
10084
|
+
* the retained map, which includes rows this page is not showing; without one it is object
|
|
10085
|
+
* identity against the visible set. Distinct from {@link isRowExpanded}, which drives
|
|
10086
|
+
* rendering and must therefore stay about the row in front of the user.
|
|
10087
|
+
*/
|
|
10088
|
+
private isExpansionOpen;
|
|
10089
|
+
/**
|
|
10090
|
+
* Opens `row`'s detail row programmatically — the same thing a chevron click does, for a
|
|
10091
|
+
* consumer restoring expansion from somewhere else (a `?jobId=` query parameter, say).
|
|
10092
|
+
* Honours `singleExpand` and keeps {@link expansionKey}'s retained set in step, which
|
|
10093
|
+
* writing {@link expandedRows} directly does not.
|
|
10094
|
+
*/
|
|
10095
|
+
expandRow(row: T): void;
|
|
10096
|
+
/**
|
|
10097
|
+
* Collapses every detail row, including rows retained under {@link expansionKey} that are
|
|
10098
|
+
* not on screen. `expandedRows.set(new Set())` only closes what is visible, so with a key
|
|
10099
|
+
* set the off-screen rows would re-open on the next reconcile.
|
|
10100
|
+
*/
|
|
10101
|
+
clearExpansion(): void;
|
|
10002
10102
|
isRowExpanded(row: T): boolean;
|
|
10003
10103
|
/**
|
|
10004
10104
|
* Whether the row element itself acts as the expand/collapse control. Requires `clickable` —
|
|
@@ -10226,7 +10326,7 @@ declare class TnTableComponent<T = unknown> implements OnInit {
|
|
|
10226
10326
|
getCardLabel(column: string): string;
|
|
10227
10327
|
getCellValue(row: T, column: string): unknown;
|
|
10228
10328
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<TnTableComponent<any>, never>;
|
|
10229
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<TnTableComponent<any>, "tn-table", never, { "dataSource": { "alias": "dataSource"; "required": false; "isSignal": true; }; "displayedColumns": { "alias": "displayedColumns"; "required": false; "isSignal": true; }; "trackBy": { "alias": "trackBy"; "required": false; "isSignal": true; }; "selectionKey": { "alias": "selectionKey"; "required": false; "isSignal": true; }; "emptyMessage": { "alias": "emptyMessage"; "required": false; "isSignal": true; }; "emptyDescription": { "alias": "emptyDescription"; "required": false; "isSignal": true; }; "emptyIcon": { "alias": "emptyIcon"; "required": false; "isSignal": true; }; "scrollRegionAriaLabel": { "alias": "scrollRegionAriaLabel"; "required": false; "isSignal": true; }; "selectable": { "alias": "selectable"; "required": false; "isSignal": true; }; "expandable": { "alias": "expandable"; "required": false; "isSignal": true; }; "bordered": { "alias": "bordered"; "required": false; "isSignal": true; }; "isRowExpandable": { "alias": "isRowExpandable"; "required": false; "isSignal": true; }; "activeRow": { "alias": "activeRow"; "required": false; "isSignal": true; }; "activeWhen": { "alias": "activeWhen"; "required": false; "isSignal": true; }; "activeBg": { "alias": "activeBg"; "required": false; "isSignal": true; }; "activeIndicator": { "alias": "activeIndicator"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "loadingMessage": { "alias": "loadingMessage"; "required": false; "isSignal": true; }; "clickable": { "alias": "clickable"; "required": false; "isSignal": true; }; "expandOnRowClick": { "alias": "expandOnRowClick"; "required": false; "isSignal": true; }; "singleExpand": { "alias": "singleExpand"; "required": false; "isSignal": true; }; "fixedLayout": { "alias": "fixedLayout"; "required": false; "isSignal": true; }; "minColumnWidth": { "alias": "minColumnWidth"; "required": false; "isSignal": true; }; "minWidth": { "alias": "minWidth"; "required": false; "isSignal": true; }; "mobileLayout": { "alias": "mobileLayout"; "required": false; "isSignal": true; }; "cardBreakpoint": { "alias": "cardBreakpoint"; "required": false; "isSignal": true; }; "cardPrimaryCount": { "alias": "cardPrimaryCount"; "required": false; "isSignal": true; }; "sortColumn": { "alias": "sortColumn"; "required": false; "isSignal": true; }; "sortDirection": { "alias": "sortDirection"; "required": false; "isSignal": true; }; }, { "sortChange": "sortChange"; "selectionChange": "selectionChange"; "rowClick": "rowClick"; "rowDoubleClick": "rowDoubleClick"; "sortColumn": "sortColumnChange"; "sortDirection": "sortDirectionChange"; }, ["columnDefs", "detailRowDef", "rowActionsDef"], never, true, [{ directive: typeof TnTestIdDirective; inputs: { "tnTestId": "testId"; }; outputs: {}; }]>;
|
|
10329
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<TnTableComponent<any>, "tn-table", never, { "dataSource": { "alias": "dataSource"; "required": false; "isSignal": true; }; "displayedColumns": { "alias": "displayedColumns"; "required": false; "isSignal": true; }; "trackBy": { "alias": "trackBy"; "required": false; "isSignal": true; }; "selectionKey": { "alias": "selectionKey"; "required": false; "isSignal": true; }; "expansionKey": { "alias": "expansionKey"; "required": false; "isSignal": true; }; "rowTestId": { "alias": "rowTestId"; "required": false; "isSignal": true; }; "emptyMessage": { "alias": "emptyMessage"; "required": false; "isSignal": true; }; "emptyDescription": { "alias": "emptyDescription"; "required": false; "isSignal": true; }; "emptyIcon": { "alias": "emptyIcon"; "required": false; "isSignal": true; }; "scrollRegionAriaLabel": { "alias": "scrollRegionAriaLabel"; "required": false; "isSignal": true; }; "selectable": { "alias": "selectable"; "required": false; "isSignal": true; }; "expandable": { "alias": "expandable"; "required": false; "isSignal": true; }; "bordered": { "alias": "bordered"; "required": false; "isSignal": true; }; "isRowExpandable": { "alias": "isRowExpandable"; "required": false; "isSignal": true; }; "activeRow": { "alias": "activeRow"; "required": false; "isSignal": true; }; "activeWhen": { "alias": "activeWhen"; "required": false; "isSignal": true; }; "activeBg": { "alias": "activeBg"; "required": false; "isSignal": true; }; "activeIndicator": { "alias": "activeIndicator"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "loadingMessage": { "alias": "loadingMessage"; "required": false; "isSignal": true; }; "clickable": { "alias": "clickable"; "required": false; "isSignal": true; }; "expandOnRowClick": { "alias": "expandOnRowClick"; "required": false; "isSignal": true; }; "singleExpand": { "alias": "singleExpand"; "required": false; "isSignal": true; }; "fixedLayout": { "alias": "fixedLayout"; "required": false; "isSignal": true; }; "minColumnWidth": { "alias": "minColumnWidth"; "required": false; "isSignal": true; }; "minWidth": { "alias": "minWidth"; "required": false; "isSignal": true; }; "mobileLayout": { "alias": "mobileLayout"; "required": false; "isSignal": true; }; "cardBreakpoint": { "alias": "cardBreakpoint"; "required": false; "isSignal": true; }; "cardPrimaryCount": { "alias": "cardPrimaryCount"; "required": false; "isSignal": true; }; "sortColumn": { "alias": "sortColumn"; "required": false; "isSignal": true; }; "sortDirection": { "alias": "sortDirection"; "required": false; "isSignal": true; }; }, { "sortChange": "sortChange"; "selectionChange": "selectionChange"; "rowClick": "rowClick"; "rowDoubleClick": "rowDoubleClick"; "sortColumn": "sortColumnChange"; "sortDirection": "sortDirectionChange"; }, ["columnDefs", "detailRowDef", "rowActionsDef"], never, true, [{ directive: typeof TnTestIdDirective; inputs: { "tnTestId": "testId"; }; outputs: {}; }]>;
|
|
10230
10330
|
}
|
|
10231
10331
|
|
|
10232
10332
|
/**
|
|
@@ -10431,6 +10531,17 @@ declare class TnTableHarness extends ComponentHarness {
|
|
|
10431
10531
|
* @returns Promise resolving to true if the loading overlay is visible.
|
|
10432
10532
|
*/
|
|
10433
10533
|
isLoading(): Promise<boolean>;
|
|
10534
|
+
/**
|
|
10535
|
+
* Gets the test id written on a data row by `[rowTestId]`.
|
|
10536
|
+
*
|
|
10537
|
+
* Layout-aware, like the rest of the row queries: reads the card in the card layout, which
|
|
10538
|
+
* carries the same id. Reads `data-testid` first and falls through to `data-test`, so it
|
|
10539
|
+
* answers the same either way the consumer configured `TN_TEST_ATTR`.
|
|
10540
|
+
*
|
|
10541
|
+
* @param rowIndex Zero-based index of the data row (or card).
|
|
10542
|
+
* @returns Promise resolving to the row's test id, or null when `[rowTestId]` is unset.
|
|
10543
|
+
*/
|
|
10544
|
+
getRowTestId(rowIndex: number): Promise<string | null>;
|
|
10434
10545
|
/**
|
|
10435
10546
|
* Checks if a data row is currently marked active.
|
|
10436
10547
|
*
|