Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Skip exit module + regen catalogs #155

Merged
merged 13 commits into from
May 16, 2024
Merged
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

### Changed

* Autosave ([#144](https://github.com/i-VRESSE/workflow-builder/pull/144))
* Improved handling of groups in ui schema
* Nodes with all its properties in a single group is expanded by default

### Fixed

* Hide the exit module ([#153](https://github.com/i-VRESSE/workflow-builder/issues/153))

## @i-vresse/wb-core 2.0.1 - 2024-03-25

### Changed
Expand Down
2 changes: 1 addition & 1 deletion apps/kitchensink/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
"@vitejs/plugin-react": "^2.0.0",
"ts-standard": "^11.0.0",
"ts-standard": "^12.0.2",
"typescript": "^4.7.4",
"vite": "^3.0.4"
},
Expand Down
3 changes: 2 additions & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
"@types/js-yaml": "^4.0.5",
"@types/papaparse": "^5.3.2",
"@types/react-syntax-highlighter": "^13.5.2",
"@vitest/coverage-v8": "^1.5.3",
"babel-loader": "^8.2.5",
"c8": "^7.11.0",
"jsdom": "^20.0.0",
Expand All @@ -59,7 +60,7 @@
"tsup": "^6.1.3",
"typedoc": "^0.23.7",
"vite": "^3.0.4",
"vitest": "^0.20.2"
"vitest": "1.5.3"
},
"dependencies": {
"@dnd-kit/core": "^6.0.5",
Expand Down
84 changes: 83 additions & 1 deletion packages/core/src/grouper.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { groupCatalog, groupParameters, groupSchema, groupUiSchema, unGroupParam
import { ICatalog, IParameters } from './types'

function deepCopy<T> (value: T): T {
return JSON.parse(JSON.stringify(value))
return structuredClone(value)
}

describe('given a schema without any property with ui:group in uiSchema', () => {
Expand Down Expand Up @@ -504,6 +504,88 @@ describe('given a un-grouped prop with same name as group', () => {
})
})

describe('given a prop in own group with same name as group of another prop', () => {
describe('groupSchema()', () => {
it('should make 2 groups each with a prop', () => {
const schema: JSONSchema7 = {
type: 'object',
properties: {
receptor_chains: {
type: 'string'
},
restraints: {
type: 'string'
}
},
additionalProperties: false
}
const uiSchema: UiSchema = {
receptor_chains: {
'ui:group': 'restraints'
},
restraints: {
'ui:group': 'distance restraints'
}
}
const groupedSchema = groupSchema(schema, uiSchema)

const expectedSchema: JSONSchema7 = {
type: 'object',
properties: {
restraints: {
type: 'object',
properties: {
receptor_chains: {
type: 'string'
}
},
additionalProperties: false
},
'distance restraints': {
type: 'object',
properties: {
restraints: {
type: 'string'
}
},
additionalProperties: false
}
},
additionalProperties: false
}
expect(groupedSchema).toEqual(expectedSchema)
})
})

describe('unGroupParameters()', () => {
it('should work', () => {
const groupedParameters = {
restraints: {
receptor_chains: 'val1'
},
'distance restraints': {
restraints: 'val2'
}
}

const actual = unGroupParameters(groupedParameters, {
receptor_chains: {
'ui:group': 'restraints'
},
restraints: {
'ui:group': 'distance restraints'
}
})

const expectedParameters = {
receptor_chains: 'val1',
restraints: 'val2'
}
expect(actual).toEqual(expectedParameters)
})
})
})

describe('given a prop with same name as group and another prop in same group', () => {
describe('groupSchema()', () => {
it('should move property inside object with same name', () => {
Expand Down
57 changes: 39 additions & 18 deletions packages/core/src/grouper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,49 +29,70 @@ export function groupSchema (
schema: JSONSchema7,
uiSchema: UiSchema
): JSONSchema7 {
const newSchema = JSON.parse(JSON.stringify(schema))
const newSchema = structuredClone(schema)

// Handle overlap between groups and direct prop names.
const definedGroups = new Set(
Object.values(uiSchema)
.filter((v) => 'ui:group' in v)
.map((v) => v['ui:group'])
)
const directProps = schema.properties ?? {}
const directPropNamesWithSameNameAsGroup = new Set(
Object.keys(directProps).filter((k) => definedGroups.has(k))
const propsWithGroup = new Set(
Object.keys(uiSchema).filter((k) => 'ui:group' in uiSchema[k])
)
for (const k of directPropNamesWithSameNameAsGroup) {
const propHasGroup =
k in uiSchema && 'ui:group' in uiSchema[k] && 'ui:group' in uiSchema[k]
if (!(propHasGroup && uiSchema[k]['ui:group'] === k)) {
throw new Error(
`Can not have group and un-grouped parameter with same name ${k}`
)
}
// Prop has same name as its group so nest it
const v = newSchema.properties[k]
newSchema.properties[k] = {
const allProps = new Set(Object.keys(schema.properties ?? {}))
const grouplessProps = new Set([...allProps].filter((x) => !propsWithGroup.has(x)))
const grouplessPropsWithSameNameAsGroup = new Set(
[...grouplessProps].filter((x) => definedGroups.has(x))
)
// direct prop with same name as group throw error
if (grouplessPropsWithSameNameAsGroup.size > 0) {
const msg = Array.from(grouplessPropsWithSameNameAsGroup).join(', ')
throw new Error(
`Can not have group and un-grouped parameter with same name ${msg}`
)
}

if (!('properties' in newSchema && typeof newSchema.properties === 'object')) {
return newSchema
}

// prop with group and same name as any group should be nested first
const propsWithSameNameAsAnyGroup = new Set(Object.entries(uiSchema).filter(([k, v]) => 'ui:group' in v && definedGroups.has(k)).map((d) => d[0]))
for (const k of propsWithSameNameAsAnyGroup) {
const prop = newSchema.properties[k]
/* eslint-disable @typescript-eslint/no-dynamic-delete */
delete newSchema.properties[k]
/* eslint-enable @typescript-eslint/no-dynamic-delete */
const group = uiSchema[k]['ui:group']
newSchema.properties[group] = {
type: 'object',
properties: {
[k]: v
[k]: prop
},
additionalProperties: false
}
}

Object.entries(uiSchema).forEach(([k, v]) => {
// TODO recursivly, now only loops over first direct props
if ('ui:group' in v && !directPropNamesWithSameNameAsGroup.has(k)) {
if ('ui:group' in v && !propsWithSameNameAsAnyGroup.has(k)) {
const group = v['ui:group']
if (!('properties' in newSchema && typeof newSchema.properties === 'object')) {
throw new Error('Schema must have properties')
}
if (!(group in newSchema.properties)) {
newSchema.properties[group] = {
type: 'object',
properties: {},
additionalProperties: false
}
}
newSchema.properties[group].properties[k] = newSchema.properties[k]
const newGroup = newSchema.properties[group]
if (typeof newGroup === 'boolean' || newGroup.properties === undefined) {
return
}
newGroup.properties[k] = newSchema.properties[k]
// Remove k as it now is in the group
/* eslint-disable @typescript-eslint/no-dynamic-delete */
delete newSchema.properties[k]
Expand Down
24 changes: 23 additions & 1 deletion packages/core/src/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,27 @@ export function useSelectedNodeFormSchema (): JSONSchema7 | undefined {
return useRecoilValue(selectedNodeFormSchemaState)
}

function expandSingleCollapsibleField (uiSchema: UiSchema): UiSchema {
const nrCollapsibles = Object.values(uiSchema).filter(
(v) => v['ui:field'] === 'collapsible'
).length
if (nrCollapsibles === 1) {
const firstCollapsibleKey = Object.keys(uiSchema).find(
(k) => uiSchema[k]['ui:field'] === 'collapsible'
)
if (firstCollapsibleKey !== undefined) {
return {
...uiSchema,
[firstCollapsibleKey]: {
...uiSchema[firstCollapsibleKey],
'ui:collapsed': false
}
}
}
}
return uiSchema
}

const selectedNodeFormUiSchemaState = selector<UiSchema | undefined>({
key: 'selectedNodeFormUiSchema',
get: ({ get }) => {
Expand All @@ -475,7 +496,8 @@ const selectedNodeFormUiSchemaState = selector<UiSchema | undefined>({
moleculeInfos,
moleculesPropName
)
return uiSchemaWithMolInfo

return expandSingleCollapsibleField(uiSchemaWithMolInfo)
}
})

Expand Down
3 changes: 2 additions & 1 deletion packages/form/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,14 @@
"@storybook/react": "^6.5.9",
"@storybook/testing-library": "^0.0.13",
"@testing-library/react": "12",
"@vitest/coverage-v8": "^1.5.3",
"babel-loader": "^8.2.5",
"jsdom": "^20.0.0",
"postcss": "^8.4.14",
"ts-standard": "^12.0.2",
"tsup": "^6.1.3",
"typedoc": "^0.23.7",
"vitest": "^0.20.2"
"vitest": "^1.5.3"
},
"tsup": {
"entry": [
Expand Down
6 changes: 5 additions & 1 deletion packages/haddock3_catalog/generate_haddock3_catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -430,11 +430,15 @@ def process_level(level_fn: Path, level: str):

broken_modules = {
'topocg', # Gives `AttributeError: module 'haddock.modules.topology.topocg' has no attribute 'HaddockModule'` error
'exit', # Does not make sense to have exit module in the catalog
}
# TODO define module order like category order
# now they are sorted alphabetically
# now they are sorted by insert
nodes = [process_module(module, category, level) for module, category in sorted(modules_category.items()) if module not in broken_modules]

# remove catagories without nodes
categories = [c for c in categories if any(n['category'] == c['name'] for n in nodes)]

catalog = {
"title": f"Haddock 3 on {level} level",
"categories": categories,
Expand Down
Loading
Loading