You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@devlake.apache.org by li...@apache.org on 2022/09/30 05:20:17 UTC

[incubator-devlake] branch main updated: fix(config-ui): change jira board selection box to be searchable (#3287)

This is an automated email from the ASF dual-hosted git repository.

likyh 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 13a46ac3 fix(config-ui): change jira board selection box to be searchable (#3287)
13a46ac3 is described below

commit 13a46ac3ff26bef85cd015b14c0a33898f98254e
Author: 青湛 <0x...@gmail.com>
AuthorDate: Fri Sep 30 13:20:12 2022 +0800

    fix(config-ui): change jira board selection box to be searchable (#3287)
---
 .../blueprints/BlueprintDataScopesDialog.jsx       |  2 +
 .../src/components/blueprints/BoardsSelector.jsx   |  9 ++-
 .../src/components/blueprints/DataScopesGrid.jsx   |  4 +-
 .../blueprints/create-workflow/DataScopes.jsx      |  2 +
 config-ui/src/hooks/useDataScopesManager.jsx       |  5 +-
 config-ui/src/hooks/useJIRA.jsx                    | 83 ++++++++++++----------
 .../src/pages/blueprints/blueprint-settings.jsx    | 82 +++++++++++++++------
 .../src/pages/blueprints/create-blueprint.jsx      |  9 +++
 8 files changed, 127 insertions(+), 69 deletions(-)

diff --git a/config-ui/src/components/blueprints/BlueprintDataScopesDialog.jsx b/config-ui/src/components/blueprints/BlueprintDataScopesDialog.jsx
index ff7fc34b..941e8e6f 100644
--- a/config-ui/src/components/blueprints/BlueprintDataScopesDialog.jsx
+++ b/config-ui/src/components/blueprints/BlueprintDataScopesDialog.jsx
@@ -74,6 +74,7 @@ const BlueprintDataScopesDialog = (props) => {
     issueTypesList = [],
     fieldsList = [],
     boards = {},
+    setBoardSearch = () => {},
     gitlabProjects = [],
     fetchGitlabProjects = () => [],
     entities = {},
@@ -178,6 +179,7 @@ const BlueprintDataScopesDialog = (props) => {
                 dataEntitiesList={dataEntitiesList}
                 boardsList={boardsList}
                 boards={boards}
+                setBoardSearch={setBoardSearch}
                 fetchGitlabProjects={fetchGitlabProjects}
                 gitlabProjects={gitlabProjects}
                 isFetchingGitlab={isFetchingGitlab}
diff --git a/config-ui/src/components/blueprints/BoardsSelector.jsx b/config-ui/src/components/blueprints/BoardsSelector.jsx
index 9c6d5b73..3e8b370e 100644
--- a/config-ui/src/components/blueprints/BoardsSelector.jsx
+++ b/config-ui/src/components/blueprints/BoardsSelector.jsx
@@ -24,7 +24,7 @@ const BoardsSelector = (props) => {
   const {
     boards = [],
     configuredConnection,
-    placeholder = 'Select boards',
+    placeholder = 'Search and select boards',
     items = [],
     selectedItems = [],
     // eslint-disable-next-line max-len
@@ -36,6 +36,7 @@ const BoardsSelector = (props) => {
     onItemSelect = () => {},
     onRemove = () => {},
     onClear = () => {},
+    onQueryChange = () => {},
     itemRenderer = (item, { handleClick, modifiers }) => (
       <MenuItem
         active={modifiers.active}
@@ -75,7 +76,7 @@ const BoardsSelector = (props) => {
         >
           <MultiSelect
             disabled={disabled || isSaving || isLoading}
-            // openOnKeyDown={true}
+            openOnKeyDown={true}
             resetOnSelect={true}
             placeholder={placeholder}
             popoverProps={{ usePortal: false, minimal: true }}
@@ -85,9 +86,6 @@ const BoardsSelector = (props) => {
             items={items}
             selectedItems={selectedItems}
             activeItem={activeItem}
-            itemPredicate={(query, item) =>
-              item?.title?.toLowerCase().indexOf(query.toLowerCase()) >= 0
-            }
             itemRenderer={itemRenderer}
             tagRenderer={tagRenderer}
             tagInputProps={{
@@ -97,6 +95,7 @@ const BoardsSelector = (props) => {
               }
             }}
             noResults={<MenuItem disabled={true} text='No Boards Available.' />}
+            onQueryChange={(query) => onQueryChange(query)}
             onRemove={(item) => {
               onRemove((rT) => {
                 return {
diff --git a/config-ui/src/components/blueprints/DataScopesGrid.jsx b/config-ui/src/components/blueprints/DataScopesGrid.jsx
index 9cc4f38a..16c87f5b 100644
--- a/config-ui/src/components/blueprints/DataScopesGrid.jsx
+++ b/config-ui/src/components/blueprints/DataScopesGrid.jsx
@@ -171,8 +171,8 @@ const DataScopesGrid = (props) => {
                     padding: 0
                   }}
                 >
-                  {c.boards.map((board, bIdx) => (
-                    <li key={`list-item-key-${bIdx}`}>{board}</li>
+                  {c.boardsList.map((board, bIdx) => (
+                    <li key={`list-item-key-${bIdx}`}>{board.title}</li>
                   ))}
                 </ul>
               )}
diff --git a/config-ui/src/components/blueprints/create-workflow/DataScopes.jsx b/config-ui/src/components/blueprints/create-workflow/DataScopes.jsx
index eea5d9b2..2091dfab 100644
--- a/config-ui/src/components/blueprints/create-workflow/DataScopes.jsx
+++ b/config-ui/src/components/blueprints/create-workflow/DataScopes.jsx
@@ -51,6 +51,7 @@ const DataScopes = (props) => {
     setDataEntities = () => {},
     setProjects = () => {},
     setBoards = () => {},
+    setBoardSearch = () => {},
     prevStep = () => {},
     fieldHasError = () => {},
     getFieldError = () => {},
@@ -199,6 +200,7 @@ const DataScopes = (props) => {
                       <BoardsSelector
                         items={boardsList}
                         selectedItems={selectedBoards}
+                        onQueryChange={setBoardSearch}
                         onItemSelect={setBoards}
                         onClear={setBoards}
                         onRemove={setBoards}
diff --git a/config-ui/src/hooks/useDataScopesManager.jsx b/config-ui/src/hooks/useDataScopesManager.jsx
index f0cf6fd1..d96cb2d0 100644
--- a/config-ui/src/hooks/useDataScopesManager.jsx
+++ b/config-ui/src/hooks/useDataScopesManager.jsx
@@ -458,14 +458,15 @@ function useDataScopesManager({
     (boardIds = [], boardListItems = []) => {
       return boardIds.map((bId, sIdx) => {
         const boardObject = boardListItems.find(
-          (apiBoard) => Number(apiBoard.id) === Number(bId)
+          (apiBoard) =>
+            Number(apiBoard.id) === Number(bId) || +apiBoard.boardId === +bId
         )
         return new JiraBoard({
           ...boardObject,
           id: boardObject?.id || bId || sIdx + 1,
           key: sIdx,
           value: bId,
-          title: boardObject?.name || `Board ${bId}`,
+          title: boardObject?.name || boardObject?.title || `Board ${bId}`,
           type: boardObject?.type || 'scrum',
           location: { ...boardObject?.location }
         })
diff --git a/config-ui/src/hooks/useJIRA.jsx b/config-ui/src/hooks/useJIRA.jsx
index 871b8de1..eccaa5be 100644
--- a/config-ui/src/hooks/useJIRA.jsx
+++ b/config-ui/src/hooks/useJIRA.jsx
@@ -122,48 +122,53 @@ const useJIRA = (
     }
   }, [fieldsEndpoint, activeConnection, apiProxyPath])
 
-  const fetchBoards = useCallback(() => {
-    // if (activeConnection?.plugin !== Providers.JIRA) {
-    //   return
-    // }
-    try {
-      if (apiProxyPath.includes('null') || !activeConnection?.connectionId) {
-        throw new Error('Connection ID is Null')
-      }
-      setError(null)
-      setIsFetching(true)
-      const fetchApiBoards = async () => {
-        const boards = await request
-          .get(
-            activeConnection?.connectionId
-              ? boardsEndpoint.replace(
-                  '[:connectionId:]',
-                  activeConnection?.connectionId
-                )
-              : boardsEndpoint
+  const fetchBoards = useCallback(
+    async (search, callback = () => {}) => {
+      // if (activeConnection?.plugin !== Providers.JIRA) {
+      //   return
+      // }
+      try {
+        if (apiProxyPath.includes('null') || !activeConnection?.connectionId) {
+          throw new Error('Connection ID is Null')
+        }
+        setError(null)
+        setIsFetching(true)
+        const fetchApiBoards = async () => {
+          const boards = await request
+            .get(
+              activeConnection?.connectionId
+                ? `${boardsEndpoint.replace(
+                    '[:connectionId:]',
+                    activeConnection?.connectionId
+                  )}?name=${search}`
+                : `${boardsEndpoint}?name=${search}`
+            )
+            .catch((e) => setError(e))
+          console.log('>>> JIRA API PROXY: Boards Response...', boards)
+          setBoardsResponse(
+            boards && Array.isArray(boards.data?.values)
+              ? boards.data?.values
+              : []
           )
-          .catch((e) => setError(e))
-        console.log('>>> JIRA API PROXY: Boards Response...', boards)
-        setBoardsResponse(
-          boards && Array.isArray(boards.data?.values)
-            ? boards.data?.values
-            : []
-        )
-        // setTimeout(() => {
+          // setTimeout(() => {
+          setIsFetching(false)
+          // }, 1000)
+          return boards.data.values
+        }
+        const res = await fetchApiBoards()
+        if (callback) callback(res)
+      } catch (e) {
         setIsFetching(false)
-        // }, 1000)
+        setError(e)
+        ToastNotification.show({
+          message: e.message,
+          intent: 'danger',
+          icon: 'error'
+        })
       }
-      fetchApiBoards()
-    } catch (e) {
-      setIsFetching(false)
-      setError(e)
-      ToastNotification.show({
-        message: e.message,
-        intent: 'danger',
-        icon: 'error'
-      })
-    }
-  }, [boardsEndpoint, activeConnection, apiProxyPath])
+    },
+    [boardsEndpoint, activeConnection, apiProxyPath]
+  )
 
   const fetchAllResources = useCallback(
     async (connectionId, callback = () => {}) => {
diff --git a/config-ui/src/pages/blueprints/blueprint-settings.jsx b/config-ui/src/pages/blueprints/blueprint-settings.jsx
index 14b64352..cb1c9355 100644
--- a/config-ui/src/pages/blueprints/blueprint-settings.jsx
+++ b/config-ui/src/pages/blueprints/blueprint-settings.jsx
@@ -117,6 +117,8 @@ const BlueprintSettings = (props) => {
   const [runTasks, setRunTasks] = useState([])
   const [runTasksAdvanced, setRunTasksAdvanced] = useState([])
 
+  const [boardSearch, setBoardSearch] = useState()
+
   const {
     // eslint-disable-next-line no-unused-vars
     activeStep,
@@ -671,8 +673,11 @@ const BlueprintSettings = (props) => {
                 connectionsList,
                 [Providers.JIRA].includes(c.plugin)
                   ? getJiraMappedBoards(
-                      c.scope.map((s) => s.options?.boardId),
-                      allJiraResources?.boards
+                      c.scope?.map((s) => s.options?.boardId),
+                      [
+                        ...allJiraResources?.boards,
+                        ...c.scope.map((s) => s.options)
+                      ]
                     )
                   : []
               )
@@ -697,7 +702,10 @@ const BlueprintSettings = (props) => {
                 [Providers.JIRA].includes(c.plugin)
                   ? getJiraMappedBoards(
                       c.scope?.map((s) => s.options?.boardId),
-                      allJiraResources?.boards
+                      [
+                        ...allJiraResources?.boards,
+                        ...c.scope.map((s) => s.options)
+                      ]
                     )
                   : []
               )
@@ -897,35 +905,66 @@ const BlueprintSettings = (props) => {
       scopeConnection?.connectionId &&
       activeBlueprint?.mode === BlueprintMode.NORMAL
     ) {
-      fetchAllResources(
-        scopeConnection?.connectionId,
-        (jiraResourcesResponse) => {
-          setConnections((Cs) =>
-            Cs.map(
-              (c) =>
-                new DataScopeConnection({
-                  ...c,
-                  boardsList: jiraResourcesResponse?.boards
-                    ? getJiraMappedBoards(
-                        c.boardIds,
-                        jiraResourcesResponse?.boards
-                      )
-                    : []
-                })
-            )
+      fetchIssueTypes()
+      fetchFields()
+      fetchBoards(undefined, (boards) =>
+        setConnections((Cs) =>
+          Cs.map(
+            (c) =>
+              new DataScopeConnection({
+                ...c,
+                boardsList: getJiraMappedBoards(c.boardIds, [
+                  ...(boards ?? []),
+                  ...c.scope.map((s) => s.options)
+                ])
+              })
           )
-        }
+        )
       )
     }
   }, [
     activeBlueprint?.mode,
-    fetchAllResources,
+    fetchIssueTypes,
+    fetchFields,
+    fetchBoards,
     scopeConnection?.connectionId,
     scopeConnection?.providerId,
     getJiraMappedBoards,
     setConnections
   ])
 
+  useEffect(() => {
+    if (
+      scopeConnection?.providerId === Providers.JIRA &&
+      scopeConnection?.connectionId &&
+      activeBlueprint?.mode === BlueprintMode.NORMAL &&
+      boardSearch
+    ) {
+      fetchBoards(boardSearch, (boards) =>
+        setConnections((Cs) =>
+          Cs.map(
+            (c) =>
+              new DataScopeConnection({
+                ...c,
+                boardsList: getJiraMappedBoards(c.boardIds, [
+                  ...(boards ?? []),
+                  ...c.scope.map((s) => s.options)
+                ])
+              })
+          )
+        )
+      )
+    }
+  }, [
+    activeBlueprint?.mode,
+    fetchBoards,
+    scopeConnection?.connectionId,
+    scopeConnection?.providerId,
+    getJiraMappedBoards,
+    setConnections,
+    boardSearch
+  ])
+
   useEffect(() => {
     console.log('>>> PROJECTS SELECTED...', projects)
     if (configuredConnection?.id) {
@@ -1405,6 +1444,7 @@ const BlueprintSettings = (props) => {
         provider={activeProvider}
         entities={entities}
         boards={boards}
+        setBoardSearch={setBoardSearch}
         boardsList={jiraApiBoards}
         projects={projects}
         issueTypesList={jiraApiIssueTypes}
diff --git a/config-ui/src/pages/blueprints/create-blueprint.jsx b/config-ui/src/pages/blueprints/create-blueprint.jsx
index 193a6e66..2c2bd83c 100644
--- a/config-ui/src/pages/blueprints/create-blueprint.jsx
+++ b/config-ui/src/pages/blueprints/create-blueprint.jsx
@@ -134,6 +134,8 @@ const CreateBlueprint = (props) => {
   // eslint-disable-next-line no-unused-vars
   const [canAdvancePrev, setCanAdvancePrev] = useState(true)
 
+  const [boardSearch, setBoardSearch] = useState()
+
   const {
     activeConnection,
     // eslint-disable-next-line no-unused-vars
@@ -688,6 +690,12 @@ const CreateBlueprint = (props) => {
     mode
   ])
 
+  useEffect(() => {
+    if (boardSearch) {
+      fetchBoards(boardSearch)
+    }
+  }, [fetchBoards, boardSearch])
+
   useEffect(() => {
     console.log(
       '>> PIPELINE RUN TASK SETTINGS FOR PIPELINE MANAGER ....',
@@ -1137,6 +1145,7 @@ const CreateBlueprint = (props) => {
                       setDataEntities={setDataEntities}
                       setProjects={setProjects}
                       setBoards={setBoards}
+                      setBoardSearch={setBoardSearch}
                       prevStep={prevStep}
                       isSaving={isSaving}
                       isRunning={isRunning}