Skip to content

Commit

Permalink
Implemented reordering of array properties
Browse files Browse the repository at this point in the history
  • Loading branch information
zonia3000 committed Jan 18, 2024
1 parent 99300a0 commit 7b26232
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 17 deletions.
40 changes: 39 additions & 1 deletion src/lib/components/common/jschema/ArrayProperty.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import PropertyDiscriminator from '$lib/components/common/jschema/PropertyDiscriminator.svelte';
import PropertyDescription from '$lib/components/common/jschema/PropertyDescription.svelte';
/** @type {import('$lib/components/common/jschema/schema_management').SchemaProperty} */
export let schemaProperty;
let nestedProperties = [];
Expand Down Expand Up @@ -63,7 +64,10 @@
nestedProperties = schemaProperty.nestedProperties;
}
function removeNestedProperty(/** @type {number} */ index) {
/**
* @param {number} index
*/
function removeNestedProperty(index) {
schemaProperty.removeNestedSchemaProperty(index);
nestedProperties = schemaProperty.nestedProperties;
const minItems = getMinItems(schemaProperty.referenceSchema);
Expand All @@ -72,6 +76,20 @@
nestedProperties = schemaProperty.nestedProperties;
}
}
/**
* @param {number} index
*/
function moveUp(index) {
nestedProperties = schemaProperty.moveNestedPropertyUp(index);
}
/**
* @param {number} index
*/
function moveDown(index) {
nestedProperties = schemaProperty.moveNestedPropertyDown(index);
}
</script>

{#if schemaProperty}
Expand Down Expand Up @@ -121,6 +139,26 @@
<div class="flex-fill">
<PropertyDiscriminator schemaProperty={nestedProperty} />
</div>
<div class="align-self-right mt-2 me-2">
{#if nestedProperties.length > 1}
<button
class="btn btn-light"
on:click|preventDefault={() => moveUp(index)}
aria-label="Move item up"
disabled={index === 0}
>
<i class="bi-arrow-up" />
</button>
<button
class="btn btn-light"
on:click|preventDefault={() => moveDown(index)}
aria-label="Move item down"
disabled={index === nestedProperties.length - 1}
>
<i class="bi-arrow-down" />
</button>
{/if}
</div>
</div>
{/each}
</div>
Expand Down
57 changes: 54 additions & 3 deletions src/lib/components/common/jschema/schema_management.js
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,52 @@ export class SchemaProperty {
return nestedProperty;
}

/**
* @param {number} index
* @returns {any[]}
*/
moveNestedPropertyUp(index) {
if (index > 0) {
let updatedArray = [];
for (let i = 0; i < this.nestedProperties.length; i++) {
if (i === index - 1) {
updatedArray[i] = this.nestedProperties[i + 1];
} else if (i === index) {
updatedArray[i] = this.nestedProperties[i - 1];
} else {
updatedArray[i] = this.nestedProperties[i];
}
updatedArray[i].key = `${this.key}${this.keySeparator}${i}`;
}
this.nestedProperties = updatedArray;
this.manager.updateValue(this.key, this.getUpdatedNestedProperties());
}
return this.nestedProperties;
}

/**
* @param {number} index
* @returns {any[]}
*/
moveNestedPropertyDown(index) {
if (index < this.nestedProperties.length - 1) {
let updatedArray = [];
for (let i = 0; i < this.nestedProperties.length; i++) {
if (i === index) {
updatedArray[i] = this.nestedProperties[i + 1];
} else if (i === index + 1) {
updatedArray[i] = this.nestedProperties[i - 1];
} else {
updatedArray[i] = this.nestedProperties[i];
}
updatedArray[i].key = `${this.key}${this.keySeparator}${i}`;
}
this.nestedProperties = updatedArray;
this.manager.updateValue(this.key, this.getUpdatedNestedProperties());
}
return this.nestedProperties;
}

addProperty(namedKey, propertyValue) {
if (this.type !== 'object') {
throw new Error('Schema property is not of type object');
Expand Down Expand Up @@ -292,15 +338,20 @@ export class SchemaProperty {
}
}

/**
* @param {number} index
*/
removeNestedSchemaProperty(index) {
this.nestedProperties.splice(index, 1);
// Should update the keys of nested properties and update the value of the property
const updatedValues = this.nestedProperties.map((nestedProperty, index) => {
this.manager.updateValue(this.key, this.getUpdatedNestedProperties());
}

getUpdatedNestedProperties() {
return this.nestedProperties.map((nestedProperty, index) => {
nestedProperty.key = `${this.key}${this.keySeparator}${index}`;
return nestedProperty.value;
});
this.manager.updateValue(this.key, updatedValues);
// this.manager.updateValue(this.key, this.value)
}

discriminatePropertyType(schema, globalSchema, currentValue) {
Expand Down
71 changes: 58 additions & 13 deletions tests/jschema.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import path from 'path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

test('JSON Schema validation', async ({ page, workflow }) => {
test('JSON Schema validation', async ({ page, browserName, workflow }) => {
await page.waitForURL(workflow.url);
await waitPageLoading(page);

Expand Down Expand Up @@ -97,8 +97,11 @@ test('JSON Schema validation', async ({ page, workflow }) => {

await test.step('Fill required integer with min and max', async () => {
const input = form.getByLabel('minMaxRequiredInt', { exact: true });
await input.pressSequentially('foo');
expect(form.getByText('Should be a number')).toHaveCount(1);
if (browserName === 'firefox') {
// chrome doesn't allow to insert text inside numeric inputs
await input.pressSequentially('foo');
expect(form.getByText('Should be a number')).toHaveCount(1);
}
await input.fill('1');
expect(form.getByText('Should be greater or equal than 5')).toHaveCount(1);
await input.fill('15');
Expand All @@ -111,8 +114,11 @@ test('JSON Schema validation', async ({ page, workflow }) => {

await test.step('Fill optional integer with min and max', async () => {
const input = form.getByLabel('minMaxOptionalInt', { exact: true });
await input.pressSequentially('foo');
expect(form.getByText('Should be a number')).toHaveCount(1);
if (browserName === 'firefox') {
// chrome doesn't allow to insert text inside numeric inputs
await input.pressSequentially('foo');
expect(form.getByText('Should be a number')).toHaveCount(1);
}
await input.fill('-7');
expect(form.getByText('Should be greater or equal than 0')).toHaveCount(1);
await input.fill('33');
Expand All @@ -123,8 +129,11 @@ test('JSON Schema validation', async ({ page, workflow }) => {

await test.step('Fill optional integer with exclusive min and max', async () => {
const input = form.getByLabel('exclusiveMinMaxOptionalInt', { exact: true });
await input.pressSequentially('foo');
expect(form.getByText('Should be a number')).toHaveCount(1);
if (browserName === 'firefox') {
// chrome doesn't allow to insert text inside numeric inputs
await input.pressSequentially('foo');
expect(form.getByText('Should be a number')).toHaveCount(1);
}
await input.fill('2');
expect(form.getByText('Should be greater or equal than 4')).toHaveCount(1);
await input.fill('99');
Expand All @@ -138,21 +147,39 @@ test('JSON Schema validation', async ({ page, workflow }) => {
await addBtn.click();
await addBtn.click();
await addBtn.click();
// Fill items
await form.locator('id=property-requiredArrayWithMinMaxItems###0').fill('a');
await form.locator('id=property-requiredArrayWithMinMaxItems###1').fill('b');
await form.locator('id=property-requiredArrayWithMinMaxItems###2').fill('c');
await form.locator('id=property-requiredArrayWithMinMaxItems###3').fill('d');
// Move "d" up
await page.getByRole('button', { name: 'Move item up' }).nth(3).click();
await page.getByRole('button', { name: 'Move item up' }).nth(2).click();
await page.getByRole('button', { name: 'Move item up' }).nth(1).click();
await checkFirstArray(['d', 'a', 'b', 'c']);
// Move "d" down
await page.getByRole('button', { name: 'Move item down' }).first().click();
await page.getByRole('button', { name: 'Move item down' }).nth(1).click();
await checkFirstArray(['a', 'b', 'd', 'c']);
// Remove items
await form.getByRole('button', { name: 'Remove' }).nth(3).click();
await form.getByRole('button', { name: 'Remove' }).nth(2).click();
expect(await form.locator('id=property-requiredArrayWithMinMaxItems###1').inputValue()).toEqual(
'b'
);
await checkFirstArray(['a', 'b']);
await form.getByRole('button', { name: 'Remove' }).nth(1).click();
expect(await form.locator('id=property-requiredArrayWithMinMaxItems###1').inputValue()).toEqual(
''
);
await checkFirstArray(['a', '']);
});

/**
* @param {string[]} expectedValues
*/
async function checkFirstArray(expectedValues) {
for (let i = 0; i < expectedValues.length; i++) {
expect(
await form.locator('id=property-requiredArrayWithMinMaxItems###' + i).inputValue()
).toEqual(expectedValues[i]);
}
}

await test.step('Optional array with minItems and maxItems', async () => {
await form.getByText('optionalArrayWithMinMaxItems').first().click();
const addBtn = form.getByRole('button', { name: 'Add argument to list' }).nth(1);
Expand All @@ -179,6 +206,24 @@ test('JSON Schema validation', async ({ page, workflow }) => {
expect(form.getByText('Field is required')).toHaveCount(2);
});

await test.step('Save values', async () => {
const stringInput = form.getByLabel('Required string', { exact: true });
await stringInput.fill('foo');
const intInput = form.getByLabel('minMaxRequiredInt', { exact: true });
await intInput.fill('7');
await form.locator('id=property-requiredArrayWithMinMaxItems###1').fill('b');
await page.getByRole('button', { name: 'Move item up' }).nth(1).click();
await page.getByRole('button', { name: 'Save changes' }).click();
await page.getByText('Arguments changes saved successfully').waitFor();
await page.reload();
await waitPageLoading(page);
await page.getByText(`${randomTaskName} #`).first().click();
expect(await page.getByLabel('Required string', { exact: true }).inputValue()).toEqual('foo');
expect(await page.getByLabel('minMaxRequiredInt', { exact: true }).inputValue()).toEqual('7');
expect(await page.locator('id=property-requiredEnum').inputValue()).toEqual('option1');
await checkFirstArray(['b', 'a']);
});

await test.step('Delete workflow task', async () => {
await page.getByLabel('Delete workflow task').click();
const modal = page.locator('.modal.show');
Expand Down

0 comments on commit 7b26232

Please sign in to comment.