From e85ecb0347e95ff1cfc4ac714838514688a3ded0 Mon Sep 17 00:00:00 2001 From: Ingerid Gjeitnes Hellen <64828956+ingeridhellen@users.noreply.github.com> Date: Wed, 2 Aug 2023 15:09:18 +0200 Subject: [PATCH] feat(form): add inline flag * feat(form): add isline flag * fix(form): remove bugs in inline form * test(form): validate inline form and yaml * test(form): split into multiple tests --- e2e/tests/plugin-form-Nested.spec.ts | 105 +++++++++++------- .../CarRentalCompany.blueprint.json | 7 ++ .../form/nested/carRentalCompany.recipe.json | 11 +- .../blueprints/form/fields/Field.json | 8 ++ .../src/form/fields/ObjectField.tsx | 53 ++++----- packages/dm-core-plugins/src/form/types.tsx | 2 + .../src/view_selector/Content.tsx | 5 +- 7 files changed, 119 insertions(+), 72 deletions(-) diff --git a/e2e/tests/plugin-form-Nested.spec.ts b/e2e/tests/plugin-form-Nested.spec.ts index 2180d59ec..56a63202c 100644 --- a/e2e/tests/plugin-form-Nested.spec.ts +++ b/e2e/tests/plugin-form-Nested.spec.ts @@ -1,14 +1,27 @@ -import { expect, test } from '@playwright/test' +import { Page, expect, test } from '@playwright/test' -test('Nested Form', async ({ page }) => { - //Open form +test.describe.configure({ mode: 'serial' }) + +let page: Page + +test.beforeAll(async ({ browser }) => { + page = await browser.newPage() await page.goto('http://localhost:3000/') + await navigate() +}) + +test.afterAll(async () => { + await page.close() +}) + +const navigate = async () => { await page.getByText('plugins', { exact: true }).click() await page.getByText('form').click() await page.getByText('nested', { exact: true }).click() await page.getByText('DemoDataSource/$Nested').click() +} - //Change owner +test('Change owner', async () => { await expect(page.getByText('Owner', { exact: true })).toBeVisible await page .getByText('OwnerOpen') @@ -22,8 +35,9 @@ test('Nested Form', async ({ page }) => { await expect(page.getByLabel('Name')).toHaveValue('Jacob') await expect(page.getByLabel('Phone Number (optional)')).toHaveValue('1234') await page.getByRole('tab').nth(2).click() +}) - //Hiring a CEO +test('Hiring a CEO', async () => { await page .getByText('CEO (optional)Add') .getByRole('button', { name: 'Add' }) @@ -52,52 +66,64 @@ test('Nested Form', async ({ page }) => { await expect( page.getByText('CEO (optional)Add').getByRole('button', { name: 'Add' }) ).toBeVisible() +}) + +test('View accountant yaml', async () => { + await expect( + page.getByTestId('accountant').getByRole('button', { name: 'Copy as YAML' }) + ).toBeVisible() + await expect( + page.getByTestId('accountant').getByRole('button', { name: 'Copy as JSON' }) + ).toBeVisible() + await expect(page.getByTestId('accountant').getByRole('code')).toBeVisible() +}) - //Replacing accountant +test('Adding a trainee', async () => { await page - .getByText('AccountantOpen') - .getByRole('button', { name: 'Open' }) + .getByText('Trainee (optional)Add') + .getByRole('button', { name: 'Add' }) .click() - await page.getByLabel('Name').fill('Richie') - await page.getByLabel('Phone Number (optional)').fill('11223344') - await page.getByRole('button', { name: 'Submit' }).click() - await page.getByText('self').first().click() - await page.getByRole('tab').nth(2).click() + await page.getByTestId('trainee').getByLabel('Name').fill('Peter Pan') await page - .getByText('AccountantOpen') - .getByRole('button', { name: 'Open' }) - .click() - await expect(page.getByLabel('Name')).toHaveValue('Richie') - await expect(page.getByLabel('Phone Number (optional)')).toHaveValue( - '11223344' + .getByTestId('trainee') + .getByLabel('Phone Number (optional)') + .fill('123') + await page.getByRole('button', { name: 'Submit' }).click() + await page.reload() + await navigate() + await expect(page.getByTestId('trainee').getByLabel('Name')).toHaveValue( + 'Peter Pan' ) - await page.getByRole('tab').nth(2).click() + await expect( + page.getByTestId('trainee').getByLabel('Phone Number (optional)') + ).toHaveValue('123') +}) - //New car +test('New car', async () => { await page.getByText('CarsOpen').getByRole('button', { name: 'Open' }).click() await expect.soft(page.getByText('1 - 2 of 2')).toBeVisible() await page.getByRole('button', { name: 'Append Add Item' }).click() await expect.soft(page.getByText('1 - 3 of 3')).toBeVisible() await page.getByRole('button', { name: 'Save' }).click() await page.getByRole('button', { name: 'Open item' }).last().click() - await page.getByLabel('Name').fill('McLaren') - await page.getByLabel('Plate Number').fill('3000') - await page.getByRole('button', { name: 'Submit' }).click() + const lastTabPanel = page.getByRole('tabpanel').last() + await expect(lastTabPanel).toBeVisible() + await lastTabPanel.getByLabel('Name').fill('McLaren') + await lastTabPanel.getByLabel('Plate Number').fill('3000') + await lastTabPanel.getByRole('button', { name: 'Submit' }).click() await page.reload() - await page.getByText('plugins', { exact: true }).click() - await page.getByText('form').click() - await page.getByText('nested').click() - await page.getByText('DemoDataSource/$Nested').click() + await navigate() await page.getByText('CarsOpen').getByRole('button', { name: 'Open' }).click() // await expect(page.getByText('McLaren')).toBeVisible() Does not work because two instances are stored when submitting form... Known bug. await page.getByRole('button', { name: 'Open item' }).last().click() await expect(page.getByRole('tab', { name: 'McLaren' })).toBeVisible() - await expect(page.getByLabel('Name')).toHaveValue('McLaren') - await expect(page.getByLabel('Plate Number')).toHaveValue('3000') + await expect(lastTabPanel.getByLabel('Name')).toHaveValue('McLaren') + await expect(lastTabPanel.getByLabel('Plate Number')).toHaveValue('3000') await page.getByRole('tab').last().click() await page.getByRole('tab').last().click() +}) - //New customer +test('New customer', async () => { await page .getByText('CustomersOpen') .getByRole('button', { name: 'Open' }) @@ -107,14 +133,13 @@ test('Nested Form', async ({ page }) => { await expect.soft(page.getByText('1 - 3 of 3')).toBeVisible() await page.getByRole('button', { name: 'Save' }).click() await page.getByRole('button', { name: 'Open item' }).last().click() - await page.getByLabel('Name').fill('Lewis') - await page.getByLabel('Phone number (optional)').fill('12345678') - await page.getByRole('button', { name: 'Submit' }).click() + const lastTabPanel = page.getByRole('tabpanel').last() + await expect(lastTabPanel).toBeVisible() + await lastTabPanel.getByLabel('Name').fill('Lewis') + await lastTabPanel.getByLabel('Phone number (optional)').fill('12345678') + await lastTabPanel.getByRole('button', { name: 'Submit' }).click() await page.reload() - await page.getByText('plugins', { exact: true }).click() - await page.getByText('form').click() - await page.getByText('nested').click() - await page.getByText('DemoDataSource/$Nested').click() + await navigate() await page .getByText('CustomersOpen') .getByRole('button', { name: 'Open' }) @@ -122,8 +147,8 @@ test('Nested Form', async ({ page }) => { // await expect(page.getByText('Lewis')).toBeVisible() Does not work because two instances are stored when submitting form... Known bug. await page.getByRole('button', { name: 'Open item' }).last().click() await expect(page.getByRole('tab', { name: 'Lewis' })).toBeVisible() - await expect(page.getByLabel('Name')).toHaveValue('Lewis') - await expect(page.getByLabel('Phone number (optional)')).toHaveValue( + await expect(lastTabPanel.getByLabel('Name')).toHaveValue('Lewis') + await expect(lastTabPanel.getByLabel('Phone number (optional)')).toHaveValue( '12345678' ) await page.getByRole('tab').last().click() diff --git a/example/app/data/DemoDataSource/plugins/form/nested/blueprints/CarRentalCompany.blueprint.json b/example/app/data/DemoDataSource/plugins/form/nested/blueprints/CarRentalCompany.blueprint.json index 671ad12c3..2e5603175 100644 --- a/example/app/data/DemoDataSource/plugins/form/nested/blueprints/CarRentalCompany.blueprint.json +++ b/example/app/data/DemoDataSource/plugins/form/nested/blueprints/CarRentalCompany.blueprint.json @@ -27,6 +27,13 @@ "attributeType": "./Person", "label": "Accountant" }, + { + "name": "trainee", + "type": "CORE:BlueprintAttribute", + "attributeType": "./Person", + "label": "Trainee", + "optional": true + }, { "name": "bestCustomer", "type": "CORE:BlueprintAttribute", diff --git a/example/app/data/DemoDataSource/recipes/plugins/form/nested/carRentalCompany.recipe.json b/example/app/data/DemoDataSource/recipes/plugins/form/nested/carRentalCompany.recipe.json index 12c76d221..ba48cd1e5 100644 --- a/example/app/data/DemoDataSource/recipes/plugins/form/nested/carRentalCompany.recipe.json +++ b/example/app/data/DemoDataSource/recipes/plugins/form/nested/carRentalCompany.recipe.json @@ -30,13 +30,15 @@ "type": "PLUGINS:dm-core-plugins/form/FormInput", "attributes": [ { - "type": "PLUGINS:dm-core-plugins/form/fields/StringField", - "name": "type", - "widget": "TypeWidget" + "type": "PLUGINS:dm-core-plugins/form/fields/ObjectField", + "name": "trainee", + "isInline": true, + "uiRecipe": "defaultForm" }, { "type": "PLUGINS:dm-core-plugins/form/fields/ObjectField", - "name": "owner", + "name": "accountant", + "isInline": true, "uiRecipe": "defaultYaml" } ], @@ -44,6 +46,7 @@ "owner", "ceo", "accountant", + "trainee", "bestCustomer", "cars", "customers" diff --git a/packages/dm-core-plugins/blueprints/form/fields/Field.json b/packages/dm-core-plugins/blueprints/form/fields/Field.json index 512f14e37..7c39de782 100644 --- a/packages/dm-core-plugins/blueprints/form/fields/Field.json +++ b/packages/dm-core-plugins/blueprints/form/fields/Field.json @@ -13,6 +13,14 @@ "type": "dmss://system/SIMOS/BlueprintAttribute", "optional": false, "attributeType": "string" + }, + { + "name": "isInline", + "description": "If true, the attribute will be shown inline. If false, it will be opened in a new tab if possible", + "type": "dmss://system/SIMOS/BlueprintAttribute", + "optional": true, + "default": false, + "attributeType": "boolean" } ] } diff --git a/packages/dm-core-plugins/src/form/fields/ObjectField.tsx b/packages/dm-core-plugins/src/form/fields/ObjectField.tsx index e4c7f0c1d..7c4ee5fb7 100644 --- a/packages/dm-core-plugins/src/form/fields/ObjectField.tsx +++ b/packages/dm-core-plugins/src/form/fields/ObjectField.tsx @@ -135,6 +135,7 @@ export const ContainedAttribute = (props: TContentProps): JSX.Element => { namePath, displayLabel = '', optional = false, + uiAttribute, uiRecipe, blueprint, } = props @@ -149,7 +150,7 @@ export const ContainedAttribute = (props: TContentProps): JSX.Element => { const attributePath = idReference.split('.', 2).slice(1) return ( -
+
{displayLabel} {optional && @@ -174,36 +175,35 @@ export const ContainedAttribute = (props: TContentProps): JSX.Element => { onAdd={() => setIsDefined(true)} /> ))} - {hasOpen && isDefined && ( - 1 - ? `${attributePath[1]}.${namePath}` - : namePath - } - /> - )} - {!hasOpen && isDefined && ( - <> - {uiRecipe && uiRecipe.plugin !== 'form' && ( - - )} - {(uiRecipe === undefined || - (uiRecipe && uiRecipe.plugin === 'form')) && ( + {isDefined && + (hasOpen && !uiAttribute?.isInline ? ( + 1 + ? `${attributePath[1]}.${namePath}` + : namePath + } + /> + ) : uiRecipe && + uiRecipe.plugin !== + '@development-framework/dm-core-plugins/form' ? ( + + ) : ( +
- )} - - )} +
+ ))}
) @@ -328,6 +328,7 @@ export const ObjectTypeSelector = (props: TObjectFieldProps): JSX.Element => { optional={optional} blueprint={blueprint} uiRecipe={uiRecipe} + uiAttribute={uiAttribute} /> ) } diff --git a/packages/dm-core-plugins/src/form/types.tsx b/packages/dm-core-plugins/src/form/types.tsx index d1b6c9bfa..8423f8149 100644 --- a/packages/dm-core-plugins/src/form/types.tsx +++ b/packages/dm-core-plugins/src/form/types.tsx @@ -30,6 +30,7 @@ export type TContentProps = { optional: boolean blueprint: TBlueprint | undefined uiRecipe: TUiRecipeForm | undefined + uiAttribute: TAttributeConfig | undefined } export type TAttributeFieldProps = { @@ -64,6 +65,7 @@ export type TBooleanFieldProps = { type TAttributeBasis = { name: string type: string + isInline?: boolean } type TAttributeString = TAttributeBasis & { widget: string; format: string } type TAttributeArray = TAttributeBasis & { diff --git a/packages/dm-core-plugins/src/view_selector/Content.tsx b/packages/dm-core-plugins/src/view_selector/Content.tsx index af6bae286..951b96909 100644 --- a/packages/dm-core-plugins/src/view_selector/Content.tsx +++ b/packages/dm-core-plugins/src/view_selector/Content.tsx @@ -1,10 +1,10 @@ -import * as React from 'react' -import styled from 'styled-components' import { TGenericObject, TViewConfig, ViewCreator, } from '@development-framework/dm-core' +import * as React from 'react' +import styled from 'styled-components' import { TItemData } from './types' const HidableWrapper = styled.div` @@ -28,6 +28,7 @@ export const Content = (props: {