Skip to content

Commit

Permalink
Merge pull request #457 from fractal-analytics-platform/further-v2-ch…
Browse files Browse the repository at this point in the history
…anges

More V2 features
  • Loading branch information
zonia3000 authored Apr 19, 2024
2 parents 8a7b140 + d138d92 commit 4cd7b48
Show file tree
Hide file tree
Showing 22 changed files with 739 additions and 300 deletions.
6 changes: 4 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# Unreleased

* Supported fractal-server API V2:
* added menu switch to support legacy and current API (\#434);
* added menu switch to support legacy and current API (\#434, \#457);
* Dataset V2 CRUD with attribute and type filters (\#434);
* new Dataset page with image list and filters (\#434);
* updated Single Task form to handle parallel and non parallel fields (\#434);
Expand All @@ -13,9 +13,11 @@
* added admin "Tasks V1/V2 compatibility" page (\#450);
* supported adding V1 task in V2 workflow (\#450);
* removed read only property from V2 datasets (\#450);
* added input filters tab in workflow task page (\#452);
* added input filters tab in workflow task page (\#452, \#457);
* added searchable dropdowns for image filters (\#452);
* moved editing of dataset inside dataset page (\#452);
* supported editing of single dataset images (\#457);
* used switches to represent boolean flags (\#457);

# 0.10.2

Expand Down
12 changes: 11 additions & 1 deletion __tests__/v1/JSchema.test.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
import { describe, it, expect } from 'vitest';
import { describe, it, expect, vi } from 'vitest';
import { fireEvent, render, screen } from '@testing-library/svelte';
import { readable } from 'svelte/store';

import JSchema from '../../src/lib/components/v1/workflow/JSchema.svelte';

// Mocking the page store
vi.mock('$app/stores', () => {
return {
page: readable({
url: { pathname: '/v1/projects/1/workflows/1' }
})
};
});

describe('JSchema', () => {
it('Required NumberProperty with title', async () => {
const result = renderSchemaWithSingleProperty(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { describe, it, expect } from 'vitest';
import { fireEvent, render } from '@testing-library/svelte';

import FiltersCreationForm from '../../src/lib/components/v2/projects/datasets/FiltersCreationForm.svelte';
import AttributesTypesForm from '../../src/lib/components/v2/projects/datasets/AttributesTypesForm.svelte';
import { tick } from 'svelte';

describe('FiltersCreationForm', () => {
describe('AttributesTypesForm', () => {
it('init with existing filters', async () => {
const result = render(FiltersCreationForm);
const result = render(AttributesTypesForm);
result.component.init(
{
key1: 'value1',
Expand All @@ -29,7 +29,7 @@ describe('FiltersCreationForm', () => {
});

it('add and remove attribute filter', async () => {
const result = render(FiltersCreationForm);
const result = render(AttributesTypesForm);
expect(result.queryAllByPlaceholderText('Key').length).eq(0);
await fireEvent.click(result.getByRole('button', { name: 'Add attribute filter' }));
expect(result.queryAllByPlaceholderText('Key').length).eq(1);
Expand All @@ -38,7 +38,7 @@ describe('FiltersCreationForm', () => {
});

it('add and remove type filter', async () => {
const result = render(FiltersCreationForm);
const result = render(AttributesTypesForm);
expect(result.queryAllByPlaceholderText('Key').length).eq(0);
await fireEvent.click(result.getByRole('button', { name: 'Add type filter' }));
expect(result.queryAllByPlaceholderText('Key').length).eq(1);
Expand All @@ -47,7 +47,7 @@ describe('FiltersCreationForm', () => {
});

it('validate missing attribute filter key', async () => {
const result = render(FiltersCreationForm);
const result = render(AttributesTypesForm);
result.component.init({}, {});
await fireEvent.click(result.getByRole('button', { name: 'Add attribute filter' }));
expect(result.component.validateFields()).false;
Expand All @@ -56,7 +56,7 @@ describe('FiltersCreationForm', () => {
});

it('validate missing attribute filter value', async () => {
const result = render(FiltersCreationForm);
const result = render(AttributesTypesForm);
result.component.init({}, {});
await fireEvent.click(result.getByRole('button', { name: 'Add attribute filter' }));
await fireEvent.input(result.getByPlaceholderText('Key'), { target: { value: 'my-key' } });
Expand All @@ -66,7 +66,7 @@ describe('FiltersCreationForm', () => {
});

it('validate invalid number', async () => {
const result = render(FiltersCreationForm);
const result = render(AttributesTypesForm);
await fireEvent.click(result.getByRole('button', { name: 'Add attribute filter' }));
await fireEvent.input(result.getByPlaceholderText('Key'), { target: { value: 'my-key' } });
await fireEvent.change(result.getByLabelText('Type'), { target: { value: 'number' } });
Expand All @@ -76,17 +76,47 @@ describe('FiltersCreationForm', () => {
expect(result.getByText('Invalid number')).toBeDefined();
});

it('switch to boolean attribute', async () => {
const result = render(FiltersCreationForm);
it('switch to number attribute from string containing a numeric value (number is preserved)', async () => {
const result = render(AttributesTypesForm);
await fireEvent.click(result.getByRole('button', { name: 'Add attribute filter' }));
await fireEvent.input(result.getByPlaceholderText('Key'), { target: { value: 'my-key' } });
await fireEvent.input(result.getByPlaceholderText('Value'), { target: { value: '42' } });
await fireEvent.change(result.getByLabelText('Type'), { target: { value: 'number' } });
expect(result.getByPlaceholderText('Value').value).eq('42');
expect(result.component.validateFields()).true;
});

it('switch to number attribute from string containing text (number is reset)', async () => {
const result = render(AttributesTypesForm);
await fireEvent.click(result.getByRole('button', { name: 'Add attribute filter' }));
await fireEvent.input(result.getByPlaceholderText('Key'), { target: { value: 'my-key' } });
await fireEvent.input(result.getByPlaceholderText('Value'), { target: { value: 'foo' } });
await fireEvent.change(result.getByLabelText('Type'), { target: { value: 'number' } });
expect(result.getByPlaceholderText('Value').value).eq('');
expect(result.component.validateFields()).false;
});

it('switch to boolean attribute, default to false', async () => {
const result = render(AttributesTypesForm);
await fireEvent.click(result.getByRole('button', { name: 'Add attribute filter' }));
await fireEvent.input(result.getByPlaceholderText('Key'), { target: { value: 'my-key' } });
await fireEvent.change(result.getByLabelText('Type'), { target: { value: 'boolean' } });
expect(result.getByLabelText('Value').value).eq('false');
expect(result.component.validateFields()).true;
});

it('switch to boolean attribute from string equals to "true", true is set', async () => {
const result = render(AttributesTypesForm);
await fireEvent.click(result.getByRole('button', { name: 'Add attribute filter' }));
await fireEvent.input(result.getByPlaceholderText('Key'), { target: { value: 'my-key' } });
await fireEvent.input(result.getByPlaceholderText('Value'), { target: { value: 'true' } });
await fireEvent.change(result.getByLabelText('Type'), { target: { value: 'boolean' } });
expect(result.getByLabelText('Value').value).eq('true');
expect(result.component.validateFields()).true;
});

it('validate duplicated attribute key', async () => {
const result = render(FiltersCreationForm);
const result = render(AttributesTypesForm);
await fireEvent.click(result.getByRole('button', { name: 'Add attribute filter' }));
await fireEvent.input(result.getByPlaceholderText('Key'), { target: { value: 'my-key' } });
await fireEvent.input(result.getByPlaceholderText('Value'), { target: { value: 'foo' } });
Expand All @@ -103,7 +133,7 @@ describe('FiltersCreationForm', () => {
});

it('validate missing type filter key', async () => {
const result = render(FiltersCreationForm);
const result = render(AttributesTypesForm);
result.component.init({}, {});
await fireEvent.click(result.getByRole('button', { name: 'Add type filter' }));
expect(result.component.validateFields()).false;
Expand All @@ -112,7 +142,7 @@ describe('FiltersCreationForm', () => {
});

it('validate duplicated type filter key', async () => {
const result = render(FiltersCreationForm);
const result = render(AttributesTypesForm);
result.component.init({}, {});
await fireEvent.click(result.getByRole('button', { name: 'Add type filter' }));
await fireEvent.input(result.getByPlaceholderText('Key'), { target: { value: 'my-key' } });
Expand Down
2 changes: 1 addition & 1 deletion playwright.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export default defineConfig({

webServer: [
{
command: './tests/start-test-server.sh 2.0.0a8',
command: './tests/start-test-server.sh 2.0.0a10',
port: 8000,
waitForPort: true,
stdout: 'pipe',
Expand Down
5 changes: 0 additions & 5 deletions src/lib/common/selected_api_version.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
import { goto } from "$app/navigation";

export const versionsLabels = {
v1: 'legacy',
v2: 'current'
};

/**
* Save the selected API version in the cookie and reload the page.
* This function is called from the Svelte frontend.
Expand Down
42 changes: 29 additions & 13 deletions src/lib/components/common/jschema/BooleanProperty.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script>
import { getContext } from 'svelte';
import PropertyDescription from '$lib/components/common/jschema/PropertyDescription.svelte';
import { page } from '$app/stores';
const schemaManager = getContext('schemaManager');
Expand All @@ -14,21 +15,36 @@

<div class="d-flex align-items-center p-2">
<div class="property-metadata d-flex flex-row align-self-center w-50">
<span class={schemaProperty.isRequired() ? 'fw-bold' : ''}>{schemaProperty.title || 'Boolean argument'}</span>
<span class={schemaProperty.isRequired() ? 'fw-bold' : ''}>
{schemaProperty.title || 'Boolean argument'}
</span>
<PropertyDescription description={schemaProperty.description} />
</div>
<div class="property-input ms-auto w-25">
<div class="form-check">
<input
id="property-{schemaProperty.key}"
type="checkbox"
bind:checked={schemaProperty.value}
on:change={handleValueChange}
class="form-check-input"
/>
<label class="form-check-label" for="property-{schemaProperty.key}">
{schemaProperty.value}
</label>
</div>
{#if $page.url.pathname.startsWith('/v1')}
<div class="form-check">
<input
id="property-{schemaProperty.key}"
type="checkbox"
bind:checked={schemaProperty.value}
on:change={handleValueChange}
class="form-check-input"
/>
<label class="form-check-label" for="property-{schemaProperty.key}">
{schemaProperty.value}
</label>
</div>
{:else}
<div class="form-check form-switch">
<input
id="property-{schemaProperty.key}"
class="form-check-input"
type="checkbox"
bind:checked={schemaProperty.value}
on:change={handleValueChange}
role="switch"
/>
</div>
{/if}
</div>
</div>
91 changes: 0 additions & 91 deletions src/lib/components/v2/projects/datasets/AddImageModal.svelte

This file was deleted.

Loading

0 comments on commit 4cd7b48

Please sign in to comment.