This is an automated email from the ASF dual-hosted git repository. mintsweet pushed a commit to branch refactor-6307 in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git
commit 572c6310e25caed748793d07c208d0e1f37b6cae Author: mintsweet <[email protected]> AuthorDate: Thu Dec 14 17:26:06 2023 +1300 refactor(config-ui): use new ui select to replace selector --- config-ui/src/components/index.ts | 1 - config-ui/src/components/selector/index.ts | 20 --- .../components/selector/multi-selector/index.tsx | 147 --------------------- .../src/components/selector/selector/index.tsx | 91 ------------- .../plugins/components/data-scope-select/index.tsx | 19 ++- .../plugins/components/scope-config-form/index.tsx | 16 +-- .../plugins/register/bitbucket/transformation.tsx | 54 ++++---- .../src/plugins/register/jira/transformation.tsx | 91 +++++++------ .../src/plugins/register/tapd/transformation.tsx | 106 ++++++--------- config-ui/src/routes/api-keys/api-keys.tsx | 23 ++-- 10 files changed, 142 insertions(+), 426 deletions(-) diff --git a/config-ui/src/components/index.ts b/config-ui/src/components/index.ts index 707c3506d..143c30b7f 100644 --- a/config-ui/src/components/index.ts +++ b/config-ui/src/components/index.ts @@ -24,5 +24,4 @@ export * from './logo'; export * from './message'; export * from './no-data'; export * from './page-header'; -export * from './selector'; export * from './tooltip'; diff --git a/config-ui/src/components/selector/index.ts b/config-ui/src/components/selector/index.ts deleted file mode 100644 index eb2f71e3d..000000000 --- a/config-ui/src/components/selector/index.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -export * from './selector'; -export * from './multi-selector'; diff --git a/config-ui/src/components/selector/multi-selector/index.tsx b/config-ui/src/components/selector/multi-selector/index.tsx deleted file mode 100644 index 4d48c6c4b..000000000 --- a/config-ui/src/components/selector/multi-selector/index.tsx +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { useState, useEffect, useMemo } from 'react'; -import { MenuItem, Checkbox, Intent } from '@blueprintjs/core'; -import { MultiSelect2 } from '@blueprintjs/select'; -import { useDebounce } from 'ahooks'; - -interface Props<T> { - placeholder?: string; - loading?: boolean; - disabled?: boolean; - items: T[]; - disabledItems?: T[]; - getKey?: (item: T) => string | number; - getName?: (item: T) => string; - getIcon?: (item: T) => string; - selectedItems?: T[]; - onChangeItems?: (selectedItems: T[]) => void; - noResult?: string; - onQueryChange?: (query: string) => void; -} - -export const MultiSelector = <T,>({ - placeholder, - loading = false, - disabled = false, - items, - disabledItems = [], - getKey = (it) => it as string, - getName = (it) => it as string, - getIcon, - onChangeItems, - noResult = 'No results found.', - onQueryChange, - ...props -}: Props<T>) => { - const [selectedItems, setSelectedItems] = useState<T[]>([]); - const [query, setQuery] = useState(''); - const search = useDebounce(query, { wait: 500 }); - - const filteredItems = useMemo( - () => - items.filter((it) => { - const name = getName(it); - return name.toLocaleLowerCase().includes(search.toLocaleLowerCase()); - }), - [items, search], - ); - - useEffect(() => { - setSelectedItems(props.selectedItems ?? []); - }, [props.selectedItems]); - - const tagRenderer = (item: T) => { - const name = getName(item); - return <span>{name}</span>; - }; - - const itemRenderer = (item: T, { handleClick }: any) => { - const key = getKey(item); - const name = getName(item); - const icon = getIcon?.(item); - const selected = !!selectedItems.find((it) => getKey(it) === key); - const disabled = !!disabledItems.find((it) => getKey(it) === key); - - return ( - <MenuItem - key={key} - disabled={selected || disabled} - onClick={(e) => { - e.preventDefault(); - handleClick(); - }} - labelElement={icon ? <img src={icon} width={16} alt="" /> : null} - text={<Checkbox disabled={selected || disabled} checked={selected || disabled} readOnly label={name} />} - /> - ); - }; - - const handleItemSelect = (item: T) => { - const newSelectedItems = [...selectedItems, item]; - if (onChangeItems) { - onChangeItems(newSelectedItems); - } else { - setSelectedItems(newSelectedItems); - } - }; - - const handleItemRemove = (item: T) => { - const newSelectedItems = selectedItems.filter((it) => getKey(it) !== getKey(item)); - if (onChangeItems) { - onChangeItems(newSelectedItems); - } else { - setSelectedItems(newSelectedItems); - } - }; - - const handleQueryChange = (query: string) => { - if (onQueryChange && query) { - onQueryChange(query); - } else { - setQuery(query); - } - }; - - return ( - <MultiSelect2 - disabled={disabled} - resetOnSelect - fill - placeholder={placeholder ?? 'Select...'} - items={filteredItems} - // https://github.com/palantir/blueprint/issues/3596 - // set activeItem to null will fixed the scrollBar to top when the selectedItems changed - activeItem={null} - selectedItems={selectedItems} - itemRenderer={itemRenderer} - tagRenderer={tagRenderer} - tagInputProps={{ - tagProps: { - intent: Intent.PRIMARY, - minimal: true, - }, - }} - onItemSelect={handleItemSelect} - onRemove={handleItemRemove} - onQueryChange={handleQueryChange} - noResults={<MenuItem disabled={true} text={loading ? 'Fetching...' : noResult} />} - /> - ); -}; diff --git a/config-ui/src/components/selector/selector/index.tsx b/config-ui/src/components/selector/selector/index.tsx deleted file mode 100644 index e425c5139..000000000 --- a/config-ui/src/components/selector/selector/index.tsx +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { useState, useEffect, useMemo } from 'react'; -import { MenuItem, Button, Alignment } from '@blueprintjs/core'; -import { Select2 } from '@blueprintjs/select'; - -interface Props<T> { - items: T[]; - disabledItems?: T[]; - getKey?: (item: T) => ID; - getName?: (item: T) => string; - getIcon?: (item: T) => string; - selectedItem?: T; - onChangeItem?: (selectedItem: T) => void; -} - -export const Selector = <T,>({ - items, - disabledItems = [], - getKey = (it) => it as string, - getName = (it) => it as string, - getIcon, - onChangeItem, - ...props -}: Props<T>) => { - const [selectedItem, setSelectedItem] = useState<T>(); - - useEffect(() => { - setSelectedItem(props.selectedItem); - }, [props.selectedItem]); - - const btnText = useMemo(() => (selectedItem ? getName(selectedItem) : 'Select...'), [selectedItem]); - - const itemPredicate = (query: string, item: T) => { - const name = getName(item); - return name.toLowerCase().indexOf(query.toLowerCase()) >= 0; - }; - - const itemRenderer = (item: T, { handleClick }: any) => { - const key = getKey(item); - const name = getName(item); - const icon = getIcon?.(item) ?? null; - const disabled = !!disabledItems.find((it) => getKey(it) === getKey(item)) || selectedItem === item; - - return ( - <MenuItem - key={key} - disabled={disabled} - text={<span>{name}</span>} - icon={icon ? <img src={icon} alt="" width={20} /> : null} - onClick={handleClick} - /> - ); - }; - - const handleItemSelect = (item: T) => { - if (onChangeItem) { - onChangeItem(item); - } else { - setSelectedItem(item); - } - }; - - return ( - <Select2 - items={items} - activeItem={selectedItem} - itemPredicate={itemPredicate} - itemRenderer={itemRenderer} - onItemSelect={handleItemSelect} - > - <Button outlined fill alignText={Alignment.LEFT} rightIcon="caret-down" text={btnText} /> - </Select2> - ); -}; diff --git a/config-ui/src/plugins/components/data-scope-select/index.tsx b/config-ui/src/plugins/components/data-scope-select/index.tsx index f9bf2254e..3f1e86092 100644 --- a/config-ui/src/plugins/components/data-scope-select/index.tsx +++ b/config-ui/src/plugins/components/data-scope-select/index.tsx @@ -17,14 +17,14 @@ */ import { useState, useEffect, useMemo } from 'react'; -import { Flex } from 'antd'; +import { Flex, Select } from 'antd'; import { Button, Intent } from '@blueprintjs/core'; import { useDebounce } from 'ahooks'; import type { McsItem } from 'miller-columns-select'; import MillerColumnsSelect from 'miller-columns-select'; import API from '@/api'; -import { Loading, Block, ExternalLink, Message, MultiSelector } from '@/components'; +import { Loading, Block, ExternalLink, Message } from '@/components'; import { useRefreshData } from '@/hooks'; import { getPluginScopeId } from '@/plugins'; @@ -133,15 +133,14 @@ export const DataScopeSelect = ({ <Button intent={Intent.PRIMARY} icon="refresh" text="Refresh Data Scope" /> </Flex> )} - <MultiSelector + <Select loading={!ready} - items={searchItems} - getName={(it) => it.name} - getKey={(it) => getPluginScopeId(plugin, it)} - noResult="No Data Scopes Available." - onQueryChange={(query) => setQuery(query)} - selectedItems={searchItems.filter((it) => selectedIds.includes(getPluginScopeId(plugin, it)))} - onChangeItems={(selectedItems) => setSelectedIds(selectedItems.map((it) => getPluginScopeId(plugin, it)))} + showSearch + mode="multiple" + options={searchItems.map((it) => ({ label: it.fullName, value: getPluginScopeId(plugin, it) }))} + value={selectedIds} + onChange={(value) => setSelectedIds(value)} + onSearch={(value) => setQuery(value)} /> <MillerColumnsSelect showSelectAll diff --git a/config-ui/src/plugins/components/scope-config-form/index.tsx b/config-ui/src/plugins/components/scope-config-form/index.tsx index abb6c18db..4d1be1e88 100644 --- a/config-ui/src/plugins/components/scope-config-form/index.tsx +++ b/config-ui/src/plugins/components/scope-config-form/index.tsx @@ -18,11 +18,11 @@ import { useState, useEffect, useMemo } from 'react'; import { omit } from 'lodash'; -import { Flex, Form, Input, Card, Alert, Divider } from 'antd'; +import { Flex, Form, Input, Card, Alert, Divider, Select } from 'antd'; import { Button, Intent } from '@blueprintjs/core'; import API from '@/api'; -import { ExternalLink, Block, MultiSelector, Message } from '@/components'; +import { ExternalLink, Block, Message } from '@/components'; import { transformEntities, EntitiesLabel } from '@/config'; import { getPluginConfig } from '@/plugins'; import { GitHubTransformation } from '@/plugins/register/github'; @@ -145,12 +145,12 @@ export const ScopeConfigForm = ({ } required > - <MultiSelector - items={transformEntities(config.scopeConfig?.entities ?? [])} - getKey={(it) => it.value} - getName={(it) => it.label} - selectedItems={entities.map((it) => ({ label: EntitiesLabel[it], value: it }))} - onChangeItems={(its) => setEntities(its.map((it) => it.value))} + <Select + style={{ width: '100%' }} + mode="multiple" + options={transformEntities(config.scopeConfig?.entities ?? [])} + value={entities} + onChange={(value) => setEntities(value)} /> </Block> {showWarning && ( diff --git a/config-ui/src/plugins/register/bitbucket/transformation.tsx b/config-ui/src/plugins/register/bitbucket/transformation.tsx index f0562a538..6bae7b8a7 100644 --- a/config-ui/src/plugins/register/bitbucket/transformation.tsx +++ b/config-ui/src/plugins/register/bitbucket/transformation.tsx @@ -18,9 +18,9 @@ import { useMemo, useState, useEffect } from 'react'; import { CaretRightOutlined } from '@ant-design/icons'; -import { theme, Collapse, Tag, Form, Input, Checkbox } from 'antd'; +import { theme, Collapse, Tag, Form, Input, Checkbox, Select } from 'antd'; -import { ExternalLink, HelpTooltip, MultiSelector } from '@/components'; +import { ExternalLink, HelpTooltip } from '@/components'; import { DOC_URL } from '@/release'; import ExampleJpg from './assets/bitbucket-example.jpg'; @@ -127,55 +127,53 @@ const renderCollapseItems = ({ children: ( <div className="list"> <Form.Item label="TODO"> - <MultiSelector - items={ALL_STATES} - disabledItems={selectedStates} - selectedItems={transformation.issueStatusTodo ? transformation.issueStatusTodo.split(',') : []} - onChangeItems={(selectedItems) => + <Select + mode="multiple" + options={ALL_STATES.map((it) => ({ label: it, value: it }))} + value={transformation.issueStatusTodo ? transformation.issueStatusTodo.split(',') : []} + onChange={(value) => onChangeTransformation({ ...transformation, - issueStatusTodo: selectedItems.join(','), + issueStatusTodo: value.join(','), }) } /> </Form.Item> <Form.Item label="IN-PROGRESS"> - <MultiSelector - items={ALL_STATES} - disabledItems={selectedStates} - selectedItems={ - transformation.issueStatusInProgress ? transformation.issueStatusInProgress.split(',') : [] - } - onChangeItems={(selectedItems) => + <Select + mode="multiple" + options={ALL_STATES.map((it) => ({ label: it, value: it }))} + value={transformation.issueStatusInProgress ? transformation.issueStatusInProgress.split(',') : []} + onChange={(value) => onChangeTransformation({ ...transformation, - issueStatusInProgress: selectedItems.join(','), + issueStatusInProgress: value.join(','), }) } /> </Form.Item> <Form.Item label="DONE"> - <MultiSelector - items={ALL_STATES} - disabledItems={selectedStates} - selectedItems={transformation.issueStatusDone ? transformation.issueStatusDone.split(',') : []} - onChangeItems={(selectedItems) => + <Select + mode="multiple" + options={ALL_STATES.map((it) => ({ label: it, value: it }))} + value={transformation.issueStatusDone ? transformation.issueStatusDone.split(',') : []} + onChange={(value) => onChangeTransformation({ ...transformation, - issueStatusDone: selectedItems.join(','), + issueStatusDone: value.join(','), }) } /> </Form.Item> <Form.Item label="OTHER"> - <MultiSelector - items={ALL_STATES} - disabledItems={selectedStates} - selectedItems={transformation.issueStatusOther ? transformation.issueStatusOther.split(',') : []} - onChangeItems={(selectedItems) => + <Select + mode="multiple" + options={ALL_STATES.map((it) => ({ label: it, value: it }))} + value={transformation.issueStatusOther ? transformation.issueStatusOther.split(',') : []} + onChange={(value) => onChangeTransformation({ ...transformation, - issueStatusOther: selectedItems.join(','), + issueStatusOther: value.join(','), }) } /> diff --git a/config-ui/src/plugins/register/jira/transformation.tsx b/config-ui/src/plugins/register/jira/transformation.tsx index 7964674e5..90fd62037 100644 --- a/config-ui/src/plugins/register/jira/transformation.tsx +++ b/config-ui/src/plugins/register/jira/transformation.tsx @@ -19,10 +19,10 @@ import { useState, useEffect, useMemo } from 'react'; import { uniqWith } from 'lodash'; import { CaretRightOutlined } from '@ant-design/icons'; -import { theme, Collapse, Tag, Form } from 'antd'; +import { theme, Collapse, Tag, Form, Select } from 'antd'; import API from '@/api'; -import { PageLoading, HelpTooltip, ExternalLink, MultiSelector, Selector } from '@/components'; +import { PageLoading, HelpTooltip, ExternalLink } from '@/components'; import { useProxyPrefix, useRefreshData } from '@/hooks'; import { DOC_URL } from '@/release'; @@ -165,14 +165,26 @@ const renderCollapseItems = ({ transformation: any; onChangeTransformation: any; connectionId: ID; - issueTypes: any; + issueTypes: Array<{ + id: string; + name: string; + }>; fields: Array<{ id: string; name: string; }>; - requirementItems: any; - bugItems: any; - incidentItems: any; + requirementItems: Array<{ + id: string; + name: string; + }>; + bugItems: Array<{ + id: string; + name: string; + }>; + incidentItems: Array<{ + id: string; + name: string; + }>; transformaType: any; }) => [ @@ -194,18 +206,18 @@ const renderCollapseItems = ({ <ExternalLink link={DOC_URL.METRICS.MTTR}>DORA - Median Time to Restore Service</ExternalLink>, etc. </p> <Form.Item label="Requirement"> - <MultiSelector - items={issueTypes} - disabledItems={[...bugItems, ...incidentItems]} - getKey={(it) => it.id} - getName={(it) => it.name} - getIcon={(it) => it.iconUrl} - selectedItems={requirementItems} - onChangeItems={(selectedItems) => + <Select + mode="multiple" + options={issueTypes.map((it) => ({ label: it.name, value: it.id }))} + value={requirementItems.map((it) => it.id)} + onChange={(value) => onChangeTransformation({ ...transformation, typeMappings: { - ...transformaType(selectedItems, StandardType.Requirement), + ...transformaType( + requirementItems.filter((it) => value.includes(it.id)), + StandardType.Requirement, + ), ...transformaType(bugItems, StandardType.Bug), ...transformaType(incidentItems, StandardType.Incident), }, @@ -214,19 +226,19 @@ const renderCollapseItems = ({ /> </Form.Item> <Form.Item label="Bug"> - <MultiSelector - items={issueTypes} - disabledItems={[...requirementItems, ...incidentItems]} - getKey={(it) => it.id} - getName={(it) => it.name} - getIcon={(it) => it.iconUrl} - selectedItems={bugItems} - onChangeItems={(selectedItems) => + <Select + mode="multiple" + options={issueTypes.map((it) => ({ label: it.name, value: it.id }))} + value={bugItems.map((it) => it.id)} + onChange={(value) => onChangeTransformation({ ...transformation, typeMappings: { ...transformaType(requirementItems, StandardType.Requirement), - ...transformaType(selectedItems, StandardType.Bug), + ...transformaType( + bugItems.filter((it) => value.includes(it.id)), + StandardType.Bug, + ), ...transformaType(incidentItems, StandardType.Incident), }, }) @@ -243,20 +255,21 @@ const renderCollapseItems = ({ </> } > - <MultiSelector - items={issueTypes} - disabledItems={[...requirementItems, ...bugItems]} - getKey={(it) => it.id} - getName={(it) => it.name} - getIcon={(it) => it.iconUrl} - selectedItems={incidentItems} - onChangeItems={(selectedItems) => + <Select + mode="multiple" + options={issueTypes.map((it) => ({ label: it.name, value: it.id }))} + value={incidentItems.map((it) => it.id)} + onChange={(value) => onChangeTransformation({ ...transformation, typeMappings: { ...transformaType(requirementItems, StandardType.Requirement), ...transformaType(bugItems, StandardType.Bug), - ...transformaType(selectedItems, StandardType.Incident), + ...transformaType( + incidentItems.filter((it) => value.includes(it.id)), + + StandardType.Incident, + ), }, }) } @@ -270,15 +283,13 @@ const renderCollapseItems = ({ </> } > - <Selector - items={fields} - getKey={(it) => it.id} - getName={(it) => it.name} - selectedItem={fields.find((it) => it.id === transformation.storyPointField)} - onChangeItem={(selectedItem) => + <Select + options={fields.map((it) => ({ label: it.name, value: it.id }))} + value={transformation.storyPointField} + onChange={(value) => onChangeTransformation({ ...transformation, - storyPointField: selectedItem.id, + storyPointField: value, }) } /> diff --git a/config-ui/src/plugins/register/tapd/transformation.tsx b/config-ui/src/plugins/register/tapd/transformation.tsx index cb4d9e624..b010ed7de 100644 --- a/config-ui/src/plugins/register/tapd/transformation.tsx +++ b/config-ui/src/plugins/register/tapd/transformation.tsx @@ -19,10 +19,10 @@ import { useEffect, useState } from 'react'; import { uniqWith } from 'lodash'; import { CaretRightOutlined } from '@ant-design/icons'; -import { theme, Collapse, Tag, Form } from 'antd'; +import { theme, Collapse, Tag, Form, Select } from 'antd'; import API from '@/api'; -import { MultiSelector, PageLoading } from '@/components'; +import { PageLoading } from '@/components'; import { useProxyPrefix, useRefreshData } from '@/hooks'; enum StandardType { @@ -211,20 +211,15 @@ const renderCollapseItems = ({ and `Bug age` in built-in dashboards. </p> <Form.Item label="Requirement"> - <MultiSelector - items={typeList} - disabledItems={typeList.filter((v) => [...bugTypeList, ...incidentTypeList].includes(v.id))} - getKey={(it) => it.id} - getName={(it) => it.name} - selectedItems={typeList.filter((v) => featureTypeList.includes(v.id))} - onChangeItems={(selectedItems) => + <Select + mode="multiple" + options={typeList.map((it) => ({ label: it.name, value: it.id }))} + value={featureTypeList} + onChange={(value) => onChangeTransformation({ ...transformation, typeMappings: { - ...transformaType( - selectedItems.map((v) => v.id), - StandardType.Requirement, - ), + ...transformaType(value, StandardType.Requirement), ...transformaType(bugTypeList, StandardType.Bug), ...transformaType(incidentTypeList, StandardType.Incident), }, @@ -233,21 +228,16 @@ const renderCollapseItems = ({ /> </Form.Item> <Form.Item label="Bug"> - <MultiSelector - items={typeList} - disabledItems={typeList.filter((v) => [...featureTypeList, ...incidentTypeList].includes(v.id))} - getKey={(it) => it.id} - getName={(it) => it.name} - selectedItems={typeList.filter((v) => bugTypeList.includes(v.id))} - onChangeItems={(selectedItems) => + <Select + mode="multiple" + options={typeList.map((it) => ({ label: it.name, value: it.id }))} + value={bugTypeList} + onChange={(value) => onChangeTransformation({ ...transformation, typeMappings: { ...transformaType(featureTypeList, StandardType.Requirement), - ...transformaType( - selectedItems.map((v) => v.id), - StandardType.Bug, - ), + ...transformaType(value, StandardType.Bug), ...transformaType(incidentTypeList, StandardType.Incident), }, }) @@ -264,22 +254,17 @@ const renderCollapseItems = ({ </> } > - <MultiSelector - items={typeList} - disabledItems={typeList.filter((v) => [...featureTypeList, ...bugTypeList].includes(v.id))} - getKey={(it) => it.id} - getName={(it) => it.name} - selectedItems={typeList.filter((v) => incidentTypeList.includes(v.id))} - onChangeItems={(selectedItems) => + <Select + mode="multiple" + options={typeList.map((it) => ({ label: it.name, value: it.id }))} + value={incidentTypeList} + onChange={(value) => onChangeTransformation({ ...transformation, typeMappings: { ...transformaType(featureTypeList, StandardType.Requirement), ...transformaType(bugTypeList, StandardType.Bug), - ...transformaType( - selectedItems.map((v) => v.id), - StandardType.Incident, - ), + ...transformaType(value, StandardType.Incident), }, }) } @@ -290,20 +275,15 @@ const renderCollapseItems = ({ Delivery Rate` in built-in dashboards. </p> <Form.Item label="TODO"> - <MultiSelector - items={statusList} - disabledItems={statusList.filter((v) => [...inProgressStatusList, ...doneStatusList].includes(v.name))} - getKey={(it) => it.id} - getName={(it) => it.name} - selectedItems={statusList.filter((v) => todoStatusList.includes(v.name))} - onChangeItems={(selectedItems) => + <Select + mode="multiple" + options={statusList.map((it) => ({ label: it.name, value: it.id }))} + value={todoStatusList} + onChange={(value) => onChangeTransformation({ ...transformation, statusMappings: { - ...transformaType( - selectedItems.map((v) => v.name), - StandardStatus.Todo, - ), + ...transformaType(value, StandardStatus.Todo), ...transformaType(inProgressStatusList, StandardStatus.InProgress), ...transformaType(doneStatusList, StandardStatus.Done), }, @@ -312,21 +292,16 @@ const renderCollapseItems = ({ /> </Form.Item> <Form.Item label="IN-PROGRESS"> - <MultiSelector - items={statusList} - disabledItems={statusList.filter((v) => [...todoStatusList, ...doneStatusList].includes(v.name))} - getKey={(it) => it.id} - getName={(it) => it.name} - selectedItems={statusList.filter((v) => inProgressStatusList.includes(v.name))} - onChangeItems={(selectedItems) => + <Select + mode="multiple" + options={statusList.map((it) => ({ label: it.name, value: it.id }))} + value={inProgressStatusList} + onChange={(value) => onChangeTransformation({ ...transformation, statusMappings: { ...transformaType(todoStatusList, StandardStatus.Todo), - ...transformaType( - selectedItems.map((v) => v.name), - StandardStatus.InProgress, - ), + ...transformaType(value, StandardStatus.InProgress), ...transformaType(doneStatusList, StandardStatus.Done), }, }) @@ -334,22 +309,17 @@ const renderCollapseItems = ({ /> </Form.Item> <Form.Item label="DONE"> - <MultiSelector - items={statusList} - disabledItems={statusList.filter((v) => [...todoStatusList, ...inProgressStatusList].includes(v.name))} - getKey={(it) => it.id} - getName={(it) => it.name} - selectedItems={statusList.filter((v) => doneStatusList.includes(v.name))} - onChangeItems={(selectedItems) => + <Select + mode="multiple" + options={statusList.map((it) => ({ label: it.name, value: it.id }))} + value={doneStatusList} + onChange={(value) => onChangeTransformation({ ...transformation, statusMappings: { ...transformaType(todoStatusList, StandardStatus.Todo), ...transformaType(inProgressStatusList, StandardStatus.InProgress), - ...transformaType( - selectedItems.map((v) => v.name), - StandardStatus.Done, - ), + ...transformaType(value, StandardStatus.Done), }, }) } diff --git a/config-ui/src/routes/api-keys/api-keys.tsx b/config-ui/src/routes/api-keys/api-keys.tsx index 252ac553f..6271b4674 100644 --- a/config-ui/src/routes/api-keys/api-keys.tsx +++ b/config-ui/src/routes/api-keys/api-keys.tsx @@ -17,12 +17,12 @@ */ import { useState, useMemo } from 'react'; -import { Table, Modal, Input } from 'antd'; +import { Table, Modal, Input, Select } from 'antd'; import { Button, Tag, Intent } from '@blueprintjs/core'; import dayjs from 'dayjs'; import API from '@/api'; -import { PageHeader, Block, Selector, ExternalLink, CopyText, Message } from '@/components'; +import { PageHeader, Block, ExternalLink, CopyText, Message } from '@/components'; import { useRefreshData } from '@/hooks'; import { operator, formatTime } from '@/utils'; @@ -53,8 +53,8 @@ export const ApiKeys = () => { const [dataSource, total] = useMemo(() => [data?.apikeys ?? [], data?.count ?? 0], [data]); const hasError = useMemo(() => !form.name || !form.allowedPath, [form]); - const timeSelectedItem = useMemo(() => { - return C.timeOptions.find((it) => it.value === form.expiredAt || !it.value); + const timeSelectedValue = useMemo(() => { + return C.timeOptions.find((it) => it.value === form.expiredAt || !it.value)?.value; }, [form.expiredAt]); const handleCancel = () => { @@ -174,15 +174,12 @@ export const ApiKeys = () => { /> </Block> <Block title="Expiration" description="Set an expiration time for your API key." required> - <div style={{ width: 386 }}> - <Selector - items={C.timeOptions} - getKey={(it) => it.value} - getName={(it) => it.label} - selectedItem={timeSelectedItem} - onChangeItem={(it) => setForm({ ...form, expiredAt: it.value ? it.value : undefined })} - /> - </div> + <Select + style={{ width: 386 }} + options={C.timeOptions} + value={timeSelectedValue} + onChange={(value) => setForm({ ...form, expiredAt: value ? value : undefined })} + /> </Block> <Block title="Allowed Path"
