likyh commented on code in PR #3792: URL: https://github.com/apache/incubator-devlake/pull/3792#discussion_r1043048782
########## config-ui/src/pages/blueprint/create/hooks/use-blueprint-value.ts: ########## @@ -0,0 +1,150 @@ +/* + * 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, useMemo } from 'react' + +import { operator } from '@/utils' + +import type { BPConnectionItemType, BPScopeItemType } from '../types' +import { FromEnum, ModeEnum } from '../types' +import * as API from '../api' + +interface Props { + from: FromEnum + projectName: string +} + +export const useBlueprintValue = ({ from, projectName }: Props) => { + const [step, setStep] = useState(1) + const [error, setError] = useState('') + const [showInspector, setShowInspector] = useState(false) + const [showDetail, setShowDetail] = useState(false) + + const [name, setName] = useState( + from === FromEnum.project ? `${projectName}-BLUEPRINT` : 'MY BLUEPRINT' + ) + const [mode, setMode] = useState<ModeEnum>(ModeEnum.normal) + const [rawPlan, setRawPlan] = useState(JSON.stringify([[]], null, ' ')) + const [connections, setConnections] = useState<BPConnectionItemType[]>([]) + const [scope, setScope] = useState<BPScopeItemType[]>([]) + const [cronConfig, setCronConfig] = useState('0 0 * * *') + const [isManual, setIsManual] = useState(false) + const [skipOnFail, setSkipOnFail] = useState(false) + + const validRawPlan = (rp: string) => { + try { + const p = JSON.parse(rp) + if (p.flat().length === 0) { + return true + } + return false + } catch { + return true + } + } + + const payload = useMemo( + () => ({ + name, + projectName, + mode, + plan: validRawPlan(rawPlan) ? JSON.parse(rawPlan) : [[]], + enable: true, + cronConfig, + isManual, + skipOnFail, + settings: { + version: '2.0.0', + connections: connections.map((cs) => ({ + plugin: cs.plugin, + connectionId: cs.id, + scope: cs.scope + })) + } + }), + [ + name, + projectName, + mode, + rawPlan, + cronConfig, + isManual, + skipOnFail, + connections, + scope + ] + ) + + const handleSave = async () => { + const [success] = await operator(() => API.createBlueprint(payload)) + console.log(success) Review Comment: delete debug code. Or add some info to make it readable. ########## config-ui/src/pages/blueprint/create/step-one/example/jenkins.ts: ########## @@ -0,0 +1,29 @@ +/* + * 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 default [ + [ + { + plugin: 'jenkins', + options: { + connectionId: 1, + jobName: 'unit_test' Review Comment: I'm not sure if it `jobName`. Maybe `jobFullName`. So does the scope API. ########## config-ui/src/pages/blueprint/create/step-four/index.tsx: ########## @@ -0,0 +1,182 @@ +/* + * 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 React, { useState, useEffect } from 'react' +import { + RadioGroup, + Radio, + Checkbox, + InputGroup, + Icon, + Position +} from '@blueprintjs/core' +import { Popover2 } from '@blueprintjs/popover2' + +import { Divider } from '@/components' +import CronHelp from '@/images/cron-help.png' + +import { useBlueprint } from '../hooks' + +import * as S from './styled' + +const cronPresets = [ + { + label: 'Hourly', + config: '59 * * * *', + desc: 'At minute 59 on every day-of-week from Monday through Sunday.' + }, + { + label: 'Daily', + config: '0 0 * * *', + desc: 'At 00:00 (Midnight) on every day-of-week from Monday through Sunday.' + }, + { + label: 'Weekly', + config: '0 0 * * 1', + desc: 'At 00:00 (Midnight) on Monday.' + }, + { + label: 'Monthly', + config: '0 0 1 * *', + desc: 'At 00:00 (Midnight) on day-of-month 1.' + } +] + +export const StepFour = () => { + const [desc, setDesc] = useState('') + const [frequency, setFrequency] = useState('') + + const { + cronConfig, + isManual, + skipOnFail, + onChangeCronConfig, + onChangeIsManual, + onChangeSkipOnFail + } = useBlueprint() + + useEffect(() => { Review Comment: useMemo ########## config-ui/src/pages/blueprint/create/components/inspector/index.tsx: ########## @@ -0,0 +1,58 @@ +/* + * 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 React, { useMemo } from 'react' +import { Drawer, DrawerSize, Classes, IconName } from '@blueprintjs/core' + +import { useBlueprint } from '../../hooks' + +import * as S from './styled' + +export const Inspector = () => { + const { name, payload, showInspector, onChangeShowInspector } = useBlueprint() Review Comment:  ########## config-ui/src/pages/blueprint/create/hooks/use-blueprint-value.ts: ########## @@ -0,0 +1,150 @@ +/* + * 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, useMemo } from 'react' + +import { operator } from '@/utils' + +import type { BPConnectionItemType, BPScopeItemType } from '../types' +import { FromEnum, ModeEnum } from '../types' +import * as API from '../api' + +interface Props { + from: FromEnum + projectName: string +} + +export const useBlueprintValue = ({ from, projectName }: Props) => { + const [step, setStep] = useState(1) + const [error, setError] = useState('') + const [showInspector, setShowInspector] = useState(false) + const [showDetail, setShowDetail] = useState(false) + + const [name, setName] = useState( + from === FromEnum.project ? `${projectName}-BLUEPRINT` : 'MY BLUEPRINT' + ) + const [mode, setMode] = useState<ModeEnum>(ModeEnum.normal) + const [rawPlan, setRawPlan] = useState(JSON.stringify([[]], null, ' ')) + const [connections, setConnections] = useState<BPConnectionItemType[]>([]) + const [scope, setScope] = useState<BPScopeItemType[]>([]) + const [cronConfig, setCronConfig] = useState('0 0 * * *') + const [isManual, setIsManual] = useState(false) + const [skipOnFail, setSkipOnFail] = useState(false) + + const validRawPlan = (rp: string) => { + try { + const p = JSON.parse(rp) + if (p.flat().length === 0) { + return true + } + return false + } catch { + return true Review Comment: why `return true` when catch error? ########## config-ui/src/pages/blueprint/create/components/inspector/index.tsx: ########## @@ -0,0 +1,58 @@ +/* + * 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 React, { useMemo } from 'react' +import { Drawer, DrawerSize, Classes, IconName } from '@blueprintjs/core' + +import { useBlueprint } from '../../hooks' + +import * as S from './styled' + +export const Inspector = () => { + const { name, payload, showInspector, onChangeShowInspector } = useBlueprint() Review Comment: I found now `plan` is shown in the inspector. In my opinion, it is just a column used by the backend. Is it shown and submitted before on normal mode? ########## config-ui/src/pages/blueprint/create/step-one/index.tsx: ########## @@ -0,0 +1,214 @@ +/* + * 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 React, { useState, useMemo, useEffect } from 'react' +import { + InputGroup, + TextArea, + ButtonGroup, + Button, + Menu, + MenuItem, + Position +} from '@blueprintjs/core' +import { Popover2 } from '@blueprintjs/popover2' + +import { useConnections, ConnectionStatusEnum } from '@/store' +import { Divider, MultiSelector, Loading } from '@/components' + +import { ModeEnum } from '../types' +import { useBlueprint } from '../hooks' + +import { DEFAULT_CONFIG } from './example' +import * as S from './styled' + +export const StepOne = () => { + const [isOpen, setIsOpen] = useState(false) + + const connectionsStore = useConnections() + + const { + mode, + name, + rawPlan, + connections, + onChangeError, + onChangeMode, + onChangeName, + onChangeRawPlan, + onChangeConnections + } = useBlueprint() + + const selectedConnections = useMemo( + () => + connectionsStore.connections.filter((cs) => + connections.map((cs) => cs.unique).includes(cs.unique) + ), + [connectionsStore, connections] + ) + + const validRawPlan = (rp: string) => { + try { + const p = JSON.parse(rp) + if (p.flat().length === 0) { + return true + } + return false + } catch { + return true + } + } + + useEffect(() => { + switch (true) { + case !name: + return onChangeError('Blueprint Name: Enter a valid Name') Review Comment: return in useEffect? I think it is a mistake. ########## config-ui/src/plugins/common/data-scope-list/use-data-scope-list.ts: ########## @@ -0,0 +1,86 @@ +/* + * 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 { groupBy } from 'lodash' + +import { Plugins } from '@/plugins' + +import * as API from './api' + +type ScopeItem = { + id: ID + name: string + transformationRuleName?: string +} + +export interface UseDataScopeList { + plugin: Plugins + connectionId: ID + scopeIds: ID[] +} + +export const useDataScopeList = ({ Review Comment: where is `useDataScopeList` used in? What is transformationRuleName? ########## config-ui/src/pages/blueprint/create/step-one/index.tsx: ########## @@ -0,0 +1,214 @@ +/* + * 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 React, { useState, useMemo, useEffect } from 'react' +import { + InputGroup, + TextArea, + ButtonGroup, + Button, + Menu, + MenuItem, + Position +} from '@blueprintjs/core' +import { Popover2 } from '@blueprintjs/popover2' + +import { useConnections, ConnectionStatusEnum } from '@/store' +import { Divider, MultiSelector, Loading } from '@/components' + +import { ModeEnum } from '../types' +import { useBlueprint } from '../hooks' + +import { DEFAULT_CONFIG } from './example' +import * as S from './styled' + +export const StepOne = () => { + const [isOpen, setIsOpen] = useState(false) + + const connectionsStore = useConnections() + + const { + mode, + name, + rawPlan, + connections, + onChangeError, + onChangeMode, + onChangeName, + onChangeRawPlan, + onChangeConnections + } = useBlueprint() + + const selectedConnections = useMemo( + () => + connectionsStore.connections.filter((cs) => + connections.map((cs) => cs.unique).includes(cs.unique) + ), + [connectionsStore, connections] + ) + + const validRawPlan = (rp: string) => { Review Comment: a duplicated function ########## config-ui/package.json: ########## @@ -29,6 +29,7 @@ "dotenv-webpack": "^7.0.3", "file-saver": "^2.0.5", "jetbrains-mono": "^1.0.6", + "miller-columns-select": "^1.0.0-alpha.5", Review Comment: https://github.com/mintsweet/miller-columns-select ? I'm not sure if it should move into apache or merico-dev. But let's just use it now. ########## config-ui/src/plugins/common/data-scope-selector/use-data-scope-selector.ts: ########## @@ -0,0 +1,75 @@ +/* + * 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 { Plugins } from '@/plugins' + +import * as API from './api' + +type ScopeItem = { + name: string +} & any + +export interface UseDataScopeSelector { + plugin: Plugins + connectionId: ID + scopeIds: ID[] +} + +export const useDataScopeSelector = ({ + plugin, + connectionId, + scopeIds +}: UseDataScopeSelector) => { + const [loading, setLoading] = useState(false) + const [scope, setScope] = useState<ScopeItem[]>([]) + + const getScopeDetail = async () => { + setLoading(true) + try { + const res = await Promise.all( + scopeIds.map((id) => API.getDataScopeRepo(plugin, connectionId, id)) + ) + setScope(res) + } finally { + setLoading(false) + } + } + + useEffect(() => { + getScopeDetail() + }, []) + + return useMemo( + () => ({ + loading, + scope, + getKey(sc: ScopeItem) { + switch (true) { + case plugin === Plugins.GitHub: Review Comment: add other plugin case ########## config-ui/src/pages/blueprint/create/step-one/example/jira.ts: ########## @@ -0,0 +1,30 @@ +/* + * 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 default [ + [ + { + plugin: 'jira', + options: { + connectionId: 1, + boardId: 8, + since: '2006-01-02T15:04:05Z' Review Comment: I'll chenge this to `createdDateAfter`. Just a signal for myself. ########## config-ui/src/pages/blueprint/create/step-four/index.tsx: ########## @@ -0,0 +1,182 @@ +/* + * 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 React, { useState, useEffect } from 'react' +import { + RadioGroup, + Radio, + Checkbox, + InputGroup, + Icon, + Position +} from '@blueprintjs/core' +import { Popover2 } from '@blueprintjs/popover2' + +import { Divider } from '@/components' +import CronHelp from '@/images/cron-help.png' + +import { useBlueprint } from '../hooks' + +import * as S from './styled' + +const cronPresets = [ + { + label: 'Hourly', + config: '59 * * * *', + desc: 'At minute 59 on every day-of-week from Monday through Sunday.' + }, + { + label: 'Daily', + config: '0 0 * * *', + desc: 'At 00:00 (Midnight) on every day-of-week from Monday through Sunday.' + }, + { + label: 'Weekly', + config: '0 0 * * 1', + desc: 'At 00:00 (Midnight) on Monday.' + }, + { + label: 'Monthly', + config: '0 0 1 * *', + desc: 'At 00:00 (Midnight) on day-of-month 1.' + } +] + +export const StepFour = () => { + const [desc, setDesc] = useState('') + const [frequency, setFrequency] = useState('') + + const { + cronConfig, + isManual, + skipOnFail, + onChangeCronConfig, + onChangeIsManual, + onChangeSkipOnFail + } = useBlueprint() + + useEffect(() => { + if (frequency === 'manual') { + setDesc('Manual') + } else if (frequency === 'custom') { + setDesc('Custom') + } else { + const targetCron = cronPresets.find((it) => it.config === frequency) + setDesc(targetCron?.desc ?? '') + } + }, [frequency]) + + useEffect(() => { + if (isManual) { + setFrequency('manual') + } else if (frequency !== 'custom') { + setFrequency(cronConfig) Review Comment: I think maybe a bug exists here. 1. choose custom and set to `* * * * *`. now frequency='custom' 2. choose manual. now frequency='manual' 3. choose custom. now frequency!=='custom', so it be `* * * * *`. And then I cannot edit the cron input. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
