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

Form autosave #144

Merged
merged 9 commits into from
May 16, 2024
31 changes: 19 additions & 12 deletions apps/haddock3-download/integration-tests/dupheader.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
molecules = [
'some.pdb'
]

[caprieval]

[caprieval]
Expand All @@ -23,30 +23,37 @@
// Upload workflow archive
await page.locator('text="Upload" >> input[type="file"]')
.setInputFiles({ name: 'workflow.zip', mimeType: 'application/zip', buffer: archive.toBuffer() })
})

// Click text=Text
await page.locator('text=Text').click()

test('it should show uplaoded file', async ({ page }) => {
// Click Files tab
await page.locator('text=Files').click()
// validate file button is present
await page.waitForSelector('button:has-text("some.pdb")')
})

test('should have both headers and added index number', async ({ page }) => {
// Click Text tab
await page.locator('text=Text').click()
// debug
// await page.pause()

const highlightedCode = await page.locator('#highlightedcode pre')
const lines = await highlightedCode.allTextContents()
const content = lines.join('\n')
const expected = dedent`

run_dir = 'run1'
molecules = [
'some.pdb',
]

molecules = [
'some.pdb',
]

[caprieval]
run_dir = 'run1'

[caprieval]

['caprieval.2']
['caprieval.2']

`
`
expect(content).toEqual(expected)

Check failure on line 57 in apps/haddock3-download/integration-tests/dupheader.spec.ts

View workflow job for this annotation

GitHub Actions / build

[chromium] › dupheader.spec.ts:35:3 › given an uploaded archive with a workflow.cfg file with a duplicated header › should have both headers and added index number

1) [chromium] › dupheader.spec.ts:35:3 › given an uploaded archive with a workflow.cfg file with a duplicated header › should have both headers and added index number Error: expect(received).toEqual(expected) // deep equality - Expected - 8 + Received + 2 ↵ molecules = [ - 'some.pdb', - ] - - run_dir = 'run1' - - [caprieval] - - ['caprieval.2'] + ] + ↵ 55 | 56 | ` > 57 | expect(content).toEqual(expected) | ^ 58 | }) 59 | }) 60 | at /home/runner/work/workflow-builder/workflow-builder/apps/haddock3-download/integration-tests/dupheader.spec.ts:57:21
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,19 @@ import { test, expect } from '@playwright/test'
test('Verify that [object Object] bug does not show up (issue #74)', async ({ page }) => {
await page.goto('http://localhost:3000')

// debugger
// await page.pause()

// Load the example
await page.locator('text=docking-protein-ligand').click()

// Click 'text' and ensure the files appear
await page.locator('text=Text').click()
// validate that file is used
await page.locator('text=Files').click()
await page.waitForSelector('button:has-text("data/target.pdb")')

// change to 'text' tab
await page.locator('text=Text').click()

// verify that the [object Object] text does not show up
// see https://github.com/i-VRESSE/workflow-builder/issues/74
const highlightedCode = await page.locator('#highlightedcode pre')
Expand Down
30 changes: 21 additions & 9 deletions apps/haddock3-download/integration-tests/topoaamol.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,38 @@ import { readFile } from 'fs/promises'
test.describe('given 1 molecule and a topoaa node', () => {
test.beforeEach(async ({ page }) => {
await page.goto('http://localhost:3000')

// Disable autosave
// await page.locator('text=Autosave').click();

// Click input[type="text"]
await page.locator('input[type="text"]').click()
// Fill input[type="text"]
await page.locator('input[type="text"]').fill('x')
// Upload e2a-hpr_1GGR.pdb
const file1 = await readFile('./integration-tests/data/e2a-hpr_1GGR.pdb')

// Click text=Input MoleculesThe input molecules that will be used for docking. >> button
await page.locator('text=Input MoleculesThe input molecules that will be used for docking. >> button').click()
await page.locator('text=1* >> input[type="file"]')
.setInputFiles({ name: 'e2a-hpr_1GGR.pdb', mimeType: 'chemical/x-pdb', buffer: file1 })
// Click text=Save
await page.locator('button:has-text("Save")').click()
// Click text=Cancel
await page.locator('button:has-text("Cancel")').click()
// Click button:has-text("topoaa")

// add topoaa step to workflow
await page.locator('button:has-text("topoaa")').click()
// select topoaa step
await page.locator('button:has-text("1. topoaa")').click()

// Click #expander4molecule svg
await page.locator('#expander4molecule svg').click()
// Click #expander4input_molecules svg
await page.locator('#expander4input_molecules svg').click()
// Click text=Save
await page.locator('button:has-text("Save")').click()
// Click text=Text
await page.locator('text=Text').click()
// await page.locator('button:has-text("Save")').click()
})

test('should have "[topoaa.mol1]" header', async ({ page }) => {
// select Text tab
await page.locator('text=Text').click()
await expectHighlightedCodeToContain(page, '[topoaa.mol1]')
})

Expand All @@ -41,7 +47,7 @@ test.describe('given 1 molecule and a topoaa node', () => {
// It is important to call waitForEvent before click to set up waiting.
page.waitForEvent('download'),
// Triggers the download.
page.locator('text=Download archive').click()
page.locator('text=Download').click()
])
// wait for download to complete
path = await download.path() ?? ''
Expand All @@ -64,10 +70,16 @@ test.describe('given 1 molecule and a topoaa node', () => {
await page.locator('text="Upload" >> input[type="file"]')
.setInputFiles({ name: 'workflow.zip', mimeType: 'application/zip', buffer: file1 })

// ensure file is uploaded
await page.locator('text=Files').click()
await page.waitForSelector('button:has-text("e2a-hpr_1GGR.pdb")')
})

test('should have "[topoaa.mol1]" header', async ({ page }) => {
// debugger
// await page.pause()
// change to Text tab
await page.locator('text=Text').click()
await expectHighlightedCodeToContain(page, '[topoaa.mol1]')
})
})
Expand Down
3 changes: 2 additions & 1 deletion apps/haddock3-download/src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
grid-template-areas: "head head head"
"catalog workflow node"
"catalog workflow-actions node-actions";
grid-template-columns: min-content minmax(12rem,1fr) minmax(20rem,2fr);
grid-template-columns: min-content minmax(19rem,1fr) minmax(20rem,2fr);
grid-template-rows: auto 1fr auto;
column-gap: 1rem;
}
Expand Down Expand Up @@ -91,6 +91,7 @@ div[role="button"],
display: flex;
gap: 1rem;
padding: 1rem 0rem;
align-items: baseline;
}

/* Show panel section is clickable */
Expand Down
90 changes: 64 additions & 26 deletions apps/haddock3-download/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,40 +9,78 @@ import {
WorkflowDownloadButton,
WorkflowPanel,
WorkflowUploadButton,
Wrapper
Wrapper,
useAutosaveValue,
useSetAutosave
} from '@i-vresse/wb-core'

import '@i-vresse/wb-form/dist/index.css'
import './App.css'

function App (): JSX.Element {
function AutosaveManagement (): JSX.Element {
const autosave = useAutosaveValue()
const setAutosave = useSetAutosave()

return (
<Wrapper>
<div className='page'>
<GridArea area='head'>
<Header />
</GridArea>
<GridArea area='catalog'>
<CatalogPanel>
<CatalogPicker />
</CatalogPanel>
</GridArea>
<GridArea area='workflow' className='workflow-area'>
<WorkflowPanel>
<WorkflowUploadButton />
</WorkflowPanel>
</GridArea>
<GridArea area='node'>
<NodePanel />
</GridArea>
<GridArea className='action-row' area='workflow-actions'>
<div
className='form-group form-check'
>
<input
type='checkbox'
className='form-check-input'
id='autosave'
checked={autosave}
onChange={(e) => {
setAutosave(!autosave)
}}
/>
<label
className='form-check-label'
htmlFor='autosave'
>
Autosave
</label>
</div>
)
}

function PageContent (): JSX.Element {
const autosave = useAutosaveValue()
console.group('PageContent')
console.log('autosave...', autosave)
console.groupEnd()

return (
<div className='page'>
<GridArea area='head'>
<Header />
</GridArea>
<GridArea area='catalog'>
<CatalogPanel>
<CatalogPicker />
</CatalogPanel>
</GridArea>
<GridArea area='workflow' className='workflow-area'>
<WorkflowPanel>
<WorkflowDownloadButton />
<WorkflowUploadButton />
<WorkflowClear />
</GridArea>
<GridArea className='action-row' area='node-actions'>
<FormActions />
</GridArea>
</div>
<AutosaveManagement />
</WorkflowPanel>
</GridArea>
<GridArea area='node'>
<NodePanel />
{/* show form actions if autosave is OFF */}
{!autosave ? <FormActions /> : null}
</GridArea>
</div>
)
}

function App (): JSX.Element {
return (
<Wrapper>
<PageContent />
</Wrapper>
)
}
Expand Down
11 changes: 5 additions & 6 deletions packages/core/src/CatalogCategory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,16 @@ export const CatalogCategory = ({ name, description, collapsed: initiallyCollaps
const style = {
// TODO On https://developer.mozilla.org/en-US/docs/Web/CSS/list-style-type
// disclosure-open/closed are said to be experimental, find how much compatibility there is.
listStyleType: collapsed ? 'disclosure-closed' : 'disclosure-open'
listStyleType: collapsed ? 'disclosure-closed' : 'disclosure-open',
cursor: 'pointer'
// utf failed in chrome
// listStyleType: collapsed ? '⏷' : '⏵'
}
return (
<li
style={style} onClick={(e) => {
if (e.target === e.currentTarget) {
// only toggle when list marker is clicked
return setCollapsed((c) => !c)
}
style={style}
onClick={(e) => {
setCollapsed((c) => !c)
}}
>
<span title={description}>{name}</span>
Expand Down
7 changes: 6 additions & 1 deletion packages/core/src/CatalogNode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,12 @@ export const CatalogNode = ({ id, label }: ICatalogNode): JSX.Element => {
{...attributes}
title={label}
className='btn btn-light btn-sm btn-catalog-node'
onClick={() => addNodeToWorkflow(id)}
onClick={(e) => {
// prevent bubbling click even to parent which toggles the group
e.stopPropagation()
// add node to workflow
addNodeToWorkflow(id)
}}
>
<span>{id}</span>
<div
Expand Down
19 changes: 17 additions & 2 deletions packages/core/src/FilesList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,31 @@ import { useFiles } from './store'

export const FilesList = (): JSX.Element => {
const files = useFiles()
const fileList = Object.keys(files)

function downloadFile (filename: string): void {
saveAs(files[filename], filename)
}

if (fileList?.length === 0) {
return (
<div style={{
padding: '0.5rem'
}}
>
<h5>No files to show</h5>
dmijatovic marked this conversation as resolved.
Show resolved Hide resolved
</div>
)
}

return (
<div>
<div style={{
padding: '0.5rem'
}}
>
<h5>Files</h5>
dmijatovic marked this conversation as resolved.
Show resolved Hide resolved
<ul>
{Object.keys(files).map(filename =>
{fileList.map(filename =>
<li key={filename}><button className='btn btn-link' onClick={() => downloadFile(filename)}>{filename}</button></li>
)}
</ul>
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/FormActions.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ export const NothingSelected: ComponentStory<typeof FormActions> = () => {

export const GlobalParametersSelected: ComponentStory<typeof FormActions> =
() => {
const { toggleGlobalEdit } = useWorkflow()
const { setEditingGlobal } = useWorkflow()
const submitFormRefSetter = useSetActiveSubmitButton()
useEffect(toggleGlobalEdit, [])
useEffect(() => setEditingGlobal(true), [])
return (
<>
<button ref={submitFormRefSetter} style={{ display: 'none' }} />
Expand Down
16 changes: 4 additions & 12 deletions packages/core/src/FormActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,15 @@ import { useSelectNodeIndex, useActiveSubmitButton, useWorkflow } from './store'
* )
* ```
* The FormActions component will use `submitFormRefSetter` to submit form.
*
* For example to render the actions when global parameter editing is selected do
*
* ```js
* import { useWorkflow } from '@i-vresse/wb-core/dist/store'
*
* const { toggleGlobalEdit } = useWorkflow()
* toggleGlobalEdit()
* ```
*/
export const FormActions = (): JSX.Element => {
export const FormActions = (): JSX.Element|null => {
const index = useSelectNodeIndex()
const { deleteNode, clearNodeSelection } = useWorkflow()
const submitFormRef = useActiveSubmitButton()
const { editingGlobal, toggleGlobalEdit } = useWorkflow()
const { editingGlobal, setEditingGlobal } = useWorkflow()
if (submitFormRef === undefined || !(index > -1 || editingGlobal)) {
return <></>
return null
}
const DeleteButton = (
<button
Expand All @@ -62,7 +54,7 @@ export const FormActions = (): JSX.Element => {
</button>
<button
className='btn btn-light'
onClick={() => editingGlobal ? toggleGlobalEdit() : clearNodeSelection()}
onClick={() => editingGlobal ? setEditingGlobal(false) : clearNodeSelection()}
title='Forget changes made in form'
>
Cancel
Expand Down
Loading
Loading