Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build/prepare.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ const configFlat = (name) => ({
],
},
},
include: ['**/*.ts'],
include: ['**/*.ts', '**/*.tsx'],
exclude,
});

Expand Down
12 changes: 7 additions & 5 deletions packages/components/frontend/autocomplete/AutoComplete.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -310,18 +310,20 @@ const AutoComplete = forwardRef(function Impl<T>(props: AutoCompleteProps<T>, re
)}
{focused && itemList.length > 0 && (
<ul ref={listRef} className="autocomplete-list" style={listStyle} onMouseDown={(e) => e.preventDefault()}>
{itemList.map((item, idx) => (
<li
{itemList.map((item, idx) => {
const inner = renderItem(item);
if (!inner) return null;
return <li
key={itemKey(item)}
onClick={() => toggleItem(item)}
onMouseMove={() => setCurrentItem(idx)}
data-selected={selectedKeys.includes(itemKey(item))}
data-focus={idx === currentItem}
>
<div>{renderItem(item)}</div>
<div>{inner}</div>
{selectedKeys.includes(itemKey(item)) && <Icon name="check" />}
</li>
))}
</li>;
})}
</ul>
)}
</div>
Expand Down
5 changes: 3 additions & 2 deletions packages/hydrooj/src/handler/contest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -305,11 +305,12 @@ export class ContestEditHandler extends Handler {
@param('contestDuration', Types.Float, true)
@param('maintainer', Types.NumericArray, true)
@param('allowViewCode', Types.Boolean)
@param('langs', Types.CommaSeperatedArray, true)
async postUpdate(
domainId: string, tid: ObjectId, beginAtDate: string, beginAtTime: string, duration: number,
title: string, content: string, rule: string, _pids: string, rated = false,
_code = '', autoHide = false, assign: string[] = [], lock: number = null,
contestDuration: number = null, maintainer: number[] = [], allowViewCode = false,
contestDuration: number = null, maintainer: number[] = [], allowViewCode = false, langs: string[] = [],
) {
if (autoHide) this.checkPerm(PERM.PERM_EDIT_PROBLEM);
const pids = _pids.replace(/,/g, ',').split(',').map((i) => +i).filter((i) => i);
Expand Down Expand Up @@ -350,7 +351,7 @@ export class ContestEditHandler extends Handler {
});
}
await contest.edit(domainId, tid, {
assign, _code, autoHide, lockAt, maintainer, allowViewCode,
assign, _code, autoHide, lockAt, maintainer, allowViewCode, langs,
});
this.response.body = { tid };
this.response.redirect = this.url('contest_detail', { tid });
Expand Down
4 changes: 3 additions & 1 deletion packages/hydrooj/src/handler/homework.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,11 +191,12 @@ class HomeworkEditHandler extends Handler {
@param('rated', Types.Boolean)
@param('maintainer', Types.NumericArray, true)
@param('assign', Types.CommaSeperatedArray, true)
@param('langs', Types.CommaSeperatedArray, true)
async postUpdate(
domainId: string, tid: ObjectId, beginAtDate: string, beginAtTime: string,
penaltySinceDate: string, penaltySinceTime: string, extensionDays: number,
penaltyRules: PenaltyRules, title: string, content: string, _pids: string, rated = false,
maintainer: number[] = [], assign: string[] = [],
maintainer: number[] = [], assign: string[] = [], langs: string[] = [],
) {
const pids = _pids.replace(/,/g, ',').split(',').map((i) => +i).filter((i) => i);
const tdoc = tid ? await contest.get(domainId, tid) : null;
Expand Down Expand Up @@ -226,6 +227,7 @@ class HomeworkEditHandler extends Handler {
rated,
maintainer,
assign,
langs,
});
if (tdoc.beginAt !== beginAt.toDate()
|| tdoc.endAt !== endAt.toDate()
Expand Down
1 change: 1 addition & 0 deletions packages/hydrooj/src/handler/problem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ export class ProblemDetailHandler extends ContestDetailBaseHandler {
if (this.pdoc.config.langs) t.push(this.pdoc.config.langs);
if (ddoc.langs) t.push(ddoc.langs.split(',').map((i) => i.trim()).filter((i) => i));
if (this.domain.langs) t.push(this.domain.langs.split(',').map((i) => i.trim()).filter((i) => i));
if (this.tdoc?.langs) t.push(this.tdoc.langs);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also need check if tdoc.langs.length > 0, or none language can be submited.

if (this.pdoc.config.type === 'remote_judge') {
const p = this.pdoc.config.subType;
const dl = Object.keys(setting.langs).filter((i) => i.startsWith(`${p}.`) || setting.langs[i].validAs[p]);
Expand Down
1 change: 1 addition & 0 deletions packages/hydrooj/src/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ export interface Tdoc extends Document {
autoHide?: boolean;
balloon?: Record<number, string | { color: string, name: string }>;
score?: Record<number, number>;
langs?: string[];

/**
* In hours
Expand Down
Original file line number Diff line number Diff line change
@@ -1,55 +1,25 @@
import { CustomSelectAutoComplete as CustomSelectAutoCompleteFC } from '@hydrooj/components';
import React from 'react';
import AutoComplete, { AutoCompleteOptions } from '.';

interface CustomSelectOptions {
data: any[]
}

const Component = React.forwardRef<any, any>((props, ref) => {
const [value, setValue] = React.useState(props.value);
return (
<CustomSelectAutoCompleteFC
ref={ref as any}
height="auto"
selectedKeys={value.split(',').map((i) => i.trim()).filter((i) => i)}
onChange={(v) => {
setValue(v);
props.onChange(v);
}}
data={props.data}
multi={props.multi}
/>
);
});

export default class CustomSelectAutoComplete<Multi extends boolean> extends AutoComplete<CustomSelectOptions> {
static DOMAttachKey = 'ucwCustomSelectAutoCompleteInstance';

constructor($dom, options: CustomSelectOptions & AutoCompleteOptions<Multi>) {
super($dom, {
classes: 'custom-select',
component: CustomSelectAutoCompleteFC,
props: {
data: options.data,
multi: options.multi,
height: 'auto',
},
...options,
});
}

value(): Multi extends true ? number[] : string {
if (this.options.multi) return this.ref?.getSelectedItemKeys().map((i) => +i) ?? this.$dom.val();
return this.ref?.getSelectedItems()[0] ?? null;
}

attach() {
const value = this.$dom.val();
this.component.render(
<Component
ref={(ref) => { this.ref = ref; }}
data={this.options.data}
value={value}
multi={this.options.multi}
onChange={this.onChange}
/>,
);
}
}

window.Hydro.components.CustomSelectAutoComplete = CustomSelectAutoComplete;
Original file line number Diff line number Diff line change
@@ -1,42 +1,20 @@
import React from 'react';
import AutoComplete from '.';
import DomainSelectAutoCompleteFC from './components/DomainSelectAutoComplete';

const Component = React.forwardRef((props: { value: string, multi: boolean, onChange: (v: string) => void }, ref) => {
const [value, setValue] = React.useState(props.value ?? '');
return (
<DomainSelectAutoCompleteFC
ref={ref as any}
height="34px"
selectedKeys={value.split(',').map((i) => i.trim()).filter((i) => i)}
onChange={(v) => {
setValue(v);
props.onChange(v);
}}
multi={props.multi}
/>
);
});

export default class DomainSelectAutoComplete extends AutoComplete {
static DOMAttachKey = 'ucwDomainSelectAutoCompleteInstance';

constructor($dom, options) {
super($dom, {
classes: 'domain-select',
component: DomainSelectAutoCompleteFC,
props: {
multi: options.multi,
height: '34px',
},
...options,
});
}

attach() {
const value = this.$dom.val();
this.component.render(<Component
ref={(ref) => { this.ref = ref; }}
value={value}
onChange={this.onChange}
multi={this.options.multi}
/>);
}
}

window.Hydro.components.DomainSelectAutoComplete = DomainSelectAutoComplete;
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import React from 'react';
import AutoComplete, { AutoCompleteOptions } from '.';
import FileSelectAutoCompleteFC from './components/FileSelectAutoComplete';

Expand All @@ -9,50 +8,21 @@ interface FileSelectOptions {
}[];
}

const Component = React.forwardRef<any, any>((props, ref) => {
const [value, setValue] = React.useState(props.value);
return (
<FileSelectAutoCompleteFC
ref={ref as any}
height="auto"
selectedKeys={value.split(',').map((i) => i.trim()).filter((i) => i)}
onChange={(v) => {
setValue(v);
props.onChange(v);
}}
data={props.data}
multi={props.multi}
/>
);
});

export default class FileSelectAutoComplete<Multi extends boolean> extends AutoComplete<FileSelectOptions> {
static DOMAttachKey = 'ucwFileSelectAutoCompleteInstance';

constructor($dom, options: FileSelectOptions & AutoCompleteOptions<Multi>) {
super($dom, {
classes: 'custom-select',
classes: 'file-select',
component: FileSelectAutoCompleteFC,
props: {
data: options.data,
multi: options.multi,
height: 'auto',
},
...options,
});
}

value(): Multi extends true ? number[] : string {
if (this.options.multi) return this.ref?.getSelectedItemKeys().map((i) => +i) ?? this.$dom.val();
return this.ref?.getSelectedItems()[0] ?? null;
}

attach() {
const value = this.$dom.val();
this.component.render(
<Component
ref={(ref) => { this.ref = ref; }}
data={this.options.data}
value={value}
multi={this.options.multi}
onChange={this.onChange}
/>,
);
}
}

window.Hydro.components.FileSelectAutoComplete = FileSelectAutoComplete;
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import AutoComplete, { AutoCompleteOptions } from '.';
import LanguageSelectAutoCompleteFC from './components/LanguageSelectAutoComplete';

interface LanguageSelectOptions {
multi?: boolean;
withAuto?: boolean;
}

export class LanguageSelectAutoComplete<Multi extends boolean> extends AutoComplete<LanguageSelectOptions> {
static DOMAttachKey = 'ucwLanguageSelectAutoCompleteInstance';

constructor($dom, options: LanguageSelectOptions & AutoCompleteOptions<Multi>) {
super($dom, {
classes: 'language-select',
component: LanguageSelectAutoCompleteFC,
props: {
multi: options.multi,
withAuto: options.withAuto,
height: 'auto',
},
...options,
});
}
}

window.Hydro.components.LanguageSelectAutoComplete = LanguageSelectAutoComplete;
Original file line number Diff line number Diff line change
@@ -1,44 +1,20 @@
import React from 'react';
import AutoComplete from '.';
import ProblemSelectAutoCompleteFC from './components/ProblemSelectAutoComplete';

const Component = React.forwardRef<any, any>((props, ref) => {
const [value, setValue] = React.useState(props.value ?? '');
return (
<ProblemSelectAutoCompleteFC
ref={ref as any}
height="auto"
selectedKeys={value.split(',').map((i) => i.trim()).filter((i) => i)}
onChange={(v) => {
setValue(v);
props.onChange(v);
}}
multi={props.multi}
/>
);
});

export default class ProblemSelectAutoComplete extends AutoComplete {
static DOMAttachKey = 'ucwProblemSelectAutoCompleteInstance';

constructor($dom, options) {
super($dom, {
classes: 'problem-select',
component: ProblemSelectAutoCompleteFC,
props: {
multi: options.multi,
height: 'auto',
},
...options,
});
}

attach() {
const value = this.$dom.val();
this.component.render(
<Component
ref={(ref) => { this.ref = ref; }}
value={value}
multi={this.options.multi}
onChange={this.onChange}
/>,
);
}
}

window.Hydro.components.ProblemSelectAutoComplete = ProblemSelectAutoComplete;
Original file line number Diff line number Diff line change
@@ -1,29 +1,17 @@
import React from 'react';
import AutoComplete, { AutoCompleteOptions } from '.';
import UserSelectAutoCompleteFC from './components/UserSelectAutoComplete';

const Component = React.forwardRef<any, any>((props, ref) => {
const [value, setValue] = React.useState(props.value ?? '');
return (
<UserSelectAutoCompleteFC
ref={ref as any}
height="auto"
selectedKeys={value.split(',').map((i) => i.trim()).filter((i) => i)}
onChange={(v) => {
setValue(v);
props.onChange(v);
}}
multi={props.multi}
/>
);
});

export default class UserSelectAutoComplete<Multi extends boolean> extends AutoComplete {
static DOMAttachKey = 'ucwUserSelectAutoCompleteInstance';

constructor($dom, options: AutoCompleteOptions<Multi>) {
super($dom, {
classes: 'user-select',
component: UserSelectAutoCompleteFC,
props: {
multi: options.multi,
height: 'auto',
},
...options,
});
}
Expand All @@ -32,18 +20,6 @@ export default class UserSelectAutoComplete<Multi extends boolean> extends AutoC
if (this.options.multi) return this.ref?.getSelectedItemKeys().map((i) => +i) ?? this.$dom.val();
return this.ref?.getSelectedItems()[0] ?? null;
}

attach() {
const value = this.$dom.val();
this.component.render(
<Component
ref={(ref) => { this.ref = ref; }}
value={value}
multi={this.options.multi}
onChange={this.onChange}
/>,
);
}
}

window.Hydro.components.UserSelectAutoComplete = UserSelectAutoComplete;
Loading
Loading