Skip to content

Commit

Permalink
XIVY-15648 info when manually importing variable
Browse files Browse the repository at this point in the history
An info is shown when trying to manually add a variable that already exists in a required project that it can be imported.
Pressing the button again will import the variable.

Also removed some unnecessary pageobject functions.
  • Loading branch information
ivy-lgi committed Dec 18, 2024
1 parent fac18b6 commit 4a3a015
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 67 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,18 @@ import {
DialogTrigger,
Flex,
Input,
Message,
selectRow
} from '@axonivy/ui-components';
import { IvyIcons } from '@axonivy/ui-icons';
import { EMPTY_KNOWN_VARIABLES } from '@axonivy/variable-editor-protocol';
import { EMPTY_KNOWN_VARIABLES, type KnownVariables } from '@axonivy/variable-editor-protocol';
import { type Table } from '@tanstack/react-table';
import { useMemo, useState } from 'react';
import { useEffect, useMemo, useState } from 'react';
import { useAppContext } from '../../../context/AppContext';
import { useMeta } from '../../../context/useMeta';
import { keyOfFirstSelectedNonLeafRow, keysOfAllNonLeafRows, newNodeName, subRowNamesOfRow, toRowId } from '../../../utils/tree/tree';
import { addNode } from '../../../utils/tree/tree-data';
import type { AddNodeReturnType } from '../../../utils/tree/types';
import { validateName, validateNamespace } from '../data/validation-utils';
import { createVariable, type Variable } from '../data/variable';
import './AddDialog.css';
Expand All @@ -37,34 +39,56 @@ export const AddVariableDialog = ({ table }: AddVariableDialogProps) => {
const [namespace, setNamespace] = useState('');

const nameValidationMessage = useMemo(() => validateName(name, subRowNamesOfRow(namespace, table)), [name, namespace, table]);

const namespaceValidationMessage = useMemo(() => validateNamespace(namespace, variables), [namespace, variables]);

const [knownVariable, setKnownVariable] = useState<KnownVariables>();
useEffect(() => setKnownVariable(undefined), [name, namespace]);

const knownVariables = useMeta('meta/knownVariables', context, EMPTY_KNOWN_VARIABLES).data;

const initializeVariableDialog = () => {
setName(newNodeName(table, 'NewVariable'));
setNamespace(keyOfFirstSelectedNonLeafRow(table));
};

const namespaceOptions = () => keysOfAllNonLeafRows(table).map(key => ({ value: key }));

const knownVariables = useMeta('meta/knownVariables', context, EMPTY_KNOWN_VARIABLES).data;
const updateSelection = (addNodeReturnValue: AddNodeReturnType<Variable>) => {
selectRow(table, toRowId(addNodeReturnValue.newNodePath));
setSelectedVariable(addNodeReturnValue.newNodePath);
};

const addVariable = () => {
const namespaceKey = namespace ? namespace.split('.') : [];
const overwrittenVariable = findKnownVariable(knownVariables, ...namespaceKey, name);
const addKnown = (knownVariable: KnownVariables) => {
setVariables(old => {
let addNodeReturnValue;
if (overwrittenVariable) {
addNodeReturnValue = addKnownVariable(old, overwrittenVariable);
} else {
addNodeReturnValue = addNode(name, namespace, old, createVariable);
}
selectRow(table, toRowId(addNodeReturnValue.newNodePath));
setSelectedVariable(addNodeReturnValue.newNodePath);
const addNodeReturnValue = addKnownVariable(old, knownVariable);
updateSelection(addNodeReturnValue);
return addNodeReturnValue.newData;
});
};

const addVar = () => {
setVariables(old => {
const addNodeReturnValue = addNode(name, namespace, old, createVariable);
updateSelection(addNodeReturnValue);
return addNodeReturnValue.newData;
});
};

const addVariable = (event: React.MouseEvent<HTMLButtonElement>) => {
if (knownVariable) {
addKnown(knownVariable);
return;
}
const namespaceKey = namespace ? namespace.split('.') : [];
const foundKnownVariable = findKnownVariable(knownVariables, ...namespaceKey, name);
if (foundKnownVariable) {
setKnownVariable(foundKnownVariable);
event.preventDefault();
return;
}
addVar();
};

const allInputsValid = () => !nameValidationMessage && !namespaceValidationMessage;

return (
Expand Down Expand Up @@ -106,18 +130,24 @@ export const AddVariableDialog = ({ table }: AddVariableDialogProps) => {
</BasicField>
</Flex>
<DialogFooter>
<DialogClose asChild>
<Button
variant='primary'
size='large'
type='submit'
aria-label='Create variable'
disabled={!allInputsValid()}
onClick={addVariable}
>
Create Variable
</Button>
</DialogClose>
<Flex>
{knownVariable && (
<Message variant='info' message='This Variable is already present in a required project. Do you want to import it?' />
)}
<DialogClose asChild>
<Button
variant='primary'
size='large'
type='submit'
aria-label='Create variable'
disabled={!allInputsValid()}
onClick={addVariable}
style={{ whiteSpace: 'nowrap' }}
>
{`${knownVariable ? 'Import' : 'Create'} Variable`}
</Button>
</DialogClose>
</Flex>
</DialogFooter>
</DialogContent>
</Dialog>
Expand Down
32 changes: 16 additions & 16 deletions playwright/tests/integration/mock/editor.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { test } from '@playwright/test';
import { VariableEditor } from '../../pageobjects/VariableEditor';
import { expect, test } from '@playwright/test';
import type { Table } from '../../pageobjects/Table';
import { VariableEditor } from '../../pageobjects/VariableEditor';

let editor: VariableEditor;
let tree: Table;
Expand Down Expand Up @@ -89,56 +89,56 @@ test('add', async () => {
test('addVariableDialogDefaultValues', async () => {
await tree.row(5).click();
await tree.row(5).expectValues(['useUserPassFlow', '']);
await editor.add.open();
await editor.add.open.click();
await editor.add.expectValues('NewVariable', 'microsoft-connector.useUserPassFlow', 'microsoft-connector', 'microsoft-connector.useUserPassFlow');
});

test.describe('addVariableDialogValidation', async () => {
test.describe('name', async () => {
test('onNameChange', async () => {
const add = editor.add;
await add.open();
await add.open.click();
await add.nameMessage.expectToBeHidden();
await add.expectCreateEnabled();
await expect(add.create.locator).toBeEnabled();
await add.name.fill('');
await add.nameMessage.expectErrorMessage('Name cannot be empty.');
await add.expectCreateDisabled();
await expect(add.create.locator).toBeDisabled();
await add.name.fill('microsoft-connector');
await add.nameMessage.expectErrorMessage('Name is already present in this Namespace.');
await add.expectCreateDisabled();
await expect(add.create.locator).toBeDisabled();
});

test('onNamespaceChange', async () => {
const add = editor.add;
await add.open();
await add.open.click();
await add.name.fill('appId');
await add.nameMessage.expectToBeHidden();
await add.expectCreateEnabled();
await expect(add.create.locator).toBeEnabled();
await add.namespace.choose('microsoft-connector');
await add.nameMessage.expectErrorMessage('Name is already present in this Namespace.');
await add.expectCreateDisabled();
await expect(add.create.locator).toBeDisabled();
});

test('onNamespaceInput', async () => {
const add = editor.add;
await add.open();
await add.open.click();
await add.name.fill('appId');
await add.nameMessage.expectToBeHidden();
await add.expectCreateEnabled();
await expect(add.create.locator).toBeEnabled();
await add.namespace.fill('microsoft-connector');
await add.nameMessage.expectErrorMessage('Name is already present in this Namespace.');
await add.expectCreateDisabled();
await expect(add.create.locator).toBeDisabled();
});
});

test('namespace', async () => {
const add = editor.add;
await add.open();
await add.open.click();
await add.namespaceMessage.expectInfoMessage("Folder structure of variable (e.g. 'Connector.Key')");
await add.expectCreateEnabled();
await expect(add.create.locator).toBeEnabled();
await add.namespace.fill('microsoft-connector.appId.New.Namespace');
await add.namespaceMessage.expectErrorMessage("Namespace 'microsoft-connector.appId' is not a folder, you cannot add a child to it.");
await add.expectCreateDisabled();
await expect(add.create.locator).toBeDisabled();
});
});

Expand Down
13 changes: 12 additions & 1 deletion playwright/tests/integration/mock/import.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,18 @@ describe('disabledMetadataOfOverwrittenVariable', async () => {
});

test('import variable when manually adding a known variable', async () => {
await editor.addVariable('Comprehend', 'Amazon');
await editor.add.open.click();
await editor.add.name.fill('Comprehend');
await editor.add.namespace.fill('Amazon');

await expect(editor.add.footerMessage).toBeHidden();

await editor.add.create.click();

await expect(editor.add.footerMessage).toBeVisible();

await editor.add.create.click();

await editor.details.expectFolderValues('Comprehend', 'Amazon comprehend connector settings');
await editor.tree.expectRowCount(15);
await editor.tree.row(11).click();
Expand Down
24 changes: 5 additions & 19 deletions playwright/tests/pageobjects/AddVariableDialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,41 +5,27 @@ import { FieldMessage } from './FieldMessage';
import { TextArea } from './TextArea';

export class AddVariableDialog {
private readonly add: Button;
readonly open: Button;
readonly name: TextArea;
readonly nameMessage: FieldMessage;
readonly namespace: Combobox;
readonly namespaceMessage: FieldMessage;
private readonly create: Button;
readonly footerMessage: Locator;
readonly create: Button;

constructor(page: Page, parent: Locator) {
this.add = new Button(parent, { name: 'Add variable' });
this.open = new Button(parent, { name: 'Add variable' });
this.name = new TextArea(parent);
this.nameMessage = new FieldMessage(parent, { label: 'Name' });
this.namespace = new Combobox(page, parent);
this.namespaceMessage = new FieldMessage(parent, { label: 'Namespace' });
this.footerMessage = parent.locator('.ui-dialog-footer').locator('.ui-message');
this.create = new Button(parent, { name: 'Create variable' });
}

async open() {
await this.add.click();
}

async expectValues(name: string, namespaceValue: string, ...namespaceOptions: Array<string>) {
await this.name.expectValue(name);
await this.namespace.expectValue(namespaceValue);
await this.namespace.expectOptions(...namespaceOptions);
}

async createVariable() {
await this.create.click();
}

async expectCreateEnabled() {
await this.create.expectEnabled();
}

async expectCreateDisabled() {
await this.create.expectDisabled();
}
}
2 changes: 1 addition & 1 deletion playwright/tests/pageobjects/Button.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { expect, type Locator } from '@playwright/test';

export class Button {
private readonly locator: Locator;
readonly locator: Locator;

constructor(parentLocator: Locator, options?: { name?: string; nth?: number }) {
if (options?.name) {
Expand Down
6 changes: 3 additions & 3 deletions playwright/tests/pageobjects/VariableEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import { expect, type Locator, type Page } from '@playwright/test';
import { AddVariableDialog } from './AddVariableDialog';
import { Button } from './Button';
import { Details } from './Details';
import { OverwriteDialog } from './OverwriteDialog';
import { Settings } from './Settings';
import { Table } from './Table';
import { TextArea } from './TextArea';
import { OverwriteDialog } from './OverwriteDialog';

export class VariableEditor {
readonly page: Page;
Expand Down Expand Up @@ -69,13 +69,13 @@ export class VariableEditor {
}

async addVariable(name?: string, namespace?: string) {
await this.add.open();
await this.add.open.click();
if (name) {
await this.add.name.fill(name);
}
if (namespace) {
await this.add.namespace.fill(namespace);
}
await this.add.createVariable();
await this.add.create.click();
}
}

0 comments on commit 4a3a015

Please sign in to comment.