diff --git a/packages/ui-default/components/problemconfig/ProblemConfigEditor.tsx b/packages/ui-default/components/problemconfig/ProblemConfigEditor.tsx index 15df4898f..934e7b074 100644 --- a/packages/ui-default/components/problemconfig/ProblemConfigEditor.tsx +++ b/packages/ui-default/components/problemconfig/ProblemConfigEditor.tsx @@ -96,7 +96,7 @@ export default connect(mapStateToProps, mapDispatchToProps)(class MonacoEditor e async componentDidMount() { const { monaco } = await load(['yaml']); const uri = monaco.Uri.parse('hydro://problem/file/config.yaml'); - this.model = monaco.editor.createModel(yaml.dump(configYamlFormat(this.props.config)), 'yaml', uri); + this.model = monaco.editor.createModel(yaml.dump(configYamlFormat(this.props.config), { noArrayIndent: true }), 'yaml', uri); this.vjEditor = Editor.getOrConstruct($(this.containerElement), { language: 'yaml', model: this.model, @@ -112,7 +112,7 @@ export default connect(mapStateToProps, mapDispatchToProps)(class MonacoEditor e componentDidUpdate(prevProps) { if (this.__preventUpdate || !this.model || !this.props.config.__valid) return; - if (yaml.dump(prevProps.config) === yaml.dump(this.props.config)) return; + if (yaml.dump(prevProps.config, { noArrayIndent: true }) === yaml.dump(this.props.config, { noArrayIndent: true })) return; const curValue = this.model.getValue(); const pending = configYamlFormat(this.props.config); try { @@ -120,7 +120,7 @@ export default connect(mapStateToProps, mapDispatchToProps)(class MonacoEditor e if (isEqual(curConfig, pending)) return; } catch { } this.__preventFormat = true; - const diff = diffLines(curValue, yaml.dump(pending)); + const diff = diffLines(curValue, yaml.dump(pending, { noArrayIndent: true })); const ops = []; let cursor = 1; for (const line of diff) { diff --git a/packages/ui-default/components/problemconfig/ProblemConfigTree.tsx b/packages/ui-default/components/problemconfig/ProblemConfigTree.tsx index 873e29b3d..f83547190 100644 --- a/packages/ui-default/components/problemconfig/ProblemConfigTree.tsx +++ b/packages/ui-default/components/problemconfig/ProblemConfigTree.tsx @@ -1,4 +1,5 @@ -import { Icon, TreeNode } from '@blueprintjs/core'; +import { Button, Icon, TreeNode } from '@blueprintjs/core'; +import { Popover2 } from '@blueprintjs/popover2'; import { normalizeSubtasks, readSubtasksFromFiles } from '@hydrooj/utils/lib/common'; import { TestCaseConfig } from 'hydrooj'; import { isEqual } from 'lodash'; @@ -19,9 +20,9 @@ interface TestcasesDndItem { export function SubtaskNode(props: { subtaskId: number }) { const { subtaskId } = props; const subtaskIds = useSelector((s: RootState) => Object.values(s.config?.subtasks || []).map((i) => i.id), isEqual); - const clen = useSelector((state: RootState) => (subtaskId === -1 - ? state.config.__cases.length - : state.config.subtasks.find((i) => i.id === subtaskId).cases?.length || 0)); + const cases = useSelector((state: RootState) => (subtaskId === -1 + ? state.config.__cases + : state.config.subtasks.find((i) => i.id === subtaskId).cases || [])); const time = useSelector((s: RootState) => s.config?.time); const memory = useSelector((s: RootState) => s.config?.memory); const dispatch = useDispatch(); @@ -43,13 +44,37 @@ export function SubtaskNode(props: { subtaskId: number }) { }, })); + function deleteSubtask() { + dispatch({ + type: 'problemconfig/moveTestcases', + payload: { + target: -1, + source: subtaskId, + cases, + }, + }); + dispatch({ + type: 'problemconfig/deleteSubtask', + id: subtaskId, + }); + } + return (