You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@devlake.apache.org by e2...@apache.org on 2022/09/08 12:18:00 UTC
[incubator-devlake] branch main updated: feat: add projects selector fetching by api for gitlab when adding blueprint (#2926)
This is an automated email from the ASF dual-hosted git repository.
e2corporation pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git
The following commit(s) were added to refs/heads/main by this push:
new 76611327 feat: add projects selector fetching by api for gitlab when adding blueprint (#2926)
76611327 is described below
commit 76611327c8692d48799789ecb4835e963a1f7278
Author: likyh <l...@likyh.com>
AuthorDate: Thu Sep 8 20:17:55 2022 +0800
feat: add projects selector fetching by api for gitlab when adding blueprint (#2926)
* feat: add projects selector fetching by api for gitlab when adding blueprint
* feat: change the project from id to object
* fix: fix some small bug
* feat: update project from id to object on setting page
* fix: fix some bug on advance mode
* fix: fix for review
* fix: fix for review
* fix: fix for review. (revert boards)
* feat: add icon for jira and gitlab
* fix: fix for lint
Co-authored-by: linyh <ya...@meri.co>
---
.../blueprints/BlueprintDataScopesDialog.jsx | 16 ++-
.../src/components/blueprints/DataScopesGrid.jsx | 4 +-
.../blueprints/GitlabProjectsSelector.jsx | 149 +++++++++++++++++++++
.../components/blueprints/StandardStackedList.jsx | 22 ++-
.../blueprints/create-workflow/DataScopes.jsx | 71 ++++++----
.../create-workflow/DataTransformations.jsx | 6 +-
.../config/{jiraApiProxy.js => gitlabApiProxy.js} | 14 +-
config-ui/src/config/jiraApiProxy.js | 14 +-
config-ui/src/hooks/useBlueprintValidation.jsx | 10 +-
config-ui/src/hooks/useDataScopesManager.jsx | 10 +-
config-ui/src/hooks/useGitlab.jsx | 86 ++++++++++++
config-ui/src/hooks/useJIRA.jsx | 10 +-
.../src/pages/blueprints/blueprint-settings.jsx | 90 +++++++++----
.../src/pages/blueprints/create-blueprint.jsx | 36 +++--
config-ui/src/pages/configure/settings/github.jsx | 28 ++--
15 files changed, 442 insertions(+), 124 deletions(-)
diff --git a/config-ui/src/components/blueprints/BlueprintDataScopesDialog.jsx b/config-ui/src/components/blueprints/BlueprintDataScopesDialog.jsx
index 2ad70849..b27fcc79 100644
--- a/config-ui/src/components/blueprints/BlueprintDataScopesDialog.jsx
+++ b/config-ui/src/components/blueprints/BlueprintDataScopesDialog.jsx
@@ -72,6 +72,8 @@ const BlueprintDataScopesDialog = (props) => {
issueTypesList = [],
fieldsList = [],
boards = {},
+ gitlabProjects = [],
+ fetchGitlabProjects = () => [],
entities = {},
projects = {},
mode = Modes.EDIT,
@@ -105,6 +107,8 @@ const BlueprintDataScopesDialog = (props) => {
isTesting = false,
isFetchingJIRA = false,
jiraProxyError,
+ isFetchingGitlab,
+ gitlabProxyError,
errors = [],
content = null,
backButtonProps = {
@@ -112,28 +116,28 @@ const BlueprintDataScopesDialog = (props) => {
intent: Intent.PRIMARY,
text: 'Previous Step',
outlined: true,
- loading: isFetchingJIRA || isSaving
+ loading: isFetchingJIRA || isFetchingGitlab || isSaving
},
nextButtonProps = {
disabled: !isValid,
intent: Intent.PRIMARY,
text: 'Next Step',
outlined: true,
- loading: isFetchingJIRA || isSaving,
+ loading: isFetchingJIRA || isFetchingGitlab || isSaving,
},
finalButtonProps = {
disabled: !isValid,
intent: Intent.PRIMARY,
onClick: onSave,
text: 'Save Changes',
- loading: isFetchingJIRA || isSaving
+ loading: isFetchingJIRA || isFetchingGitlab || isSaving
},
closeButtonProps = {
// disabled:
intent: Intent.PRIMARY,
text: 'Cancel',
outlined: true,
- loading: isFetchingJIRA || isSaving
+ loading: isFetchingJIRA || isFetchingGitlab || isSaving
}
} = props
@@ -180,6 +184,10 @@ const BlueprintDataScopesDialog = (props) => {
dataEntitiesList={dataEntitiesList}
boardsList={boardsList}
boards={boards}
+ fetchGitlabProjects={fetchGitlabProjects}
+ gitlabProjects={gitlabProjects}
+ isFetchingGitlab={isFetchingGitlab}
+ gitlabProxyError={gitlabProxyError}
dataEntities={entities}
projects={projects}
configuredConnection={configuredConnection}
diff --git a/config-ui/src/components/blueprints/DataScopesGrid.jsx b/config-ui/src/components/blueprints/DataScopesGrid.jsx
index c1ccd540..52930371 100644
--- a/config-ui/src/components/blueprints/DataScopesGrid.jsx
+++ b/config-ui/src/components/blueprints/DataScopesGrid.jsx
@@ -155,8 +155,8 @@ const DataScopesGrid = (props) => {
}}
>
{c.projects.map((project, pIdx) => (
- <li key={`list-item-key-${pIdx}`}>
- {project}
+ <li key={`list-item-key-${pIdx}`} style={{ whiteSpace: 'break-spaces' }}>
+ {project.title}
</li>
))}
</ul>
diff --git a/config-ui/src/components/blueprints/GitlabProjectsSelector.jsx b/config-ui/src/components/blueprints/GitlabProjectsSelector.jsx
new file mode 100644
index 00000000..ffeb0656
--- /dev/null
+++ b/config-ui/src/components/blueprints/GitlabProjectsSelector.jsx
@@ -0,0 +1,149 @@
+/*
+ * 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, { useEffect, useState } from 'react'
+import { Checkbox, Intent, MenuItem, } from '@blueprintjs/core'
+import { MultiSelect } from '@blueprintjs/select'
+
+const GitlabProjectsSelector = (props) => {
+ const {
+ onFetch = () => [],
+ isFetching = false,
+ configuredConnection,
+ placeholder = 'Select Projects',
+ items = [],
+ selectedItems = [],
+ activeItem = null,
+ disabled = false,
+ isLoading = false,
+ isSaving = false,
+ onItemSelect = () => {},
+ onRemove = () => {},
+ onClear = () => {},
+ itemRenderer = (item, { handleClick, modifiers }) => (
+ <MenuItem
+ active={modifiers.active}
+ disabled={
+ selectedItems.find(i => i?.id === item?.id)
+ }
+ key={item.value}
+ onClick={handleClick}
+ text={
+ selectedItems.find(i => i?.id === item?.id)
+ ? (
+ <>
+ <input type='checkbox' checked readOnly /> {item?.title}
+ </>
+ )
+ : (
+ <span style={{ fontWeight: 700 }}>
+ <input type='checkbox' readOnly /> {item?.title}
+ </span>
+ )
+ }
+ style={{
+ marginBottom: '2px',
+ fontWeight: items.includes(item) ? 700 : 'normal',
+ }}
+ />
+ ),
+ tagRenderer = (item) => item.shortTitle || item.title
+ } = props
+
+ const [query, setQuery] = useState('')
+ const [onlyQueryMemberRepo, setOnlyQueryMemberRepo] = useState(true)
+
+ useEffect(() => {
+ // prevent request too frequently
+ const timer = setTimeout(() => {
+ onFetch(query, onlyQueryMemberRepo)
+ }, 200)
+ return () => clearTimeout(timer)
+ }, [onFetch, query, onlyQueryMemberRepo])
+
+ return (
+ <div
+ className='gitlab-projects-multiselect'
+ style={{ display: 'flex', marginBottom: '10px' }}
+ >
+ <div
+ className='gitlab-projects-multiselect-selector'
+ style={{ minWidth: '200px', width: '100%' }}
+ >
+ <MultiSelect
+ disabled={disabled || isSaving || isLoading}
+ // openOnKeyDown={true}
+ resetOnSelect={true}
+ placeholder={placeholder}
+ popoverProps={{ usePortal: false, minimal: true }}
+ className='multiselector-projects'
+ inline={true}
+ fill={true}
+ items={items}
+ selectedItems={selectedItems}
+ activeItem={activeItem}
+ onQueryChange={query => setQuery(query)}
+ itemRenderer={itemRenderer}
+ tagRenderer={tagRenderer}
+ tagInputProps={{
+ tagProps: {
+ intent: Intent.PRIMARY,
+ minimal: true
+ },
+ }}
+ noResults={
+ (query.length <= 2 && <MenuItem disabled={true} text='Please type more than 2 characters to search.' />) ||
+ (isFetching && <MenuItem disabled={true} text='Fetching...' />) ||
+ <MenuItem disabled={true} text='No Projects Available.' />
+ }
+ onRemove={(item) => {
+ onRemove((rT) => {
+ return {
+ ...rT,
+ [configuredConnection.id]: rT[configuredConnection.id].filter(
+ (t) => t?.id !== item.id
+ ),
+ }
+ })
+ }}
+ onItemSelect={(item) => {
+ onItemSelect((rT) => {
+ return !rT[configuredConnection.id].includes(item)
+ ? {
+ ...rT,
+ [configuredConnection.id]: [
+ ...rT[configuredConnection.id],
+ item,
+ ],
+ }
+ : { ...rT }
+ })
+ }}
+ style={{ borderRight: 0 }}
+ />
+
+ <Checkbox
+ label='Only search my repositories' checked={onlyQueryMemberRepo}
+ onChange={e => setOnlyQueryMemberRepo(!onlyQueryMemberRepo)}
+ style={{ margin: '10px 0 0 6px' }}
+ />
+ </div>
+ </div>
+ )
+}
+
+export default GitlabProjectsSelector
diff --git a/config-ui/src/components/blueprints/StandardStackedList.jsx b/config-ui/src/components/blueprints/StandardStackedList.jsx
index cbd72a40..ad175062 100644
--- a/config-ui/src/components/blueprints/StandardStackedList.jsx
+++ b/config-ui/src/components/blueprints/StandardStackedList.jsx
@@ -15,8 +15,7 @@
* limitations under the License.
*
*/
-import React, { Fragment, useEffect, useState, useCallback } from 'react'
-import { CSSTransition } from 'react-transition-group'
+import React from 'react'
import {
Button,
Icon,
@@ -24,6 +23,8 @@ import {
Elevation,
Card,
Colors,
+ Popover,
+ PopoverInteractionKind,
} from '@blueprintjs/core'
const StandardStackedList = (props) => {
@@ -68,7 +69,22 @@ const StandardStackedList = (props) => {
onClick={() => onAdd(item)}
style={{ cursor: 'pointer' }}
>
- {item?.name || item}
+ {item.shortTitle || item.icon
+ ? (
+ <Popover
+ className='docs-popover-portal-example-popover'
+ interactionKind={PopoverInteractionKind.HOVER_TARGET_ONLY}
+ content={
+ <div style={{ padding: '5px', 'justify-content': 'center', display: 'flex' }}>
+ {item.icon && <img src={item.icon} style={{ maxWidth: '100%', overflow: 'hidden', width: '14px', height: '14px', borderRadius: '50%', marginRight: '2px' }}/>}
+ {item.title}
+ </div>
+ }
+ >
+ {item.shortTitle || item.title}
+ </Popover>
+ )
+ : item.title}
</label>
</div>
</div>
diff --git a/config-ui/src/components/blueprints/create-workflow/DataScopes.jsx b/config-ui/src/components/blueprints/create-workflow/DataScopes.jsx
index de0d204d..a550bc79 100644
--- a/config-ui/src/components/blueprints/create-workflow/DataScopes.jsx
+++ b/config-ui/src/components/blueprints/create-workflow/DataScopes.jsx
@@ -15,29 +15,14 @@
* limitations under the License.
*
*/
-import React, { Fragment, useEffect, useState, useCallback, useMemo } from 'react'
-import {
- Button,
- Icon,
- Intent,
- TagInput,
- Divider,
- Elevation,
- Card,
- Colors,
-} from '@blueprintjs/core'
-import {
- Providers,
- ProviderTypes,
- ProviderIcons,
- ConnectionStatus,
- ConnectionStatusLabels,
-} from '@/data/Providers'
-
+import React, { useEffect, useMemo } from 'react'
+import { Button, Card, Divider, Elevation, Intent, TagInput, } from '@blueprintjs/core'
+import { ProviderIcons, Providers, } from '@/data/Providers'
import ConnectionTabs from '@/components/blueprints/ConnectionTabs'
import BoardsSelector from '@/components/blueprints/BoardsSelector'
import DataEntitiesSelector from '@/components/blueprints/DataEntitiesSelector'
import NoData from '@/components/NoData'
+import GitlabProjectsSelector from '@/components/blueprints/GitlabProjectsSelector'
const DataScopes = (props) => {
const {
@@ -46,6 +31,9 @@ const DataScopes = (props) => {
blueprintConnections = [],
dataEntitiesList = [],
boardsList = [],
+ fetchGitlabProjects = () => [],
+ isFetchingGitlab = false,
+ gitlabProjects = [],
dataEntities = [],
projects = [],
boards = [],
@@ -67,11 +55,16 @@ const DataScopes = (props) => {
} = props
const selectedBoards = useMemo(() => boards[configuredConnection.id], [boards, configuredConnection?.id])
+ const selectedProjects = useMemo(() => projects[configuredConnection.id], [projects, configuredConnection?.id])
useEffect(() => {
console.log('>> OVER HERE!!!', selectedBoards)
}, [selectedBoards])
+ useEffect(() => {
+ console.log('>> OVER HERE FOR Projects!!!', selectedProjects)
+ }, [selectedProjects])
+
return (
<div className='workflow-step workflow-step-data-scope' data-step={activeStep?.id}>
{blueprintConnections.length > 0 && (
@@ -120,27 +113,28 @@ const DataScopes = (props) => {
</h3>
<Divider className='section-divider' />
- {[Providers.GITLAB, Providers.GITHUB].includes(
+ {[Providers.GITHUB].includes(
configuredConnection.provider
) && (
<>
<h4>Projects *</h4>
- {configuredConnection.provider === Providers.GITHUB && (<p>Enter the project names you would like to sync.</p>)}
- {configuredConnection.provider === Providers.GITLAB && (<p>Enter the project ids you would like to sync.</p>)}
+ <p>Enter the project names you would like to sync.</p>
<TagInput
id='project-id'
disabled={isRunning}
- placeholder={
- configuredConnection.provider === Providers.GITHUB
- ? 'username/repo, username/another-repo'
- : '1000000, 200000'
- }
- values={projects[configuredConnection.id] || []}
+ placeholder='username/repo, username/another-repo'
+ values={projects[configuredConnection.id]?.map(p => p.value) || []}
fill={true}
onChange={(values) =>
setProjects((p) => ({
...p,
- [configuredConnection.id]: [...new Set(values)],
+ [configuredConnection.id]: [...values.map((v, vIdx) => ({
+ id: v,
+ key: v,
+ title: v,
+ value: v,
+ type: 'string'
+ }))],
}))}
addOnPaste={true}
addOnBlur={true}
@@ -184,6 +178,25 @@ const DataScopes = (props) => {
</>
)}
+ {[Providers.GITLAB].includes(configuredConnection.provider) && (
+ <>
+ <h4>Projects *</h4>
+ <p>Select the project you would like to sync.</p>
+ <GitlabProjectsSelector
+ onFetch={fetchGitlabProjects}
+ isFetching={isFetchingGitlab}
+ items={gitlabProjects}
+ selectedItems={selectedProjects}
+ onItemSelect={setProjects}
+ onClear={setProjects}
+ onRemove={setProjects}
+ disabled={isSaving}
+ configuredConnection={configuredConnection}
+ isLoading={isFetching}
+ />
+ </>
+ )}
+
<h4>Data Entities</h4>
<p>
Select the data entities you wish to collect for the
diff --git a/config-ui/src/components/blueprints/create-workflow/DataTransformations.jsx b/config-ui/src/components/blueprints/create-workflow/DataTransformations.jsx
index bba7e3cc..ffb3b45d 100644
--- a/config-ui/src/components/blueprints/create-workflow/DataTransformations.jsx
+++ b/config-ui/src/components/blueprints/create-workflow/DataTransformations.jsx
@@ -101,8 +101,8 @@ const DataTransformations = (props) => {
const [entityList, setEntityList] = useState(boardsAndProjects?.map((e, eIdx) => ({
id: eIdx,
- value: e?.value || e,
- title: e?.title || e,
+ value: e?.value,
+ title: e?.title,
entity: e,
type: typeof e === 'object' ? 'board' : 'project'
})))
@@ -308,7 +308,7 @@ const DataTransformations = (props) => {
{!useDropdownSelector && (
<>
<h4>Project</h4>
- <p style={{ color: '#292B3F' }}>{configuredProject || configuredBoard?.name || '< select a project >'}</p>
+ <p style={{ color: '#292B3F' }}>{configuredProject?.title || configuredBoard?.title || '< select a project >'}</p>
</>
)}
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
diff --git a/config-ui/src/config/jiraApiProxy.js b/config-ui/src/config/gitlabApiProxy.js
similarity index 66%
copy from config-ui/src/config/jiraApiProxy.js
copy to config-ui/src/config/gitlabApiProxy.js
index cf349cdd..edcfbe27 100644
--- a/config-ui/src/config/jiraApiProxy.js
+++ b/config-ui/src/config/gitlabApiProxy.js
@@ -15,17 +15,11 @@
* limitations under the License.
*
*/
-const API_VERSION = 2
// @todo: add string replacer for [:connectionId] or refactor this const
-const API_PROXY_ENDPOINT = '/api/plugins/jira/connections/[:connectionId:]/proxy/rest'
-const ISSUE_TYPES_ENDPOINT = `${API_PROXY_ENDPOINT}/api/${API_VERSION}/issuetype`
-const ISSUE_FIELDS_ENDPOINT = `${API_PROXY_ENDPOINT}/api/${API_VERSION}/field`
-const BOARDS_ENDPOINT = `${API_PROXY_ENDPOINT}/agile/1.0/board`
+const GITLAB_API_PROXY_ENDPOINT = '/api/plugins/gitlab/connections/[:connectionId:]/proxy/rest'
+const PROJECTS_ENDPOINT = `${GITLAB_API_PROXY_ENDPOINT}/projects?search=[:search:]&membership=[:membership:]`
export {
- API_VERSION,
- API_PROXY_ENDPOINT,
- ISSUE_TYPES_ENDPOINT,
- ISSUE_FIELDS_ENDPOINT,
- BOARDS_ENDPOINT,
+ GITLAB_API_PROXY_ENDPOINT,
+ PROJECTS_ENDPOINT,
}
diff --git a/config-ui/src/config/jiraApiProxy.js b/config-ui/src/config/jiraApiProxy.js
index cf349cdd..3c0ac201 100644
--- a/config-ui/src/config/jiraApiProxy.js
+++ b/config-ui/src/config/jiraApiProxy.js
@@ -15,16 +15,16 @@
* limitations under the License.
*
*/
-const API_VERSION = 2
+const JIRA_API_VERSION = 2
// @todo: add string replacer for [:connectionId] or refactor this const
-const API_PROXY_ENDPOINT = '/api/plugins/jira/connections/[:connectionId:]/proxy/rest'
-const ISSUE_TYPES_ENDPOINT = `${API_PROXY_ENDPOINT}/api/${API_VERSION}/issuetype`
-const ISSUE_FIELDS_ENDPOINT = `${API_PROXY_ENDPOINT}/api/${API_VERSION}/field`
-const BOARDS_ENDPOINT = `${API_PROXY_ENDPOINT}/agile/1.0/board`
+const JIRA_API_PROXY_ENDPOINT = '/api/plugins/jira/connections/[:connectionId:]/proxy/rest'
+const ISSUE_TYPES_ENDPOINT = `${JIRA_API_PROXY_ENDPOINT}/api/${JIRA_API_VERSION}/issuetype`
+const ISSUE_FIELDS_ENDPOINT = `${JIRA_API_PROXY_ENDPOINT}/api/${JIRA_API_VERSION}/field`
+const BOARDS_ENDPOINT = `${JIRA_API_PROXY_ENDPOINT}/agile/1.0/board`
export {
- API_VERSION,
- API_PROXY_ENDPOINT,
+ JIRA_API_VERSION,
+ JIRA_API_PROXY_ENDPOINT,
ISSUE_TYPES_ENDPOINT,
ISSUE_FIELDS_ENDPOINT,
BOARDS_ENDPOINT,
diff --git a/config-ui/src/hooks/useBlueprintValidation.jsx b/config-ui/src/hooks/useBlueprintValidation.jsx
index 9ff6f66c..ef66ff6b 100644
--- a/config-ui/src/hooks/useBlueprintValidation.jsx
+++ b/config-ui/src/hooks/useBlueprintValidation.jsx
@@ -84,9 +84,9 @@ function useBlueprintValidation ({
return Array.isArray(set) ? set.every(i => !isNaN(i)) : false
}, [])
- const validateRepositoryName = useCallback((set = []) => {
+ const validateRepositoryName = useCallback((projects = []) => {
const repoRegExp = /([a-z0-9_-]){2,}\/([a-z0-9_-]){2,}$/gi
- return set.every(i => i.match(repoRegExp))
+ return projects.every(p => p.value.match(repoRegExp))
}, [])
const valiateNonEmptySet = useCallback((set = []) => {
@@ -151,9 +151,6 @@ function useBlueprintValidation ({
if (activeProvider?.id === Providers.GITLAB && projects[activeConnection?.id]?.length === 0) {
errs.push('Projects: No Project IDs entered.')
}
- if (activeProvider?.id === Providers.GITLAB && !validateNumericSet(projects[activeConnection?.id])) {
- errs.push('Projects: Only Numeric Project IDs are supported.')
- }
connections.forEach(c => {
if (c.provider === Providers.JIRA && boards[c?.id]?.length === 0) {
@@ -168,9 +165,6 @@ function useBlueprintValidation ({
if (c.provider === Providers.GITLAB && projects[c?.id]?.length === 0) {
errs.push(`${c.name} requires Project IDs`)
}
- if (c.provider === Providers.GITLAB && !validateNumericSet(projects[c?.id])) {
- errs.push(`${c.name} has invalid Project ID`)
- }
if (entities[c?.id]?.length === 0) {
errs.push(`${c.name} is missing Data Entities`)
}
diff --git a/config-ui/src/hooks/useDataScopesManager.jsx b/config-ui/src/hooks/useDataScopesManager.jsx
index 28060fdf..c1cdbeea 100644
--- a/config-ui/src/hooks/useDataScopesManager.jsx
+++ b/config-ui/src/hooks/useDataScopesManager.jsx
@@ -126,7 +126,8 @@ function useDataScopesManager ({ provider, blueprint, /* connection, */ settings
newScope = boards[connection.id]?.map((b) => ({
...newScope,
options: {
- boardId: Number(b?.id),
+ boardId: Number(b?.value),
+ title: b.title
// @todo: verify initial value of since date for jira provider
// since: new Date(),
},
@@ -137,7 +138,8 @@ function useDataScopesManager ({ provider, blueprint, /* connection, */ settings
newScope = projects[connection.id]?.map((p) => ({
...newScope,
options: {
- projectId: Number(p),
+ projectId: Number(p.value),
+ title: p.title
},
transformation: {},
}))
@@ -154,8 +156,8 @@ function useDataScopesManager ({ provider, blueprint, /* connection, */ settings
newScope = projects[connection.id]?.map((p) => ({
...newScope,
options: {
- owner: p.split('/')[0],
- repo: p.split('/')[1],
+ owner: p.value.split('/')[0],
+ repo: p.value.split('/')[1],
},
transformation: { ...transformations[p] },
}))
diff --git a/config-ui/src/hooks/useGitlab.jsx b/config-ui/src/hooks/useGitlab.jsx
new file mode 100644
index 00000000..0eca9a2e
--- /dev/null
+++ b/config-ui/src/hooks/useGitlab.jsx
@@ -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 { useEffect, useState, useCallback } from 'react'
+import request from '@/utils/request'
+import { ToastNotification } from '@/components/Toast'
+
+const useGitlab = ({ apiProxyPath, projectsEndpoint }, activeConnection = null) => {
+ const [isFetching, setIsFetching] = useState(false)
+ const [projects, setProjects] = useState([])
+ const [error, setError] = useState()
+
+ const fetchProjects = useCallback(async (search = '', onlyQueryMemberRepo = true) => {
+ try {
+ if (apiProxyPath.includes('null')) {
+ throw new Error('Connection ID is Null')
+ }
+ setError(null)
+ setIsFetching(true)
+ if (search.length > 2) {
+ // only search when type more than 2 chars
+ const endpoint = projectsEndpoint
+ .replace('[:connectionId:]', activeConnection?.connectionId)
+ .replace('[:search:]', search)
+ .replace('[:membership:]', onlyQueryMemberRepo ? 1 : 0)
+ const projectsResponse = await request.get(endpoint)
+ if (projectsResponse && projectsResponse.status === 200 && projectsResponse.data) {
+ setProjects(createListData(projectsResponse.data))
+ } else {
+ throw new Error('request projects fail')
+ }
+ } else {
+ setProjects([])
+ }
+ } catch (e) {
+ setError(e)
+ ToastNotification.show({ message: e.message, intent: 'danger', icon: 'error' })
+ } finally {
+ setIsFetching(false)
+ }
+ }, [projectsEndpoint, activeConnection, apiProxyPath])
+
+ const createListData = (
+ data = [],
+ titleProperty = 'name_with_namespace',
+ valueProperty = 'id',
+ iconProperty = 'avatar_url',
+ ) => {
+ return data.map((d, dIdx) => ({
+ id: d[valueProperty],
+ key: d[valueProperty],
+ title: d[titleProperty],
+ shortTitle: d.name,
+ value: d[valueProperty],
+ icon: d[iconProperty],
+ type: 'string'
+ }))
+ }
+
+ useEffect(() => {
+ console.log('>>> GITLAB API PROXY: FIELD SELECTOR PROJECTS DATA', projects)
+ }, [projects])
+
+ return {
+ isFetching,
+ fetchProjects,
+ projects,
+ error
+ }
+}
+
+export default useGitlab
diff --git a/config-ui/src/hooks/useJIRA.jsx b/config-ui/src/hooks/useJIRA.jsx
index 09428c09..dcc9e14b 100644
--- a/config-ui/src/hooks/useJIRA.jsx
+++ b/config-ui/src/hooks/useJIRA.jsx
@@ -153,13 +153,13 @@ const useJIRA = ({ apiProxyPath, issuesEndpoint, fieldsEndpoint, boardsEndpoint
activeConnection,
apiProxyPath])
- const createListData = (data = [], titleProperty = 'name', valueProperty = 'name') => {
+ const createListData = (data = [], titleProperty = 'name', valueProperty = 'id') => {
return data.map((d, dIdx) => ({
- ...d,
- id: d.id || dIdx,
- key: d.key ? d.key : dIdx,
+ id: d[valueProperty],
+ key: d[valueProperty],
title: d[titleProperty],
value: d[valueProperty],
+ icon: d?.location?.avatarURI,
type: d.schema?.type || 'string'
}))
}
@@ -175,7 +175,7 @@ const useJIRA = ({ apiProxyPath, issuesEndpoint, fieldsEndpoint, boardsEndpoint
}, [fieldsResponse])
useEffect(() => {
- setBoards(boardsResponse ? createListData(boardsResponse, 'name', 'name') : [])
+ setBoards(boardsResponse ? createListData(boardsResponse, 'name', 'id') : [])
}, [boardsResponse])
useEffect(() => {
diff --git a/config-ui/src/pages/blueprints/blueprint-settings.jsx b/config-ui/src/pages/blueprints/blueprint-settings.jsx
index 5b7c636e..fcc77747 100644
--- a/config-ui/src/pages/blueprints/blueprint-settings.jsx
+++ b/config-ui/src/pages/blueprints/blueprint-settings.jsx
@@ -20,7 +20,7 @@ import { useParams, useHistory } from 'react-router-dom'
import { ENVIRONMENT } from '@/config/environment'
import dayjs from '@/utils/time'
import {
- API_PROXY_ENDPOINT,
+ JIRA_API_PROXY_ENDPOINT,
ISSUE_TYPES_ENDPOINT,
ISSUE_FIELDS_ENDPOINT,
BOARDS_ENDPOINT,
@@ -72,6 +72,8 @@ import BlueprintDataScopesDialog from '@/components/blueprints/BlueprintDataScop
import BlueprintNavigationLinks from '@/components/blueprints/BlueprintNavigationLinks'
import DataScopesGrid from '@/components/blueprints/DataScopesGrid'
import AdvancedJSON from '@/components/blueprints/create-workflow/AdvancedJSON'
+import useGitlab from '@/hooks/useGitlab'
+import { GITLAB_API_PROXY_ENDPOINT, PROJECTS_ENDPOINT } from '@/config/gitlabApiProxy'
const BlueprintSettings = (props) => {
// eslint-disable-next-line no-unused-vars
@@ -288,7 +290,7 @@ const BlueprintSettings = (props) => {
error: jiraProxyError,
} = useJIRA(
{
- apiProxyPath: API_PROXY_ENDPOINT,
+ apiProxyPath: JIRA_API_PROXY_ENDPOINT,
issuesEndpoint: ISSUE_TYPES_ENDPOINT,
fieldsEndpoint: ISSUE_FIELDS_ENDPOINT,
boardsEndpoint: BOARDS_ENDPOINT,
@@ -296,6 +298,19 @@ const BlueprintSettings = (props) => {
configuredConnection
)
+ const {
+ fetchProjects: fetchGitlabProjects,
+ projects: gitlabProjects,
+ isFetching: isFetchingGitlab,
+ error: gitlabProxyError,
+ } = useGitlab(
+ {
+ apiProxyPath: GITLAB_API_PROXY_ENDPOINT,
+ projectsEndpoint: PROJECTS_ENDPOINT,
+ },
+ configuredConnection
+ )
+
const handleBlueprintActivation = useCallback(
(blueprint) => {
if (blueprint.enable) {
@@ -454,7 +469,7 @@ const BlueprintSettings = (props) => {
break
case Providers.GITLAB:
isValid = Array.isArray(projects[configuredConnection?.id]) &&
- validateNumericSet(projects[configuredConnection?.id]) &&
+ projects[configuredConnection?.id]?.length > 0 &&
entities[configuredConnection?.id]?.length > 0
break
case Providers.JIRA:
@@ -529,17 +544,13 @@ const BlueprintSettings = (props) => {
}, [setConfiguredBoard])
// @todo: lift higher to dsm hook
- const getJiraMappedBoards = useCallback((boardIds = [], boardListItems = []) => {
- return boardIds.map((bId, sIdx) => {
- const boardObject = boardListItems.find(apiBoard => Number(apiBoard.id) === Number(bId))
+ const getJiraMappedBoards = useCallback((options = []) => {
+ return options.map(({ boardId, title }, sIdx) => {
return {
- ...boardObject,
- id: boardObject?.id || bId || sIdx + 1,
- key: sIdx,
- value: boardObject?.name || `Board ${bId}`,
- title: boardObject?.name || `Board ${bId}`,
- type: boardObject?.type || 'scrum',
- self: `https://${scopeConnection?.endpoint}agile/1.0/board/${bId}`
+ id: boardId,
+ key: boardId,
+ value: boardId,
+ title: title || `Board ${boardId}`,
}
})
}, [scopeConnection?.endpoint])
@@ -579,20 +590,45 @@ const BlueprintSettings = (props) => {
useEffect(() => {
console.log('>>> ACTIVE BLUEPRINT ....', activeBlueprint)
const getGithubProjects = (c) => [Providers.GITHUB].includes(c.plugin)
- ? c.scope.map((s) => `${s.options.owner}/${s.options?.repo}`)
+ ? c.scope.map((s) => ({
+ id: `${s.options.owner}/${s.options?.repo}`,
+ key: `${s.options.owner}/${s.options?.repo}`,
+ value: `${s.options.owner}/${s.options?.repo}`,
+ title: `${s.options.owner}/${s.options?.repo}`,
+ }))
: []
const getGitlabProjects = (c) => [Providers.GITLAB].includes(c.plugin)
- ? c.scope.map((s) => s.options?.projectId)
+ ? c.scope.map((s) => ({
+ id: s.options?.projectId,
+ key: s.options?.projectId,
+ value: s.options?.projectId,
+ title: s.options?.title || `Project ${s.options?.projectId}`,
+ }))
: []
// @todo: handle multi-stage
const getAdvancedGithubProjects = (t, providerId) => [Providers.GITHUB].includes(providerId)
- ? [`${t.options?.owner}/${t.options?.repo}`]
+ ? [{
+ id: `${t.options?.owner}/${t.options?.repo}`,
+ key: `${t.options?.owner}/${t.options?.repo}`,
+ value: `${t.options?.owner}/${t.options?.repo}`,
+ title: `${t.options?.owner}/${t.options?.repo}`,
+ }]
: []
const getAdvancedGitlabProjects = (t, providerId) => [Providers.GITLAB].includes(providerId)
- ? [t.options?.projectId]
+ ? [{
+ id: t.options?.projectId,
+ key: t.options?.projectId,
+ value: t.options?.projectId,
+ title: t.options?.title || `Project ${t.options?.projectId}`,
+ }]
: []
const getAdvancedJiraBoards = (t, providerId) => [Providers.JIRA].includes(providerId)
- ? [t.options?.boardId]
+ ? [{
+ id: t.options?.boardId,
+ key: t.options?.boardId,
+ value: t.options?.boardId,
+ title: t.options?.title || `Board ${t.options?.boardId}`,
+ }]
: []
// @todo: migrate to data scopes manager
if (activeBlueprint?.id && activeBlueprint?.mode === BlueprintMode.NORMAL) {
@@ -615,12 +651,12 @@ const BlueprintSettings = (props) => {
? getGitlabProjects(c)
: getGithubProjects(c),
boards: [Providers.JIRA].includes(c.plugin)
- ? c.scope.map((s) => `Board ${s.options?.boardId}`)
+ ? c.scope.map((s) => s.options?.title || `Board ${s.options?.boardId}`)
: [],
boardIds: [Providers.JIRA].includes(c.plugin)
? c.scope.map((s) => s.options?.boardId)
: [],
- boardsList: allJiraResources?.boards ? getJiraMappedBoards(c.scope.map((s) => s.options?.boardId), allJiraResources?.boards) : [],
+ boardsList: getJiraMappedBoards(c.scope.map((s) => s.options)),
transformations: c.scope.map((s) => ({ ...s.transformation })),
transformationStates: c.scope.map((s) =>
Object.values(s.transformation).some((v) => Array.isArray(v) ? v.length > 0 : (v && typeof v === 'object' ? Object.keys(v)?.length > 0 : v?.toString().length > 0))
@@ -658,13 +694,13 @@ const BlueprintSettings = (props) => {
entities: ['-'],
entitityList: getDefaultEntities(c.plugin),
boards: [Providers.JIRA].includes(c.plugin)
- ? getAdvancedJiraBoards(c, c.plugin).map(bId => `Board ${bId}`)
+ ? getAdvancedJiraBoards(c, c.plugin).map(board => board.title)
: [],
boardIds: [Providers.JIRA].includes(c.plugin)
? getAdvancedJiraBoards(c, c.plugin)
: [],
- boardList: [Providers.JIRA].includes(c.plugin)
- ? getAdvancedJiraBoards(c, c.plugin).map(bId => `Board ${bId}`)
+ boardsList: [Providers.JIRA].includes(c.plugin)
+ ? getAdvancedJiraBoards(c, c.plugin)
: [],
transformations: {},
// transformationStates: ['-'],
@@ -1190,7 +1226,7 @@ const BlueprintSettings = (props) => {
blueprint={activeBlueprint}
onModify={modifyConnection}
mode={activeBlueprint?.mode}
- loading={isFetchingBlueprint || isFetchingJIRA}
+ loading={isFetchingBlueprint || isFetchingJIRA || isFetchingGitlab}
/>
</div>
)
@@ -1228,7 +1264,7 @@ const BlueprintSettings = (props) => {
onModify={() => modifySetting('plan')}
mode={activeBlueprint?.mode}
classNames={['advanced-mode-grid']}
- loading={isFetchingBlueprint || isFetchingJIRA}
+ loading={isFetchingBlueprint || isFetchingJIRA || isFetchingGitlab}
/>
</div>
)}
@@ -1355,6 +1391,10 @@ const BlueprintSettings = (props) => {
fieldsList={jiraApiFields}
isFetching={isFetchingBlueprint}
isFetchingJIRA={isFetchingJIRA}
+ fetchGitlabProjects={fetchGitlabProjects}
+ gitlabProjects={gitlabProjects}
+ isFetchingGitlab={isFetchingGitlab}
+ gitlabProxyError={gitlabProxyError}
setConfiguredProject={setConfiguredProject}
setConfiguredBoard={setConfiguredBoard}
setBoards={setBoards}
diff --git a/config-ui/src/pages/blueprints/create-blueprint.jsx b/config-ui/src/pages/blueprints/create-blueprint.jsx
index 8602b6fe..fdc7c717 100644
--- a/config-ui/src/pages/blueprints/create-blueprint.jsx
+++ b/config-ui/src/pages/blueprints/create-blueprint.jsx
@@ -20,7 +20,7 @@ import { CSSTransition } from 'react-transition-group'
import { useHistory, useLocation, Link } from 'react-router-dom'
import dayjs from '@/utils/time'
import {
- API_PROXY_ENDPOINT,
+ JIRA_API_PROXY_ENDPOINT,
ISSUE_TYPES_ENDPOINT,
ISSUE_FIELDS_ENDPOINT,
BOARDS_ENDPOINT,
@@ -69,6 +69,8 @@ import AdvancedJSON from '@/components/blueprints/create-workflow/AdvancedJSON'
import { DEVLAKE_ENDPOINT } from '@/utils/config'
import request from '@/utils/request'
+import useGitlab from '@/hooks/useGitlab'
+import { GITLAB_API_PROXY_ENDPOINT, PROJECTS_ENDPOINT } from '@/config/gitlabApiProxy'
// import ConnectionTabs from '@/components/blueprints/ConnectionTabs'
@@ -241,7 +243,7 @@ const CreateBlueprint = (props) => {
error: jiraProxyError,
} = useJIRA(
{
- apiProxyPath: API_PROXY_ENDPOINT,
+ apiProxyPath: JIRA_API_PROXY_ENDPOINT,
issuesEndpoint: ISSUE_TYPES_ENDPOINT,
fieldsEndpoint: ISSUE_FIELDS_ENDPOINT,
boardsEndpoint: BOARDS_ENDPOINT,
@@ -249,6 +251,19 @@ const CreateBlueprint = (props) => {
configuredConnection
)
+ const {
+ fetchProjects: fetchGitlabProjects,
+ projects: gitlabProjects,
+ isFetching: isFetchingGitlab,
+ error: gitlabProxyError,
+ } = useGitlab(
+ {
+ apiProxyPath: GITLAB_API_PROXY_ENDPOINT,
+ projectsEndpoint: PROJECTS_ENDPOINT,
+ },
+ configuredConnection
+ )
+
const {
testConnection,
// eslint-disable-next-line no-unused-vars
@@ -350,7 +365,7 @@ const CreateBlueprint = (props) => {
null
)
- const activeTransformation = useMemo(() => transformations[configuredProject || configuredBoard?.id], [transformations, configuredProject, configuredBoard?.id])
+ const activeTransformation = useMemo(() => transformations[configuredProject?.id || configuredBoard?.id], [transformations, configuredProject?.id, configuredBoard?.id])
// eslint-disable-next-line no-unused-vars
const isValidStep = useCallback((stepId) => { }, [])
@@ -462,7 +477,7 @@ const CreateBlueprint = (props) => {
)
setTransformations((existingTransformations) => ({
...existingTransformations,
- [configuredProject]: {},
+ [configuredProject?.id]: {},
[configuredBoard?.id]: {},
}))
setConfiguredProject(null)
@@ -799,10 +814,8 @@ const CreateBlueprint = (props) => {
console.log('>> PROJECTS LIST', projects)
console.log('>> BOARDS LIST', boards)
- const projectTransformation = projects[configuredConnection?.id]
- const boardTransformation = boards[configuredConnection?.id]?.map(
- (b) => b.id
- )
+ const projectTransformation = projects[configuredConnection?.id]?.map(p => p.id)
+ const boardTransformation = boards[configuredConnection?.id]?.map(b => b.id)
if (projectTransformation) {
setTransformations((cT) => ({
...projectTransformation.reduce(initializeTransformations, {}),
@@ -1034,6 +1047,9 @@ const CreateBlueprint = (props) => {
blueprintConnections={blueprintConnections}
dataEntitiesList={dataEntitiesList}
boardsList={boardsList}
+ fetchGitlabProjects={fetchGitlabProjects}
+ isFetchingGitlab={isFetchingGitlab}
+ gitlabProjects={gitlabProjects}
boards={boards}
dataEntities={dataEntities}
projects={projects}
@@ -1046,6 +1062,7 @@ const CreateBlueprint = (props) => {
isSaving={isSaving}
isRunning={isRunning}
validationErrors={[...validationErrors, ...blueprintValidationErrors]}
+ isFetching={isFetchingJIRA || isFetchingGitlab || isFetchingConnection}
/>
)}
@@ -1058,7 +1075,6 @@ const CreateBlueprint = (props) => {
blueprintConnections={blueprintConnections}
dataEntities={dataEntities}
projects={projects}
- boardsList={boardsList}
boards={boards}
issueTypes={jiraApiIssueTypes}
fields={jiraApiFields}
@@ -1115,7 +1131,7 @@ const CreateBlueprint = (props) => {
onPrev={prevStep}
onSave={handleBlueprintSave}
onSaveAndRun={handleBlueprintSaveAndRun}
- isLoading={isSaving || isFetchingJIRA || isFetchingConnection || isTestingConnection}
+ isLoading={isSaving || isFetchingJIRA || isFetchingGitlab || isFetchingConnection || isTestingConnection}
isValid={advancedMode ? isValidBlueprint && isValidPipeline : isValidBlueprint}
canGoNext={canAdvanceNext}
/>
diff --git a/config-ui/src/pages/configure/settings/github.jsx b/config-ui/src/pages/configure/settings/github.jsx
index 9afeb793..0f53a5b2 100644
--- a/config-ui/src/pages/configure/settings/github.jsx
+++ b/config-ui/src/pages/configure/settings/github.jsx
@@ -51,12 +51,12 @@ export default function GithubSettings (props) {
// eslint-disable-next-line no-unused-vars
const handleSettingsChange = useCallback((setting) => {
- onSettingsChange(setting, configuredProject)
+ onSettingsChange(setting, configuredProject?.id)
}, [onSettingsChange, configuredProject])
const handleAdditionalSettings = useCallback((setting) => {
setEnableAdditionalCalculations(setting)
- onSettingsChange({ refdiff: setting ? { tagsOrder: '', tagsPattern: '', tagsLimit: 10, } : null }, configuredProject)
+ onSettingsChange({ refdiff: setting ? { tagsOrder: '', tagsPattern: '', tagsLimit: 10, } : null }, configuredProject?.id)
}, [setEnableAdditionalCalculations, configuredProject, onSettingsChange])
useEffect(() => {
@@ -94,7 +94,7 @@ export default function GithubSettings (props) {
placeholder='severity/(.*)$'
// defaultValue={transformation?.issueSeverity}
value={transformation?.issueSeverity}
- onChange={(e) => onSettingsChange({ issueSeverity: e.target.value }, configuredProject)}
+ onChange={(e) => onSettingsChange({ issueSeverity: e.target.value }, configuredProject?.id)}
disabled={isSaving || isSavingConnection}
className='input'
maxLength={255}
@@ -115,7 +115,7 @@ export default function GithubSettings (props) {
id='github-issue-component'
placeholder='component/(.*)$'
value={transformation?.issueComponent}
- onChange={(e) => onSettingsChange({ issueComponent: e.target.value }, configuredProject)}
+ onChange={(e) => onSettingsChange({ issueComponent: e.target.value }, configuredProject?.id)}
disabled={isSaving || isSavingConnection}
className='input'
maxLength={255}
@@ -135,7 +135,7 @@ export default function GithubSettings (props) {
id='github-issue-priority'
placeholder='(highest|high|medium|low)$'
value={transformation?.issuePriority}
- onChange={(e) => onSettingsChange({ issuePriority: e.target.value }, configuredProject)}
+ onChange={(e) => onSettingsChange({ issuePriority: e.target.value }, configuredProject?.id)}
disabled={isSaving || isSavingConnection}
className='input'
maxLength={255}
@@ -155,7 +155,7 @@ export default function GithubSettings (props) {
id='github-issue-requirement'
placeholder='(feat|feature|proposal|requirement)$'
value={transformation?.issueTypeRequirement}
- onChange={(e) => onSettingsChange({ issueTypeRequirement: e.target.value }, configuredProject)}
+ onChange={(e) => onSettingsChange({ issueTypeRequirement: e.target.value }, configuredProject?.id)}
disabled={isSaving || isSavingConnection}
className='input'
maxLength={255}
@@ -175,7 +175,7 @@ export default function GithubSettings (props) {
id='github-issue-bug'
placeholder='(bug|broken)$'
value={transformation?.issueTypeBug}
- onChange={(e) => onSettingsChange({ issueTypeBug: e.target.value }, configuredProject)}
+ onChange={(e) => onSettingsChange({ issueTypeBug: e.target.value }, configuredProject?.id)}
disabled={isSaving || isSavingConnection}
className='input'
maxLength={255}
@@ -195,7 +195,7 @@ export default function GithubSettings (props) {
id='github-issue-incident'
placeholder='(incident|p0|p1|p2)$'
value={transformation?.issueTypeIncident}
- onChange={(e) => onSettingsChange({ issueTypeIncident: e.target.value }, configuredProject)}
+ onChange={(e) => onSettingsChange({ issueTypeIncident: e.target.value }, configuredProject?.id)}
disabled={isSaving || isSavingConnection}
className='input'
maxLength={255}
@@ -224,7 +224,7 @@ export default function GithubSettings (props) {
id='github-pr-type'
placeholder='type/(.*)$'
value={transformation?.prType}
- onChange={(e) => onSettingsChange({ prType: e.target.value }, configuredProject)}
+ onChange={(e) => onSettingsChange({ prType: e.target.value }, configuredProject?.id)}
disabled={isSaving || isSavingConnection}
className='input'
maxLength={255}
@@ -244,7 +244,7 @@ export default function GithubSettings (props) {
id='github-pr-type'
placeholder='component/(.*)$'
value={transformation?.prComponent}
- onChange={(e) => onSettingsChange({ prComponent: e.target.value }, configuredProject)}
+ onChange={(e) => onSettingsChange({ prComponent: e.target.value }, configuredProject?.id)}
disabled={isSaving || isSavingConnection}
className='input'
maxLength={255}
@@ -297,7 +297,7 @@ export default function GithubSettings (props) {
id='github-pr-body'
className='textarea'
placeholder='(?mi)(fix|close|resolve|fixes|closes|resolves|fixed|closed|resolved)[\s]*.*(((and )?(#|https:\/\/github.com\/%s\/%s\/issues\/)\d+[ ]*)+)'
- onChange={(e) => onSettingsChange({ prBodyClosePattern: e.target.value }, configuredProject)}
+ onChange={(e) => onSettingsChange({ prBodyClosePattern: e.target.value }, configuredProject?.id)}
disabled={isSaving || isSavingConnection}
fill
rows={2}
@@ -327,7 +327,7 @@ export default function GithubSettings (props) {
fill={true}
placeholder='10'
allowNumericCharactersOnly={true}
- onValueChange={(tagsLimitNumeric) => onSettingsChange({ refdiff: { ...transformation?.refdiff, tagsLimit: tagsLimitNumeric } }, configuredProject)}
+ onValueChange={(tagsLimitNumeric) => onSettingsChange({ refdiff: { ...transformation?.refdiff, tagsLimit: tagsLimitNumeric } }, configuredProject?.id)}
value={transformation?.refdiff?.tagsLimit}
/>
</FormGroup>
@@ -342,7 +342,7 @@ export default function GithubSettings (props) {
id='refdiff-tags-pattern'
placeholder='(regex)$'
value={transformation?.refdiff?.tagsPattern}
- onChange={(e) => onSettingsChange({ refdiff: { ...transformation?.refdiff, tagsPattern: e.target.value } }, configuredProject)}
+ onChange={(e) => onSettingsChange({ refdiff: { ...transformation?.refdiff, tagsPattern: e.target.value } }, configuredProject?.id)}
disabled={isSaving || isSavingConnection}
className='input'
maxLength={255}
@@ -359,7 +359,7 @@ export default function GithubSettings (props) {
id='refdiff-tags-order'
placeholder='reverse semver'
value={transformation?.refdiff?.tagsOrder}
- onChange={(e) => onSettingsChange({ refdiff: { ...transformation?.refdiff, tagsOrder: e.target.value } }, configuredProject)}
+ onChange={(e) => onSettingsChange({ refdiff: { ...transformation?.refdiff, tagsOrder: e.target.value } }, configuredProject?.id)}
disabled={isSaving || isSavingConnection}
className='input'
maxLength={255}