@kronor/dtv 0.2.9 → 0.3.0
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/dist/assets/InterVariable-CWi-zmRD.woff2 +0 -0
- package/dist/assets/InterVariable-Italic-d6KXgdvN.woff2 +0 -0
- package/dist/assets/index-BNgm6iTo.js +2105 -0
- package/dist/assets/index-CKkrV_Rb.css +1 -0
- package/dist/assets/primeicons-C6QP2o4f.woff2 +0 -0
- package/dist/assets/primeicons-DMOk5skT.eot +0 -0
- package/dist/assets/primeicons-Dr5RGzOO.svg +345 -0
- package/dist/assets/primeicons-MpK4pl85.ttf +0 -0
- package/dist/assets/primeicons-WjwUDZjB.woff +0 -0
- package/dist/index.html +17 -0
- package/package.json +5 -1
- package/.editorconfig +0 -12
- package/.github/copilot-instructions.md +0 -64
- package/.github/workflows/ci.yml +0 -51
- package/.husky/pre-commit +0 -8
- package/e2e/app.spec.ts +0 -6
- package/e2e/cell-renderer-setfilterstate.spec.ts +0 -63
- package/e2e/filter-sharing.spec.ts +0 -113
- package/e2e/filter-url-persistence.spec.ts +0 -36
- package/e2e/graphqlMock.ts +0 -144
- package/e2e/multi-field-filters.spec.ts +0 -95
- package/e2e/pagination.spec.ts +0 -38
- package/e2e/payment-request-email-filter.spec.ts +0 -67
- package/e2e/save-filter-splitbutton.spec.ts +0 -68
- package/e2e/simple-view-email-filter.spec.ts +0 -67
- package/e2e/simple-view-transforms.spec.ts +0 -171
- package/e2e/simple-view.spec.ts +0 -104
- package/e2e/transform-regression.spec.ts +0 -108
- package/eslint.config.js +0 -30
- package/index.html +0 -17
- package/jest.config.js +0 -10
- package/playwright.config.ts +0 -54
- package/src/App.externalRuntime.test.ts +0 -190
- package/src/App.tsx +0 -540
- package/src/assets/react.svg +0 -1
- package/src/components/AIAssistantForm.tsx +0 -241
- package/src/components/FilterForm.test.ts +0 -82
- package/src/components/FilterForm.tsx +0 -375
- package/src/components/PhoneNumberFilter.tsx +0 -102
- package/src/components/SavedFilterList.tsx +0 -181
- package/src/components/SpeechInput.tsx +0 -67
- package/src/components/Table.tsx +0 -119
- package/src/components/TablePagination.tsx +0 -40
- package/src/components/aiAssistant.test.ts +0 -270
- package/src/components/aiAssistant.ts +0 -291
- package/src/framework/cell-renderer-components/CurrencyAmount.tsx +0 -30
- package/src/framework/cell-renderer-components/LayoutHelpers.tsx +0 -74
- package/src/framework/cell-renderer-components/Link.tsx +0 -28
- package/src/framework/cell-renderer-components/Mapping.tsx +0 -11
- package/src/framework/cell-renderer-components.test.ts +0 -353
- package/src/framework/column-definition.tsx +0 -85
- package/src/framework/currency.test.ts +0 -46
- package/src/framework/currency.ts +0 -62
- package/src/framework/data.staticConditions.test.ts +0 -46
- package/src/framework/data.test.ts +0 -167
- package/src/framework/data.ts +0 -162
- package/src/framework/filter-form-state.test.ts +0 -189
- package/src/framework/filter-form-state.ts +0 -185
- package/src/framework/filter-sharing.test.ts +0 -135
- package/src/framework/filter-sharing.ts +0 -118
- package/src/framework/filters.ts +0 -194
- package/src/framework/graphql.buildHasuraConditions.test.ts +0 -473
- package/src/framework/graphql.paginationKey.test.ts +0 -29
- package/src/framework/graphql.test.ts +0 -286
- package/src/framework/graphql.ts +0 -462
- package/src/framework/native-runtime/index.tsx +0 -33
- package/src/framework/native-runtime/nativeComponents.test.ts +0 -108
- package/src/framework/runtime-reference.test.ts +0 -172
- package/src/framework/runtime.ts +0 -15
- package/src/framework/saved-filters.test.ts +0 -422
- package/src/framework/saved-filters.ts +0 -293
- package/src/framework/state.test.ts +0 -86
- package/src/framework/state.ts +0 -148
- package/src/framework/transform.test.ts +0 -51
- package/src/framework/view-parser-initialvalues.test.ts +0 -228
- package/src/framework/view-parser.ts +0 -714
- package/src/framework/view.test.ts +0 -1805
- package/src/framework/view.ts +0 -38
- package/src/index.css +0 -6
- package/src/main.tsx +0 -99
- package/src/views/index.ts +0 -12
- package/src/views/payment-requests/components/NoRowsExtendDateRange.tsx +0 -37
- package/src/views/payment-requests/components/PaymentMethod.tsx +0 -184
- package/src/views/payment-requests/components/PaymentStatusTag.tsx +0 -61
- package/src/views/payment-requests/index.ts +0 -1
- package/src/views/payment-requests/runtime.tsx +0 -145
- package/src/views/payment-requests/view.json +0 -692
- package/src/views/payment-requests-initial-values.test.ts +0 -73
- package/src/views/request-log/index.ts +0 -2
- package/src/views/request-log/runtime.tsx +0 -47
- package/src/views/request-log/view.json +0 -123
- package/src/views/simple-test-view/index.ts +0 -3
- package/src/views/simple-test-view/runtime.tsx +0 -85
- package/src/views/simple-test-view/view.json +0 -191
- package/src/vite-env.d.ts +0 -1
- package/tailwind.config.js +0 -7
- package/tsconfig.app.json +0 -26
- package/tsconfig.jest.json +0 -6
- package/tsconfig.json +0 -7
- package/tsconfig.node.json +0 -24
- package/vite.config.ts +0 -11
- /package/{public → dist}/vite.svg +0 -0
package/e2e/pagination.spec.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { test, expect } from '@playwright/test';
|
|
2
|
-
import { mockPaginationGraphQL } from './graphqlMock';
|
|
3
|
-
|
|
4
|
-
const APP_URL = 'http://localhost:5173/?test-view=simple-test-view';
|
|
5
|
-
const nextButton = '[data-testid="pagination-next"]';
|
|
6
|
-
const prevButton = '[data-testid="pagination-prev"]';
|
|
7
|
-
const pageIndicator = '[data-testid="pagination-page"]';
|
|
8
|
-
const tableRows = 'table tbody tr';
|
|
9
|
-
|
|
10
|
-
test.describe('Simple View Pagination', () => {
|
|
11
|
-
test.beforeEach(async ({ page }) => {
|
|
12
|
-
await page.route('**/graphql', mockPaginationGraphQL);
|
|
13
|
-
await page.goto(APP_URL);
|
|
14
|
-
await page.waitForSelector(tableRows);
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
test('shows first page and disables previous button', async ({ page }) => {
|
|
18
|
-
await expect(page.locator(pageIndicator)).toHaveText('1-20');
|
|
19
|
-
await expect(page.locator(prevButton)).toBeDisabled();
|
|
20
|
-
const rowCount = await page.locator(tableRows).count();
|
|
21
|
-
expect(rowCount).toBe(20);
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
test('can go to next and previous page', async ({ page }) => {
|
|
25
|
-
await page.click(nextButton);
|
|
26
|
-
await expect(page.locator(pageIndicator)).toHaveText('21-30');
|
|
27
|
-
await expect(page.locator(prevButton)).toBeEnabled();
|
|
28
|
-
await page.click(prevButton);
|
|
29
|
-
await expect(page.locator(pageIndicator)).toHaveText('1-20');
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
test('next button disables on last page', async ({ page }) => {
|
|
33
|
-
await page.click(nextButton); // to 2nd page
|
|
34
|
-
await expect(page.locator(pageIndicator)).toHaveText('21-30');
|
|
35
|
-
await expect(page.locator(tableRows)).toHaveCount(10);
|
|
36
|
-
await expect(page.locator(nextButton)).toBeDisabled();
|
|
37
|
-
});
|
|
38
|
-
});
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { test, expect } from '@playwright/test';
|
|
2
|
-
import { mockPaginationGraphQL } from './graphqlMock';
|
|
3
|
-
|
|
4
|
-
test.describe('Simple View Email Filter', () => {
|
|
5
|
-
test('should set email filter when clicking on email', async ({ page }) => {
|
|
6
|
-
// Intercept the GraphQL request and mock the response
|
|
7
|
-
await page.route('**/v1/graphql', mockPaginationGraphQL);
|
|
8
|
-
|
|
9
|
-
// Navigate to the simple test view
|
|
10
|
-
await page.goto('/?test-view=simple-test-view');
|
|
11
|
-
|
|
12
|
-
// Wait for the table to be present and visible
|
|
13
|
-
const table = page.getByRole('table');
|
|
14
|
-
await expect(table).toBeVisible();
|
|
15
|
-
|
|
16
|
-
// Verify that the table headers are rendered correctly
|
|
17
|
-
await expect(table.getByText('Test Column Header')).toBeVisible();
|
|
18
|
-
await expect(table.getByText('Email')).toBeVisible();
|
|
19
|
-
|
|
20
|
-
// Find the first email button in the Email column
|
|
21
|
-
const firstEmailButton = table.locator('td button').filter({ hasText: '@' }).first();
|
|
22
|
-
await expect(firstEmailButton).toBeVisible();
|
|
23
|
-
|
|
24
|
-
// Verify the button has the expected styling classes
|
|
25
|
-
await expect(firstEmailButton).toHaveClass(/text-blue-500/);
|
|
26
|
-
await expect(firstEmailButton).toHaveClass(/underline/);
|
|
27
|
-
|
|
28
|
-
// Get the email text before clicking
|
|
29
|
-
const emailText = await firstEmailButton.textContent();
|
|
30
|
-
expect(emailText).toMatch(/@/);
|
|
31
|
-
expect(emailText).toBeTruthy(); // Ensure it's not null
|
|
32
|
-
|
|
33
|
-
// Click the email button
|
|
34
|
-
await firstEmailButton.click();
|
|
35
|
-
|
|
36
|
-
// Show filters to see the filter form
|
|
37
|
-
await page.getByText('Filters', { exact: true }).click();
|
|
38
|
-
|
|
39
|
-
// Verify that the Email filter is now populated with the clicked email
|
|
40
|
-
const emailFilterInput = page.getByText('Email', { exact: true }).locator('..').locator('~ div input');
|
|
41
|
-
await expect(emailFilterInput).toHaveValue(emailText!);
|
|
42
|
-
|
|
43
|
-
// Verify that the table now shows only rows with that email (should be just 1 row)
|
|
44
|
-
const emailButtons = table.locator('td button').filter({ hasText: emailText! });
|
|
45
|
-
await expect(emailButtons).toHaveCount(1);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
test('should show tooltip on email hover', async ({ page }) => {
|
|
49
|
-
// Intercept the GraphQL request and mock the response
|
|
50
|
-
await page.route('**/v1/graphql', mockPaginationGraphQL);
|
|
51
|
-
|
|
52
|
-
// Navigate to the simple test view
|
|
53
|
-
await page.goto('/?test-view=simple-test-view');
|
|
54
|
-
|
|
55
|
-
// Wait for the table to be present and visible
|
|
56
|
-
const table = page.getByRole('table');
|
|
57
|
-
await expect(table).toBeVisible();
|
|
58
|
-
|
|
59
|
-
// Find the first email button
|
|
60
|
-
const emailButton = table.locator('td button').filter({ hasText: '@' }).first();
|
|
61
|
-
await expect(emailButton).toBeVisible();
|
|
62
|
-
|
|
63
|
-
// Check for title attribute (tooltip)
|
|
64
|
-
const title = await emailButton.getAttribute('title');
|
|
65
|
-
expect(title).toMatch(/Filter by email:/);
|
|
66
|
-
});
|
|
67
|
-
});
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import { test, expect } from '@playwright/test';
|
|
2
|
-
import { mockPaginationGraphQL } from './graphqlMock';
|
|
3
|
-
|
|
4
|
-
test.describe('Save Filter SplitButton', () => {
|
|
5
|
-
test.beforeEach(async ({ page }) => {
|
|
6
|
-
// Set up GraphQL mock
|
|
7
|
-
await page.route('**/v1/graphql', mockPaginationGraphQL);
|
|
8
|
-
|
|
9
|
-
// Navigate to the app
|
|
10
|
-
await page.goto('/?test-view=simple-test-view');
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
test('should render SplitButton for save filter', async ({ page }) => {
|
|
14
|
-
// Show filters
|
|
15
|
-
await page.getByText('Filters', { exact: true }).click();
|
|
16
|
-
|
|
17
|
-
// Look for the Save Filter SplitButton
|
|
18
|
-
const saveFilterButton = page.locator('.p-splitbutton').filter({ hasText: 'Save Filter' });
|
|
19
|
-
await expect(saveFilterButton).toBeVisible();
|
|
20
|
-
|
|
21
|
-
// Verify the main button text
|
|
22
|
-
const mainButton = saveFilterButton.locator('.p-splitbutton-defaultbutton');
|
|
23
|
-
await expect(mainButton).toContainText('Save Filter');
|
|
24
|
-
|
|
25
|
-
// Verify the dropdown exists
|
|
26
|
-
const dropdownButton = saveFilterButton.locator('.p-splitbutton-menubutton');
|
|
27
|
-
await expect(dropdownButton).toBeVisible();
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
test('should open dropdown menu when arrow is clicked', async ({ page }) => {
|
|
31
|
-
// Show filters
|
|
32
|
-
await page.getByText('Filters', { exact: true }).click();
|
|
33
|
-
|
|
34
|
-
// Find the SplitButton
|
|
35
|
-
const saveFilterButton = page.locator('.p-splitbutton').filter({ hasText: 'Save Filter' });
|
|
36
|
-
await expect(saveFilterButton).toBeVisible();
|
|
37
|
-
|
|
38
|
-
// Click the dropdown arrow
|
|
39
|
-
const dropdownButton = saveFilterButton.locator('.p-splitbutton-menubutton');
|
|
40
|
-
await dropdownButton.click();
|
|
41
|
-
|
|
42
|
-
// Should see a menu appear (even if empty)
|
|
43
|
-
const menu = page.locator('.p-menu', { hasText: /Update/ }).or(page.locator('.p-menu'));
|
|
44
|
-
await expect(menu.first()).toBeVisible();
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
test('main button click should trigger save dialog', async ({ page }) => {
|
|
48
|
-
// Show filters
|
|
49
|
-
await page.getByText('Filters', { exact: true }).click();
|
|
50
|
-
|
|
51
|
-
// Set up dialog handler to verify it's triggered
|
|
52
|
-
let dialogTriggered = false;
|
|
53
|
-
page.on('dialog', async dialog => {
|
|
54
|
-
expect(dialog.type()).toBe('prompt');
|
|
55
|
-
expect(dialog.message()).toBe('Enter a name for this filter:');
|
|
56
|
-
dialogTriggered = true;
|
|
57
|
-
await dialog.dismiss(); // Just dismiss to avoid actually saving
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
// Click the main save button
|
|
61
|
-
const saveFilterButton = page.locator('.p-splitbutton').filter({ hasText: 'Save Filter' });
|
|
62
|
-
await saveFilterButton.locator('.p-splitbutton-defaultbutton').click();
|
|
63
|
-
|
|
64
|
-
// Verify dialog was triggered
|
|
65
|
-
await page.waitForTimeout(500);
|
|
66
|
-
expect(dialogTriggered).toBe(true);
|
|
67
|
-
});
|
|
68
|
-
});
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { test, expect } from '@playwright/test';
|
|
2
|
-
import { mockPaginationGraphQL } from './graphqlMock';
|
|
3
|
-
|
|
4
|
-
test.describe('Simple View Email Filter', () => {
|
|
5
|
-
test('should set email filter when clicking on email', async ({ page }) => {
|
|
6
|
-
// Intercept the GraphQL request and mock the response
|
|
7
|
-
await page.route('**/v1/graphql', mockPaginationGraphQL);
|
|
8
|
-
|
|
9
|
-
// Navigate to the simple test view
|
|
10
|
-
await page.goto('/?test-view=simple-test-view');
|
|
11
|
-
|
|
12
|
-
// Wait for the table to be present and visible
|
|
13
|
-
const table = page.getByRole('table');
|
|
14
|
-
await expect(table).toBeVisible();
|
|
15
|
-
|
|
16
|
-
// Verify that the table headers are rendered correctly
|
|
17
|
-
await expect(table.getByText('Test Column Header')).toBeVisible();
|
|
18
|
-
await expect(table.getByText('Email')).toBeVisible();
|
|
19
|
-
|
|
20
|
-
// Find the first email button in the Email column
|
|
21
|
-
const firstEmailButton = table.locator('td button').filter({ hasText: '@' }).first();
|
|
22
|
-
await expect(firstEmailButton).toBeVisible();
|
|
23
|
-
|
|
24
|
-
// Verify the button has the expected styling classes
|
|
25
|
-
await expect(firstEmailButton).toHaveClass(/text-blue-500/);
|
|
26
|
-
await expect(firstEmailButton).toHaveClass(/underline/);
|
|
27
|
-
|
|
28
|
-
// Get the email text before clicking
|
|
29
|
-
const emailText = await firstEmailButton.textContent();
|
|
30
|
-
expect(emailText).toMatch(/@/);
|
|
31
|
-
expect(emailText).toBeTruthy(); // Ensure it's not null
|
|
32
|
-
|
|
33
|
-
// Click the email button
|
|
34
|
-
await firstEmailButton.click();
|
|
35
|
-
|
|
36
|
-
// Show filters to see the filter form
|
|
37
|
-
await page.getByText('Filters', { exact: true }).click();
|
|
38
|
-
|
|
39
|
-
// Verify that the Email filter is now populated with the clicked email
|
|
40
|
-
const emailFilterInput = page.getByText('Email', { exact: true }).locator('..').locator('~ div input');
|
|
41
|
-
await expect(emailFilterInput).toHaveValue(emailText!);
|
|
42
|
-
|
|
43
|
-
// Verify that the table now shows only rows with that email (should be just 1 row)
|
|
44
|
-
const emailButtons = table.locator('td button').filter({ hasText: emailText! });
|
|
45
|
-
await expect(emailButtons).toHaveCount(1);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
test('should show tooltip on email hover', async ({ page }) => {
|
|
49
|
-
// Intercept the GraphQL request and mock the response
|
|
50
|
-
await page.route('**/v1/graphql', mockPaginationGraphQL);
|
|
51
|
-
|
|
52
|
-
// Navigate to the simple test view
|
|
53
|
-
await page.goto('/?test-view=simple-test-view');
|
|
54
|
-
|
|
55
|
-
// Wait for the table to be present and visible
|
|
56
|
-
const table = page.getByRole('table');
|
|
57
|
-
await expect(table).toBeVisible();
|
|
58
|
-
|
|
59
|
-
// Find the first email button
|
|
60
|
-
const emailButton = table.locator('td button').filter({ hasText: '@' }).first();
|
|
61
|
-
await expect(emailButton).toBeVisible();
|
|
62
|
-
|
|
63
|
-
// Check for title attribute (tooltip)
|
|
64
|
-
const title = await emailButton.getAttribute('title');
|
|
65
|
-
expect(title).toMatch(/Filter by email:/);
|
|
66
|
-
});
|
|
67
|
-
});
|
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
import { test, expect } from '@playwright/test';
|
|
2
|
-
import { mockPaginationGraphQL } from './graphqlMock';
|
|
3
|
-
|
|
4
|
-
test.describe('Simple View Transform Functionality', () => {
|
|
5
|
-
|
|
6
|
-
test('should apply transform functions when filtering by amount', async ({ page }) => {
|
|
7
|
-
// Intercept the GraphQL request and mock the response
|
|
8
|
-
await page.route('**/v1/graphql', mockPaginationGraphQL);
|
|
9
|
-
|
|
10
|
-
// Navigate to the page with the simple test view
|
|
11
|
-
await page.goto('/?test-view=simple-test-view');
|
|
12
|
-
|
|
13
|
-
// Wait for the table to be present and visible
|
|
14
|
-
const table = page.getByRole('table');
|
|
15
|
-
await expect(table).toBeVisible();
|
|
16
|
-
|
|
17
|
-
// Verify all rows are initially visible
|
|
18
|
-
await expect(table.getByText('Test 30', { exact: true })).toBeVisible();
|
|
19
|
-
await expect(table.getByText('Test 29', { exact: true })).toBeVisible();
|
|
20
|
-
await expect(table.getByText('Test 28', { exact: true })).toBeVisible();
|
|
21
|
-
await expect(table.getByText('Test 27', { exact: true })).toBeVisible();
|
|
22
|
-
await expect(table.getByText('Test 26', { exact: true })).toBeVisible();
|
|
23
|
-
await expect(table.getByText('Test 25', { exact: true })).toBeVisible();
|
|
24
|
-
await expect(table.getByText('$300', { exact: true })).toBeVisible(); // amount for Test 30
|
|
25
|
-
await expect(table.getByText('$290', { exact: true })).toBeVisible(); // amount for Test 29
|
|
26
|
-
await expect(table.getByText('$280', { exact: true })).toBeVisible(); // amount for Test 28
|
|
27
|
-
await expect(table.getByText('$270', { exact: true })).toBeVisible(); // amount for Test 27
|
|
28
|
-
await expect(table.getByText('$260', { exact: true })).toBeVisible(); // amount for Test 26
|
|
29
|
-
await expect(table.getByText('$250', { exact: true })).toBeVisible(); // amount for Test 25
|
|
30
|
-
|
|
31
|
-
// Show filters first
|
|
32
|
-
await page.getByText('Filters', { exact: true }).click();
|
|
33
|
-
|
|
34
|
-
// Find the amount filter input
|
|
35
|
-
const amountLabel = page.getByText('Amount', { exact: true });
|
|
36
|
-
const amountInput = amountLabel.locator('..').locator('~ div input');
|
|
37
|
-
|
|
38
|
-
// Enter 255 in the input field
|
|
39
|
-
// With transform: toQuery adds 5, so 255 becomes 260 in the query
|
|
40
|
-
// This should show only rows with amount >= 260 (Test 26, 27, 28, 29, 30)
|
|
41
|
-
await amountInput.fill('255');
|
|
42
|
-
await amountInput.press('Enter');
|
|
43
|
-
|
|
44
|
-
// Wait for filtering to complete and verify results
|
|
45
|
-
// These should still be visible (amount >= 260)
|
|
46
|
-
await expect(table.getByText('Test 30', { exact: true })).toBeVisible();
|
|
47
|
-
await expect(table.getByText('Test 29', { exact: true })).toBeVisible();
|
|
48
|
-
await expect(table.getByText('Test 28', { exact: true })).toBeVisible();
|
|
49
|
-
await expect(table.getByText('Test 27', { exact: true })).toBeVisible();
|
|
50
|
-
await expect(table.getByText('Test 26', { exact: true })).toBeVisible();
|
|
51
|
-
await expect(table.getByText('$300', { exact: true })).toBeVisible();
|
|
52
|
-
await expect(table.getByText('$290', { exact: true })).toBeVisible();
|
|
53
|
-
await expect(table.getByText('$280', { exact: true })).toBeVisible();
|
|
54
|
-
await expect(table.getByText('$270', { exact: true })).toBeVisible();
|
|
55
|
-
await expect(table.getByText('$260', { exact: true })).toBeVisible();
|
|
56
|
-
|
|
57
|
-
// These should not be visible (amount < 260)
|
|
58
|
-
await expect(table.getByText('Test 25', { exact: true })).not.toBeVisible();
|
|
59
|
-
await expect(table.getByText('Test 24', { exact: true })).not.toBeVisible();
|
|
60
|
-
await expect(table.getByText('Test 23', { exact: true })).not.toBeVisible();
|
|
61
|
-
await expect(table.getByText('$250', { exact: true })).not.toBeVisible();
|
|
62
|
-
await expect(table.getByText('$240', { exact: true })).not.toBeVisible();
|
|
63
|
-
await expect(table.getByText('$230', { exact: true })).not.toBeVisible();
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
test('should handle multiple filter value changes with transforms', async ({ page }) => {
|
|
67
|
-
// Intercept the GraphQL request and mock the response
|
|
68
|
-
await page.route('**/v1/graphql', mockPaginationGraphQL);
|
|
69
|
-
|
|
70
|
-
// Navigate to the page with the simple test view
|
|
71
|
-
await page.goto('/?test-view=simple-test-view');
|
|
72
|
-
|
|
73
|
-
// Wait for the table to be present and visible
|
|
74
|
-
const table = page.getByRole('table');
|
|
75
|
-
await expect(table).toBeVisible();
|
|
76
|
-
|
|
77
|
-
// Show filters first
|
|
78
|
-
await page.getByText('Filters', { exact: true }).click();
|
|
79
|
-
|
|
80
|
-
// Find the amount filter input
|
|
81
|
-
const amountLabel = page.getByText('Amount', { exact: true });
|
|
82
|
-
const amountInput = amountLabel.locator('..').locator('~ div input');
|
|
83
|
-
|
|
84
|
-
// Test 1: Enter 245 (transforms to 250), should show Test 25 and up
|
|
85
|
-
await amountInput.fill('245');
|
|
86
|
-
await amountInput.press('Enter');
|
|
87
|
-
|
|
88
|
-
await expect(table.getByText('Test 30', { exact: true })).toBeVisible();
|
|
89
|
-
await expect(table.getByText('Test 25', { exact: true })).toBeVisible();
|
|
90
|
-
await expect(table.getByText('Test 24', { exact: true })).not.toBeVisible();
|
|
91
|
-
|
|
92
|
-
// Test 2: Change to 265 (transforms to 270), should show Test 27 and up
|
|
93
|
-
await amountInput.clear();
|
|
94
|
-
await amountInput.fill('265');
|
|
95
|
-
await amountInput.press('Enter');
|
|
96
|
-
|
|
97
|
-
await expect(table.getByText('Test 30', { exact: true })).toBeVisible();
|
|
98
|
-
await expect(table.getByText('Test 27', { exact: true })).toBeVisible();
|
|
99
|
-
await expect(table.getByText('Test 26', { exact: true })).not.toBeVisible();
|
|
100
|
-
await expect(table.getByText('Test 25', { exact: true })).not.toBeVisible();
|
|
101
|
-
|
|
102
|
-
// Test 3: Clear filter should show all items again
|
|
103
|
-
await amountInput.clear();
|
|
104
|
-
await amountInput.press('Enter');
|
|
105
|
-
|
|
106
|
-
await expect(table.getByText('Test 30', { exact: true })).toBeVisible();
|
|
107
|
-
await expect(table.getByText('Test 25', { exact: true })).toBeVisible();
|
|
108
|
-
await expect(table.getByText('Test 24', { exact: true })).toBeVisible();
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
test('should handle key-value transform objects', async ({ page }) => {
|
|
112
|
-
// Intercept the GraphQL request and mock the response
|
|
113
|
-
await page.route('**/v1/graphql', mockPaginationGraphQL);
|
|
114
|
-
|
|
115
|
-
// Navigate to the page with the simple test view
|
|
116
|
-
await page.goto('/?test-view=simple-test-view');
|
|
117
|
-
|
|
118
|
-
// Wait for the table to be present and visible
|
|
119
|
-
const table = page.getByRole('table');
|
|
120
|
-
await expect(table).toBeVisible();
|
|
121
|
-
|
|
122
|
-
// Verify all rows are initially visible
|
|
123
|
-
await expect(table.getByText('Test 30', { exact: true })).toBeVisible();
|
|
124
|
-
await expect(table.getByText('Test 29', { exact: true })).toBeVisible();
|
|
125
|
-
|
|
126
|
-
// Show filters first
|
|
127
|
-
await page.getByText('Filters', { exact: true }).click();
|
|
128
|
-
|
|
129
|
-
// Find the extra filters panel
|
|
130
|
-
const extraFiltersPanel = page.locator('.p-panel-header', { hasText: 'Extra Filters' });
|
|
131
|
-
await expect(extraFiltersPanel).toBeVisible();
|
|
132
|
-
|
|
133
|
-
// Expand the extra filters panel if needed
|
|
134
|
-
if (await extraFiltersPanel.getAttribute('aria-expanded') !== 'true') {
|
|
135
|
-
await extraFiltersPanel.click();
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// Find the key-value transform filter input
|
|
139
|
-
const keyValueLabel = page.getByText('Test Field (Key-Value Transform)', { exact: true });
|
|
140
|
-
await expect(keyValueLabel).toBeVisible();
|
|
141
|
-
|
|
142
|
-
const keyValueInput = keyValueLabel.locator('..').locator('~ div input');
|
|
143
|
-
await expect(keyValueInput).toBeVisible();
|
|
144
|
-
|
|
145
|
-
// Test 1: Enter a value that should be transformed
|
|
146
|
-
// The transform should add "prefix_" to the input and change the field to "transformedField"
|
|
147
|
-
await keyValueInput.fill('30');
|
|
148
|
-
await keyValueInput.press('Enter');
|
|
149
|
-
|
|
150
|
-
// Wait a bit for the filter to apply
|
|
151
|
-
await page.waitForTimeout(2000);
|
|
152
|
-
|
|
153
|
-
// Verify the correct row is shown (Test 30 should be visible since it matches the transformed query)
|
|
154
|
-
await expect(table.getByText('Test 30', { exact: true })).toBeVisible();
|
|
155
|
-
// Verify other rows are hidden
|
|
156
|
-
await expect(table.getByText('Test 29', { exact: true })).not.toBeVisible();
|
|
157
|
-
|
|
158
|
-
// Test 2: Clear the filter to verify all rows show again
|
|
159
|
-
await keyValueInput.clear();
|
|
160
|
-
await keyValueInput.press('Enter');
|
|
161
|
-
|
|
162
|
-
// Wait for the filter to clear
|
|
163
|
-
await page.waitForTimeout(1000);
|
|
164
|
-
|
|
165
|
-
// All rows should be visible again
|
|
166
|
-
await expect(table.getByText('Test 30', { exact: true })).toBeVisible();
|
|
167
|
-
await expect(table.getByText('Test 29', { exact: true })).toBeVisible();
|
|
168
|
-
await expect(table.getByText('Test 28', { exact: true })).toBeVisible();
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
});
|
package/e2e/simple-view.spec.ts
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import { test, expect } from '@playwright/test';
|
|
2
|
-
import { mockPaginationGraphQL } from './graphqlMock';
|
|
3
|
-
|
|
4
|
-
test.describe('Simple View Rendering', () => {
|
|
5
|
-
|
|
6
|
-
test('should filter by phone using a custom filter component', async ({ page }) => {
|
|
7
|
-
// Intercept the GraphQL request and mock the response
|
|
8
|
-
await page.route('**/v1/graphql', mockPaginationGraphQL);
|
|
9
|
-
|
|
10
|
-
// Navigate to the page with the simple test view
|
|
11
|
-
await page.goto('/?test-view=simple-test-view');
|
|
12
|
-
|
|
13
|
-
// Wait for the table to be present and visible
|
|
14
|
-
const table = page.getByRole('table');
|
|
15
|
-
await expect(table).toBeVisible();
|
|
16
|
-
|
|
17
|
-
// Show filters first
|
|
18
|
-
await page.getByText('Filters', { exact: true }).click();
|
|
19
|
-
|
|
20
|
-
// Find the phone filter input (by placeholder or input type)
|
|
21
|
-
const phoneInput = page.locator('input[placeholder="Phone number"]');
|
|
22
|
-
|
|
23
|
-
const phoneNumber = '+46700000025';
|
|
24
|
-
await phoneInput.fill(phoneNumber);
|
|
25
|
-
|
|
26
|
-
// Submit the filter form (by aria-label)
|
|
27
|
-
await page.getByLabel('Apply filter').click();
|
|
28
|
-
|
|
29
|
-
// Wait for the table to update and check that results are filtered
|
|
30
|
-
await expect(table.getByText(phoneNumber)).toBeVisible();
|
|
31
|
-
});
|
|
32
|
-
test('should render a view with a single column header and data', async ({ page }) => {
|
|
33
|
-
// Intercept the GraphQL request and mock the response
|
|
34
|
-
await page.route('**/v1/graphql', mockPaginationGraphQL);
|
|
35
|
-
|
|
36
|
-
// Navigate to the page with the simple test view
|
|
37
|
-
await page.goto('/?test-view=simple-test-view');
|
|
38
|
-
|
|
39
|
-
// Wait for the table to be present and visible
|
|
40
|
-
const table = page.getByRole('table');
|
|
41
|
-
await expect(table).toBeVisible();
|
|
42
|
-
|
|
43
|
-
// Get the expected header text from the simple test view JSON (first column name)
|
|
44
|
-
const expectedHeaderText = "Test Column Header";
|
|
45
|
-
|
|
46
|
-
// Locate the column header by its text content
|
|
47
|
-
const columnHeader = table.getByText(expectedHeaderText, { exact: true });
|
|
48
|
-
|
|
49
|
-
// Assert that the column header is visible
|
|
50
|
-
await expect(columnHeader).toBeVisible();
|
|
51
|
-
|
|
52
|
-
// Assert that all rows are visible before applying the filter
|
|
53
|
-
await expect(table.getByText('Test 30', { exact: true })).toBeVisible();
|
|
54
|
-
await expect(table.getByText('Test 29', { exact: true })).toBeVisible();
|
|
55
|
-
await expect(table.getByText('Test 28', { exact: true })).toBeVisible();
|
|
56
|
-
await expect(table.getByText('Test 27', { exact: true })).toBeVisible();
|
|
57
|
-
await expect(table.getByText('Test 25', { exact: true })).toBeVisible();
|
|
58
|
-
await expect(table.getByText('Test 24', { exact: true })).toBeVisible();
|
|
59
|
-
await expect(table.getByText('$300', { exact: true })).toBeVisible();
|
|
60
|
-
await expect(table.getByText('$290', { exact: true })).toBeVisible();
|
|
61
|
-
await expect(table.getByText('$280', { exact: true })).toBeVisible();
|
|
62
|
-
await expect(table.getByText('$270', { exact: true })).toBeVisible();
|
|
63
|
-
await expect(table.getByText('$250', { exact: true })).toBeVisible();
|
|
64
|
-
await expect(table.getByText('$240', { exact: true })).toBeVisible();
|
|
65
|
-
|
|
66
|
-
// Show filters first
|
|
67
|
-
await page.getByText('Filters', { exact: true }).click();
|
|
68
|
-
|
|
69
|
-
// Use the filter to only show rows with amount >= 30
|
|
70
|
-
// Find the Amount label, then its parent, then the sibling div, then the input inside
|
|
71
|
-
const amountLabel = page.getByText('Amount', { exact: true });
|
|
72
|
-
const amountInput = amountLabel.locator('..').locator('~ div input');
|
|
73
|
-
await amountInput.fill('260');
|
|
74
|
-
await amountInput.press('Enter');
|
|
75
|
-
|
|
76
|
-
// Assert that only the filtered rows are visible
|
|
77
|
-
await expect(table.getByText('Test 30', { exact: true })).toBeVisible();
|
|
78
|
-
await expect(table.getByText('Test 27', { exact: true })).toBeVisible();
|
|
79
|
-
await expect(table.getByText('Test 25', { exact: true })).not.toBeVisible();
|
|
80
|
-
await expect(table.getByText('Test 24', { exact: true })).not.toBeVisible();
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
test('should render filter group captions in the filter form', async ({ page }) => {
|
|
84
|
-
// Intercept the GraphQL request and mock the response
|
|
85
|
-
await page.route('**/v1/graphql', mockPaginationGraphQL);
|
|
86
|
-
|
|
87
|
-
// Navigate to the page with the simple test view
|
|
88
|
-
await page.goto('/?test-view=simple-test-view');
|
|
89
|
-
|
|
90
|
-
// Show filters first
|
|
91
|
-
await page.getByText('Filters', { exact: true }).click();
|
|
92
|
-
|
|
93
|
-
// Wait for the filter form to be present
|
|
94
|
-
const filterForm = page.locator('form');
|
|
95
|
-
await expect(filterForm).toBeVisible();
|
|
96
|
-
|
|
97
|
-
// Check for the presence of the new group label ("Extra Filters") as a Panel header
|
|
98
|
-
const extraFiltersPanel = page.locator('.p-panel-header', { hasText: 'Extra Filters' });
|
|
99
|
-
await expect(extraFiltersPanel).toBeVisible();
|
|
100
|
-
|
|
101
|
-
// Check that the filter label is present under the new group
|
|
102
|
-
await expect(page.getByText('Test Field', { exact: true })).toBeVisible();
|
|
103
|
-
});
|
|
104
|
-
});
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import { test, expect } from '@playwright/test';
|
|
2
|
-
import { mockPaginationGraphQL } from './graphqlMock';
|
|
3
|
-
|
|
4
|
-
test.describe('Transform Regression Tests', () => {
|
|
5
|
-
|
|
6
|
-
test('should preserve display value after applying transform', async ({ page }) => {
|
|
7
|
-
// Intercept the GraphQL request and mock the response
|
|
8
|
-
await page.route('**/v1/graphql', mockPaginationGraphQL);
|
|
9
|
-
|
|
10
|
-
// Navigate to the page with the simple test view
|
|
11
|
-
await page.goto('/?test-view=simple-test-view');
|
|
12
|
-
|
|
13
|
-
// Wait for the table to be present and visible
|
|
14
|
-
const table = page.getByRole('table');
|
|
15
|
-
await expect(table).toBeVisible();
|
|
16
|
-
|
|
17
|
-
// Show filters first
|
|
18
|
-
await page.getByText('Filters', { exact: true }).click();
|
|
19
|
-
|
|
20
|
-
// Find the amount filter input
|
|
21
|
-
const amountLabel = page.getByText('Amount', { exact: true });
|
|
22
|
-
const amountInput = amountLabel.locator('..').locator('~ div input');
|
|
23
|
-
|
|
24
|
-
// Enter 255 in the input field
|
|
25
|
-
// With transform: toQuery adds 5, so 255 becomes 260 in the query
|
|
26
|
-
// Display should remain 255 (the user's input)
|
|
27
|
-
await amountInput.fill('255');
|
|
28
|
-
|
|
29
|
-
// Apply the filter
|
|
30
|
-
await page.getByRole('button', { name: 'Apply filter' }).click();
|
|
31
|
-
|
|
32
|
-
// Wait for the filter to be applied
|
|
33
|
-
await page.waitForTimeout(100);
|
|
34
|
-
|
|
35
|
-
// Check that the input still shows the original value (255) after applying the transform
|
|
36
|
-
// This is the regression test - it should show the original user input
|
|
37
|
-
await expect(amountInput).toHaveValue('255');
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
test('should correctly apply toQuery transforms', async ({ page }) => {
|
|
41
|
-
// Intercept the GraphQL request and mock the response
|
|
42
|
-
await page.route('**/v1/graphql', mockPaginationGraphQL);
|
|
43
|
-
|
|
44
|
-
// Navigate to the page with the simple test view
|
|
45
|
-
await page.goto('/?test-view=simple-test-view');
|
|
46
|
-
|
|
47
|
-
// Wait for the table to be present and visible
|
|
48
|
-
const table = page.getByRole('table');
|
|
49
|
-
await expect(table).toBeVisible();
|
|
50
|
-
|
|
51
|
-
// Show filters first
|
|
52
|
-
await page.getByText('Filters', { exact: true }).click();
|
|
53
|
-
|
|
54
|
-
// Find the amount filter input
|
|
55
|
-
const amountLabel = page.getByText('Amount', { exact: true });
|
|
56
|
-
const amountInput = amountLabel.locator('..').locator('~ div input');
|
|
57
|
-
|
|
58
|
-
// Test multiple values to ensure the transform roundtrip works correctly
|
|
59
|
-
const testValues = ['100', '255', '300'];
|
|
60
|
-
|
|
61
|
-
for (const testValue of testValues) {
|
|
62
|
-
// Clear and enter the test value
|
|
63
|
-
await amountInput.fill('');
|
|
64
|
-
await amountInput.fill(testValue);
|
|
65
|
-
|
|
66
|
-
// Apply the filter
|
|
67
|
-
await page.getByRole('button', { name: 'Apply filter' }).click();
|
|
68
|
-
|
|
69
|
-
// Wait for the filter to be applied
|
|
70
|
-
await page.waitForTimeout(100);
|
|
71
|
-
|
|
72
|
-
// Verify the input still shows the original value
|
|
73
|
-
await expect(amountInput).toHaveValue(testValue);
|
|
74
|
-
}
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
test('should handle empty values correctly with transforms', async ({ page }) => {
|
|
78
|
-
// Intercept the GraphQL request and mock the response
|
|
79
|
-
await page.route('**/v1/graphql', mockPaginationGraphQL);
|
|
80
|
-
|
|
81
|
-
// Navigate to the page with the simple test view
|
|
82
|
-
await page.goto('/?test-view=simple-test-view');
|
|
83
|
-
|
|
84
|
-
// Wait for the table to be present and visible
|
|
85
|
-
const table = page.getByRole('table');
|
|
86
|
-
await expect(table).toBeVisible();
|
|
87
|
-
|
|
88
|
-
// Show filters first
|
|
89
|
-
await page.getByText('Filters', { exact: true }).click();
|
|
90
|
-
|
|
91
|
-
// Find the amount filter input
|
|
92
|
-
const amountLabel = page.getByText('Amount', { exact: true });
|
|
93
|
-
const amountInput = amountLabel.locator('..').locator('~ div input');
|
|
94
|
-
|
|
95
|
-
// Enter a value, then clear it
|
|
96
|
-
await amountInput.fill('255');
|
|
97
|
-
await page.getByRole('button', { name: 'Apply filter' }).click();
|
|
98
|
-
await page.waitForTimeout(100);
|
|
99
|
-
|
|
100
|
-
// Clear the input
|
|
101
|
-
await amountInput.fill('');
|
|
102
|
-
await page.getByRole('button', { name: 'Apply filter' }).click();
|
|
103
|
-
await page.waitForTimeout(100);
|
|
104
|
-
|
|
105
|
-
// Verify the input remains empty
|
|
106
|
-
await expect(amountInput).toHaveValue('');
|
|
107
|
-
});
|
|
108
|
-
});
|
package/eslint.config.js
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import js from '@eslint/js'
|
|
2
|
-
import globals from 'globals'
|
|
3
|
-
import reactHooks from 'eslint-plugin-react-hooks'
|
|
4
|
-
import reactRefresh from 'eslint-plugin-react-refresh'
|
|
5
|
-
import tseslint from 'typescript-eslint'
|
|
6
|
-
|
|
7
|
-
export default tseslint.config(
|
|
8
|
-
{ ignores: ['dist'] },
|
|
9
|
-
{
|
|
10
|
-
extends: [js.configs.recommended, ...tseslint.configs.recommended],
|
|
11
|
-
files: ['**/*.{ts,tsx}'],
|
|
12
|
-
languageOptions: {
|
|
13
|
-
ecmaVersion: 2020,
|
|
14
|
-
globals: globals.browser,
|
|
15
|
-
},
|
|
16
|
-
plugins: {
|
|
17
|
-
'react-hooks': reactHooks,
|
|
18
|
-
'react-refresh': reactRefresh,
|
|
19
|
-
},
|
|
20
|
-
rules: {
|
|
21
|
-
...reactHooks.configs.recommended.rules,
|
|
22
|
-
'react-refresh/only-export-components': [
|
|
23
|
-
'warn',
|
|
24
|
-
{ allowConstantExport: true },
|
|
25
|
-
],
|
|
26
|
-
'@typescript-eslint/no-explicit-any': 'off',
|
|
27
|
-
'indent': ['error', 4, { 'SwitchCase': 1 }],
|
|
28
|
-
},
|
|
29
|
-
},
|
|
30
|
-
)
|