-
-
Notifications
You must be signed in to change notification settings - Fork 470
core&ui: contest can limit submission language #1007
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
Changes from 7 commits
f21c6ea
51f7a66
2617b47
102bbac
eff7801
da38fa5
33281bf
2ad088f
bb011cc
b461eb1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,45 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import React from 'react'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import AutoComplete from '.'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import LanguageSelectAutoCompleteFC from './components/LanguageSelectAutoComplete'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const Component = React.forwardRef<any, any>((props, ref) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [value, setValue] = React.useState(props.value ?? ''); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <LanguageSelectAutoCompleteFC | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 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} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| allowEmptyQuery={true} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Improve value parsing robustness and error handling. The current value splitting logic may fail with malformed input and lacks error handling for the onChange callback. const Component = React.forwardRef<any, any>((props, ref) => {
- const [value, setValue] = React.useState(props.value ?? '');
+ const [value, setValue] = React.useState(() => {
+ const initialValue = props.value ?? '';
+ return typeof initialValue === 'string' ? initialValue : String(initialValue);
+ });
+
+ const parseValue = (val: string) => {
+ if (!val || typeof val !== 'string') return [];
+ return val.split(',').map((i) => i.trim()).filter((i) => i);
+ };
+
return (
<LanguageSelectAutoCompleteFC
ref={ref as any}
height="auto"
- selectedKeys={value.split(',').map((i) => i.trim()).filter((i) => i)}
+ selectedKeys={parseValue(value)}
onChange={(v) => {
- setValue(v);
- props.onChange(v);
+ try {
+ setValue(v);
+ props.onChange?.(v);
+ } catch (error) {
+ console.error('Error in LanguageSelectAutoComplete onChange:', error);
+ }
}}
multi={props.multi}
allowEmptyQuery={true}
/>
);
});📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export default class LanguageSelectAutoComplete extends AutoComplete { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| static DOMAttachKey = 'ucwLanguageSelectAutoCompleteInstance'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| constructor($dom, options) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| super($dom, { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| classes: 'language-select', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ...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.LanguageSelectAutoComplete = LanguageSelectAutoComplete; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| import { AutoComplete, AutoCompleteHandle, AutoCompleteProps } from '@hydrooj/components'; | ||
| import PropTypes from 'prop-types'; | ||
| import React, { forwardRef } from 'react'; | ||
|
|
||
| interface LanguageFakeDoc { | ||
| _id: string | ||
| name: string | ||
| } | ||
|
|
||
| const getLanguagesDocList = (): LanguageFakeDoc[] => { | ||
| try { | ||
| if (!window.LANGS || typeof window.LANGS !== 'object') { | ||
| console.error('window.LANGS is not available or invalid'); | ||
| return []; | ||
| } | ||
|
|
||
| const prefixes = new Set( | ||
| Object.keys(window.LANGS) | ||
| .filter((i) => i.includes('.')) | ||
| .map((i) => i.split('.')[0]), | ||
| ); | ||
|
|
||
| return Object.keys(window.LANGS) | ||
| .filter((i) => !prefixes.has(i)) | ||
| .map((i) => ({ | ||
| name: `${i.includes('.') ? `${window.LANGS[i.split('.')[0]].display || ''}/` : ''}${window.LANGS[i].display}`, | ||
| _id: i, | ||
| })); | ||
| } catch (error) { | ||
| console.error('Error processing languages:', error); | ||
| return []; | ||
| } | ||
| }; | ||
|
|
||
| const LanguageSelectAutoComplete = forwardRef<AutoCompleteHandle<LanguageFakeDoc>, AutoCompleteProps<LanguageFakeDoc>>((props, ref) => ( | ||
| <AutoComplete<LanguageFakeDoc> | ||
| ref={ref as any} | ||
| cacheKey={`language-${UiContext.domainId}`} | ||
| queryItems={async (query) => { | ||
| const q = query.toLocaleLowerCase(); | ||
| return getLanguagesDocList().filter((el) => | ||
| el._id.toLocaleLowerCase().includes(q) || el.name.toLocaleLowerCase().includes(q), | ||
| ); | ||
| }} | ||
| fetchItems={async (ids) => getLanguagesDocList().filter((el) => ids.includes(el._id))} | ||
| itemText={(pdoc) => pdoc.name} | ||
| itemKey={(pdoc) => pdoc._id} | ||
| renderItem={(pdoc) => ( | ||
| <div className="media"> | ||
| <div className="media__body medium"> | ||
| <div className="language-select__name">{pdoc.name}</div> | ||
| <div className="language-select__id">{pdoc._id}</div> | ||
| </div> | ||
| </div> | ||
| )} | ||
| {...{ | ||
| width: '100%', | ||
| height: 'auto', | ||
| listStyle: {}, | ||
| multi: false, | ||
| selectedKeys: [], | ||
| allowEmptyQuery: false, | ||
| freeSolo: false, | ||
| freeSoloConverter: (input) => input, | ||
| ...props, | ||
| }} | ||
| /> | ||
| )); | ||
|
|
||
| LanguageSelectAutoComplete.propTypes = { | ||
| width: PropTypes.string, | ||
| height: PropTypes.string, | ||
| listStyle: PropTypes.object, | ||
| onChange: PropTypes.func.isRequired, | ||
| multi: PropTypes.bool, | ||
| selectedKeys: PropTypes.arrayOf(PropTypes.string), | ||
| allowEmptyQuery: PropTypes.bool, | ||
| freeSolo: PropTypes.bool, | ||
| freeSoloConverter: PropTypes.func, | ||
| }; | ||
|
|
||
| LanguageSelectAutoComplete.displayName = 'LanguageSelectAutoComplete'; | ||
|
|
||
| export default LanguageSelectAutoComplete; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: after this filter, objective or submit_answer problem will have empty langList.
Will be fixed in next commit.