You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@devlake.apache.org by GitBox <gi...@apache.org> on 2022/08/19 12:04:21 UTC

[GitHub] [incubator-devlake] e2corporation opened a new pull request, #2780: feat: create paginator hook and paginate blueprints grid (draft)

e2corporation opened a new pull request, #2780:
URL: https://github.com/apache/incubator-devlake/pull/2780

   ### ⚠️ Config-UI / Hooks / Paginator (_DRAFT_)
   
   
   - [ ] Create Paginator Hook
      - [ ] Complete Basic Client-Side Pagination Support
      - [ ] Enable Filter Support
   - [ ] Integrate w/ Blueprints Grid
   - [ ] Integrate w/ Historical Runs Grid (Blueprint _Status_)
   
   ### Description
   
   This PR creates a new **Paginator Hook** that will allow Page Components to use `client-side` pagination on larger data sets. Later on, the Paginator will be further enhanced to support `server-side` pagination to better accommodate listing of many pipelines (historical runs).
   
   
   ### Does this close any open issues?
   `TBD`
   
   
   


-- 
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: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] likyh commented on a diff in pull request #2780: feat: create paginator hook and paginate blueprints grid

Posted by GitBox <gi...@apache.org>.
likyh commented on code in PR #2780:
URL: https://github.com/apache/incubator-devlake/pull/2780#discussion_r954872593


##########
config-ui/src/hooks/usePaginator.jsx:
##########
@@ -0,0 +1,217 @@
+/*
+ * 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, useRef, useCallback, useMemo } from 'react'
+import {
+  Popover,
+  Menu,
+  MenuItem,
+  Button
+} from '@blueprintjs/core'
+
+import { integrationsData } from '@/data/integrations'
+
+const PagingOptionsMenu = (props) => {
+  const { pageOptions = [10, 25, 50, 75, 100], perPage = 10, setPerPage = (page) => undefined } = props
+  return (
+    <Menu>
+      {pageOptions && pageOptions.map(pageOption => (
+        <MenuItem
+          key={pageOption}
+          active={perPage === pageOption}
+          icon='key-option'
+          text={`${pageOption} Records`}
+          onClick={() => setPerPage(pageOption)}
+        />))}
+    </Menu>
+  )
+}
+
+const Controls = (props) => {
+  const {
+    enabled = true,
+    pagingOptionsMenu,
+    currentPage,
+    perPage = 10,
+    maxPage,
+    onPrevPage = () => {},
+    onNextPage = () => {},
+    isLoading = false,
+  } = props
+
+  return (
+    <div
+      className='pagination-controls'
+      style={{ display: 'flex', whiteSpace: 'nowrap' }}
+    >
+      <Popover placement='bottom'>
+        <Button
+          className='btn-select-page-size'
+          style={{ whiteSpace: 'nowrap' }}
+          icon='numbered-list'
+          text={`Rows: ${perPage}`}
+          disabled={isLoading}
+          outlined
+          minimal
+        />
+        <>{pagingOptionsMenu}</>
+      </Popover>
+      <Button
+        onClick={onPrevPage}
+        className='pagination-btn btn-prev-page'
+        icon='step-backward'
+        small
+        text='PREV'
+        style={{ marginLeft: '5px', marginRight: '5px', whiteSpace: 'nowrap' }}
+        disabled={currentPage === 1 || isLoading}
+      />
+      <Button
+        style={{ whiteSpace: 'nowrap' }}
+        disabled={currentPage === maxPage || isLoading}
+        onClick={onNextPage}
+        className='pagination-btn btn-next-page'
+        rightIcon='step-forward'
+        text='NEXT'
+        small
+      />
+    </div>
+  )
+}
+
+function usePaginator (initialLoadingState = false) {
+  // const [integrations, setIntegrations] = useState(integrationsData)
+
+  const [_data, _setData] = useState([])
+
+  // filter related
+  const [filterParams, setFilterParams] = useState({})
+  const [filterFunc, setFilterFunc] = useState(() => (params, item) => true)
+  const filteredData = useMemo(() => {
+    console.log('>> SET FILTER DATA BY', filterParams, _data)
+    const filteredData = []
+    for (const item of _data) {
+      console.log(item)
+      if (filterFunc(filterParams, item)) {
+        filteredData.push(item)
+      }
+    }
+    return filteredData
+  }, [_data, filterParams, filterFunc])
+
+  // page related
+  const [pagedData, setPagedData] = useState([])
+  const [pageOptions, setPageOptions] = useState([5, 25, 50, 75, 100])
+  const [currentPage, setCurrentPage] = useState(1)
+  const [perPage, setPerPage] = useState(pageOptions[1])
+  const [maxPage, setMaxPage] = useState(0)

Review Comment:
   Yes, we should use fewer useEffect+setter



-- 
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: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] e2corporation commented on a diff in pull request #2780: feat: create paginator hook and paginate blueprints grid

Posted by GitBox <gi...@apache.org>.
e2corporation commented on code in PR #2780:
URL: https://github.com/apache/incubator-devlake/pull/2780#discussion_r954261429


##########
config-ui/src/hooks/usePaginator.jsx:
##########
@@ -0,0 +1,217 @@
+/*
+ * 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, useRef, useCallback, useMemo } from 'react'
+import {
+  Popover,
+  Menu,
+  MenuItem,
+  Button
+} from '@blueprintjs/core'
+
+import { integrationsData } from '@/data/integrations'
+
+const PagingOptionsMenu = (props) => {
+  const { pageOptions = [10, 25, 50, 75, 100], perPage = 10, setPerPage = (page) => undefined } = props
+  return (
+    <Menu>
+      {pageOptions && pageOptions.map(pageOption => (
+        <MenuItem
+          key={pageOption}
+          active={perPage === pageOption}
+          icon='key-option'
+          text={`${pageOption} Records`}
+          onClick={() => setPerPage(pageOption)}
+        />))}
+    </Menu>
+  )
+}
+
+const Controls = (props) => {
+  const {
+    enabled = true,
+    pagingOptionsMenu,
+    currentPage,
+    perPage = 10,
+    maxPage,
+    onPrevPage = () => {},
+    onNextPage = () => {},
+    isLoading = false,
+  } = props
+
+  return (
+    <div
+      className='pagination-controls'
+      style={{ display: 'flex', whiteSpace: 'nowrap' }}
+    >
+      <Popover placement='bottom'>
+        <Button
+          className='btn-select-page-size'
+          style={{ whiteSpace: 'nowrap' }}
+          icon='numbered-list'
+          text={`Rows: ${perPage}`}
+          disabled={isLoading}
+          outlined
+          minimal
+        />
+        <>{pagingOptionsMenu}</>
+      </Popover>
+      <Button
+        onClick={onPrevPage}
+        className='pagination-btn btn-prev-page'
+        icon='step-backward'
+        small
+        text='PREV'
+        style={{ marginLeft: '5px', marginRight: '5px', whiteSpace: 'nowrap' }}
+        disabled={currentPage === 1 || isLoading}
+      />
+      <Button
+        style={{ whiteSpace: 'nowrap' }}
+        disabled={currentPage === maxPage || isLoading}
+        onClick={onNextPage}
+        className='pagination-btn btn-next-page'
+        rightIcon='step-forward'
+        text='NEXT'
+        small
+      />
+    </div>
+  )
+}
+
+function usePaginator (initialLoadingState = false) {
+  // const [integrations, setIntegrations] = useState(integrationsData)
+
+  const [_data, _setData] = useState([])
+
+  // filter related
+  const [filterParams, setFilterParams] = useState({})
+  const [filterFunc, setFilterFunc] = useState(() => (params, item) => true)
+  const filteredData = useMemo(() => {
+    console.log('>> SET FILTER DATA BY', filterParams, _data)
+    const filteredData = []
+    for (const item of _data) {
+      console.log(item)
+      if (filterFunc(filterParams, item)) {
+        filteredData.push(item)
+      }
+    }
+    return filteredData
+  }, [_data, filterParams, filterFunc])
+
+  // page related
+  const [pagedData, setPagedData] = useState([])
+  const [pageOptions, setPageOptions] = useState([5, 25, 50, 75, 100])
+  const [currentPage, setCurrentPage] = useState(1)
+  const [perPage, setPerPage] = useState(pageOptions[1])
+  const [maxPage, setMaxPage] = useState(0)
+
+  // others
+  const [isLoading, setIsLoading] = useState(initialLoadingState || false)
+  const [isProcessing, setIsProcessing] = useState(false)
+  const [refresh, setRefresh] = useState(false)
+
+  const reCalMaxPage = useCallback(() => {
+    setMaxPage(Math.max(1, Math.ceil(filteredData.length / perPage)))
+    console.log('>> MAX PAGE = ', Math.max(1, Math.ceil(filteredData.length / perPage)))
+  }, [filteredData, perPage, setMaxPage])
+
+  const setData = useCallback((data) => {
+    console.log('>> SET ALL DATA...', _data)
+    _setData(data || [])
+    reCalMaxPage()
+  }, [_setData, setRefresh])
+
+  const goNextPage = useCallback(() => {
+    console.log('>>> PAGINATOR: GO NEXT PAGE ...')
+    setCurrentPage(currentPage => Math.min(maxPage, currentPage + 1))
+    // setRefresh((r) => !r)
+    console.log('>>>> NEXT PAGE', currentPage)
+  }, [maxPage, currentPage, setRefresh])
+
+  const goPrevPage = useCallback(() => {
+    console.log('>>> PAGINATOR: GO PREV PAGE ...')
+    setCurrentPage(currentPage => Math.max(1, currentPage - 1))
+    // setRefresh((r) => !r)
+    console.log('>>>> PREV PAGE', currentPage)
+  }, [maxPage, currentPage, setRefresh])
+
+  const changePerPage = useCallback((perPage) => {
+    setPerPage(perPage)
+    setCurrentPage(1)
+    reCalMaxPage()

Review Comment:
   Remove this call after `reCalMaxPage` is deleted.



-- 
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: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] e2corporation commented on a diff in pull request #2780: feat: create paginator hook and paginate blueprints grid

Posted by GitBox <gi...@apache.org>.
e2corporation commented on code in PR #2780:
URL: https://github.com/apache/incubator-devlake/pull/2780#discussion_r954259315


##########
config-ui/src/hooks/usePaginator.jsx:
##########
@@ -0,0 +1,217 @@
+/*
+ * 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, useRef, useCallback, useMemo } from 'react'
+import {
+  Popover,
+  Menu,
+  MenuItem,
+  Button
+} from '@blueprintjs/core'
+
+import { integrationsData } from '@/data/integrations'
+
+const PagingOptionsMenu = (props) => {
+  const { pageOptions = [10, 25, 50, 75, 100], perPage = 10, setPerPage = (page) => undefined } = props
+  return (
+    <Menu>
+      {pageOptions && pageOptions.map(pageOption => (
+        <MenuItem
+          key={pageOption}
+          active={perPage === pageOption}
+          icon='key-option'
+          text={`${pageOption} Records`}
+          onClick={() => setPerPage(pageOption)}
+        />))}
+    </Menu>
+  )
+}
+
+const Controls = (props) => {
+  const {
+    enabled = true,
+    pagingOptionsMenu,
+    currentPage,
+    perPage = 10,
+    maxPage,
+    onPrevPage = () => {},
+    onNextPage = () => {},
+    isLoading = false,
+  } = props
+
+  return (
+    <div
+      className='pagination-controls'
+      style={{ display: 'flex', whiteSpace: 'nowrap' }}
+    >
+      <Popover placement='bottom'>
+        <Button
+          className='btn-select-page-size'
+          style={{ whiteSpace: 'nowrap' }}
+          icon='numbered-list'
+          text={`Rows: ${perPage}`}
+          disabled={isLoading}
+          outlined
+          minimal
+        />
+        <>{pagingOptionsMenu}</>
+      </Popover>
+      <Button
+        onClick={onPrevPage}
+        className='pagination-btn btn-prev-page'
+        icon='step-backward'
+        small
+        text='PREV'
+        style={{ marginLeft: '5px', marginRight: '5px', whiteSpace: 'nowrap' }}
+        disabled={currentPage === 1 || isLoading}
+      />
+      <Button
+        style={{ whiteSpace: 'nowrap' }}
+        disabled={currentPage === maxPage || isLoading}
+        onClick={onNextPage}
+        className='pagination-btn btn-next-page'
+        rightIcon='step-forward'
+        text='NEXT'
+        small
+      />
+    </div>
+  )
+}
+
+function usePaginator (initialLoadingState = false) {
+  // const [integrations, setIntegrations] = useState(integrationsData)
+
+  const [_data, _setData] = useState([])
+
+  // filter related
+  const [filterParams, setFilterParams] = useState({})
+  const [filterFunc, setFilterFunc] = useState(() => (params, item) => true)
+  const filteredData = useMemo(() => {
+    console.log('>> SET FILTER DATA BY', filterParams, _data)
+    const filteredData = []
+    for (const item of _data) {
+      console.log(item)
+      if (filterFunc(filterParams, item)) {
+        filteredData.push(item)
+      }
+    }
+    return filteredData
+  }, [_data, filterParams, filterFunc])
+
+  // page related
+  const [pagedData, setPagedData] = useState([])
+  const [pageOptions, setPageOptions] = useState([5, 25, 50, 75, 100])
+  const [currentPage, setCurrentPage] = useState(1)
+  const [perPage, setPerPage] = useState(pageOptions[1])
+  const [maxPage, setMaxPage] = useState(0)
+
+  // others
+  const [isLoading, setIsLoading] = useState(initialLoadingState || false)
+  const [isProcessing, setIsProcessing] = useState(false)
+  const [refresh, setRefresh] = useState(false)
+
+  const reCalMaxPage = useCallback(() => {
+    setMaxPage(Math.max(1, Math.ceil(filteredData.length / perPage)))
+    console.log('>> MAX PAGE = ', Math.max(1, Math.ceil(filteredData.length / perPage)))
+  }, [filteredData, perPage, setMaxPage])
+
+  const setData = useCallback((data) => {

Review Comment:
   This callback is unnecessary and should be removed since `setData` will be exported `Ln 98` is refactored.



-- 
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: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] likyh commented on a diff in pull request #2780: feat: create paginator hook and paginate blueprints grid

Posted by GitBox <gi...@apache.org>.
likyh commented on code in PR #2780:
URL: https://github.com/apache/incubator-devlake/pull/2780#discussion_r954441922


##########
config-ui/src/hooks/usePaginator.jsx:
##########
@@ -0,0 +1,217 @@
+/*
+ * 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, useRef, useCallback, useMemo } from 'react'
+import {
+  Popover,
+  Menu,
+  MenuItem,
+  Button
+} from '@blueprintjs/core'
+
+import { integrationsData } from '@/data/integrations'
+
+const PagingOptionsMenu = (props) => {
+  const { pageOptions = [10, 25, 50, 75, 100], perPage = 10, setPerPage = (page) => undefined } = props
+  return (
+    <Menu>
+      {pageOptions && pageOptions.map(pageOption => (
+        <MenuItem
+          key={pageOption}
+          active={perPage === pageOption}
+          icon='key-option'
+          text={`${pageOption} Records`}
+          onClick={() => setPerPage(pageOption)}
+        />))}
+    </Menu>
+  )
+}
+
+const Controls = (props) => {
+  const {
+    enabled = true,
+    pagingOptionsMenu,
+    currentPage,
+    perPage = 10,
+    maxPage,
+    onPrevPage = () => {},
+    onNextPage = () => {},
+    isLoading = false,
+  } = props
+
+  return (
+    <div
+      className='pagination-controls'
+      style={{ display: 'flex', whiteSpace: 'nowrap' }}
+    >
+      <Popover placement='bottom'>
+        <Button
+          className='btn-select-page-size'
+          style={{ whiteSpace: 'nowrap' }}
+          icon='numbered-list'
+          text={`Rows: ${perPage}`}
+          disabled={isLoading}
+          outlined
+          minimal
+        />
+        <>{pagingOptionsMenu}</>
+      </Popover>
+      <Button
+        onClick={onPrevPage}
+        className='pagination-btn btn-prev-page'
+        icon='step-backward'
+        small
+        text='PREV'
+        style={{ marginLeft: '5px', marginRight: '5px', whiteSpace: 'nowrap' }}
+        disabled={currentPage === 1 || isLoading}
+      />
+      <Button
+        style={{ whiteSpace: 'nowrap' }}
+        disabled={currentPage === maxPage || isLoading}
+        onClick={onNextPage}
+        className='pagination-btn btn-next-page'
+        rightIcon='step-forward'
+        text='NEXT'
+        small
+      />
+    </div>
+  )
+}
+
+function usePaginator (initialLoadingState = false) {
+  // const [integrations, setIntegrations] = useState(integrationsData)
+
+  const [_data, _setData] = useState([])
+
+  // filter related
+  const [filterParams, setFilterParams] = useState({})
+  const [filterFunc, setFilterFunc] = useState(() => (params, item) => true)
+  const filteredData = useMemo(() => {
+    console.log('>> SET FILTER DATA BY', filterParams, _data)
+    const filteredData = []
+    for (const item of _data) {
+      console.log(item)
+      if (filterFunc(filterParams, item)) {
+        filteredData.push(item)
+      }
+    }
+    return filteredData
+  }, [_data, filterParams, filterFunc])
+
+  // page related
+  const [pagedData, setPagedData] = useState([])
+  const [pageOptions, setPageOptions] = useState([5, 25, 50, 75, 100])
+  const [currentPage, setCurrentPage] = useState(1)
+  const [perPage, setPerPage] = useState(pageOptions[1])
+  const [maxPage, setMaxPage] = useState(0)
+
+  // others
+  const [isLoading, setIsLoading] = useState(initialLoadingState || false)
+  const [isProcessing, setIsProcessing] = useState(false)
+  const [refresh, setRefresh] = useState(false)
+
+  const reCalMaxPage = useCallback(() => {
+    setMaxPage(Math.max(1, Math.ceil(filteredData.length / perPage)))
+    console.log('>> MAX PAGE = ', Math.max(1, Math.ceil(filteredData.length / perPage)))
+  }, [filteredData, perPage, setMaxPage])
+
+  const setData = useCallback((data) => {
+    console.log('>> SET ALL DATA...', _data)
+    _setData(data || [])
+    reCalMaxPage()
+  }, [_setData, setRefresh])
+
+  const goNextPage = useCallback(() => {
+    console.log('>>> PAGINATOR: GO NEXT PAGE ...')
+    setCurrentPage(currentPage => Math.min(maxPage, currentPage + 1))
+    // setRefresh((r) => !r)
+    console.log('>>>> NEXT PAGE', currentPage)
+  }, [maxPage, currentPage, setRefresh])
+
+  const goPrevPage = useCallback(() => {
+    console.log('>>> PAGINATOR: GO PREV PAGE ...')
+    setCurrentPage(currentPage => Math.max(1, currentPage - 1))
+    // setRefresh((r) => !r)
+    console.log('>>>> PREV PAGE', currentPage)
+  }, [maxPage, currentPage, setRefresh])
+
+  const changePerPage = useCallback((perPage) => {
+    setPerPage(perPage)
+    setCurrentPage(1)
+    reCalMaxPage()
+  }, [setPerPage])
+
+  const resetPage = useCallback(() => {
+    setCurrentPage(1)
+  }, [currentPage])
+
+  const paginateData = useCallback(() => {
+    console.log('>> FILTERED DATA...', filteredData)
+    const sliceBegin = (currentPage - 1) * perPage
+    const sliceEnd = currentPage * perPage
+    setPagedData(filteredData.slice(sliceBegin, sliceEnd))
+    console.log('>> PAGED DATA = ', filteredData.slice(sliceBegin, sliceEnd))
+  }, [filteredData, perPage, currentPage, setPagedData])
+
+  useEffect(() => {
+    paginateData()
+  }, [refresh, perPage, filteredData, currentPage, paginateData])
+
+  useEffect(() => {
+    reCalMaxPage()
+  }, [refresh, reCalMaxPage, perPage, filteredData])
+
+  const renderControlsComponent = useCallback(() => {
+    return (
+      <Controls
+        currentPage={currentPage}
+        onNextPage={goNextPage}
+        onPrevPage={goPrevPage}
+        maxPage={maxPage}
+        perPage={perPage}
+        isLoading={isLoading}
+        pagingOptionsMenu={
+          <PagingOptionsMenu pageOptions={pageOptions} perPage={perPage} setPerPage={changePerPage} />
+        }
+      />
+    )
+  }, [currentPage, maxPage, perPage, isLoading, goNextPage, goPrevPage, changePerPage])
+
+  return {
+    goNextPage,
+    goPrevPage,
+    resetPage,
+    setPageOptions,
+    renderControlsComponent,
+    isLoading,
+    isProcessing,
+    data: _data,

Review Comment:
   fixed



-- 
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: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] klesh merged pull request #2780: feat: create paginator hook and paginate blueprints grid

Posted by GitBox <gi...@apache.org>.
klesh merged PR #2780:
URL: https://github.com/apache/incubator-devlake/pull/2780


-- 
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: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] e2corporation commented on a diff in pull request #2780: feat: create paginator hook and paginate blueprints grid

Posted by GitBox <gi...@apache.org>.
e2corporation commented on code in PR #2780:
URL: https://github.com/apache/incubator-devlake/pull/2780#discussion_r954256741


##########
config-ui/src/hooks/usePaginator.jsx:
##########
@@ -0,0 +1,217 @@
+/*
+ * 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, useRef, useCallback, useMemo } from 'react'
+import {
+  Popover,
+  Menu,
+  MenuItem,
+  Button
+} from '@blueprintjs/core'
+
+import { integrationsData } from '@/data/integrations'
+
+const PagingOptionsMenu = (props) => {
+  const { pageOptions = [10, 25, 50, 75, 100], perPage = 10, setPerPage = (page) => undefined } = props
+  return (
+    <Menu>
+      {pageOptions && pageOptions.map(pageOption => (
+        <MenuItem
+          key={pageOption}
+          active={perPage === pageOption}
+          icon='key-option'
+          text={`${pageOption} Records`}
+          onClick={() => setPerPage(pageOption)}
+        />))}
+    </Menu>
+  )
+}
+
+const Controls = (props) => {
+  const {
+    enabled = true,
+    pagingOptionsMenu,
+    currentPage,
+    perPage = 10,
+    maxPage,
+    onPrevPage = () => {},
+    onNextPage = () => {},
+    isLoading = false,
+  } = props
+
+  return (
+    <div
+      className='pagination-controls'
+      style={{ display: 'flex', whiteSpace: 'nowrap' }}
+    >
+      <Popover placement='bottom'>
+        <Button
+          className='btn-select-page-size'
+          style={{ whiteSpace: 'nowrap' }}
+          icon='numbered-list'
+          text={`Rows: ${perPage}`}
+          disabled={isLoading}
+          outlined
+          minimal
+        />
+        <>{pagingOptionsMenu}</>
+      </Popover>
+      <Button
+        onClick={onPrevPage}
+        className='pagination-btn btn-prev-page'
+        icon='step-backward'
+        small
+        text='PREV'
+        style={{ marginLeft: '5px', marginRight: '5px', whiteSpace: 'nowrap' }}
+        disabled={currentPage === 1 || isLoading}
+      />
+      <Button
+        style={{ whiteSpace: 'nowrap' }}
+        disabled={currentPage === maxPage || isLoading}
+        onClick={onNextPage}
+        className='pagination-btn btn-next-page'
+        rightIcon='step-forward'
+        text='NEXT'
+        small
+      />
+    </div>
+  )
+}
+
+function usePaginator (initialLoadingState = false) {
+  // const [integrations, setIntegrations] = useState(integrationsData)
+
+  const [_data, _setData] = useState([])
+
+  // filter related
+  const [filterParams, setFilterParams] = useState({})
+  const [filterFunc, setFilterFunc] = useState(() => (params, item) => true)
+  const filteredData = useMemo(() => {
+    console.log('>> SET FILTER DATA BY', filterParams, _data)
+    const filteredData = []
+    for (const item of _data) {
+      console.log(item)
+      if (filterFunc(filterParams, item)) {
+        filteredData.push(item)
+      }
+    }
+    return filteredData
+  }, [_data, filterParams, filterFunc])
+
+  // page related
+  const [pagedData, setPagedData] = useState([])
+  const [pageOptions, setPageOptions] = useState([5, 25, 50, 75, 100])
+  const [currentPage, setCurrentPage] = useState(1)
+  const [perPage, setPerPage] = useState(pageOptions[1])
+  const [maxPage, setMaxPage] = useState(0)
+
+  // others
+  const [isLoading, setIsLoading] = useState(initialLoadingState || false)
+  const [isProcessing, setIsProcessing] = useState(false)
+  const [refresh, setRefresh] = useState(false)
+
+  const reCalMaxPage = useCallback(() => {
+    setMaxPage(Math.max(1, Math.ceil(filteredData.length / perPage)))
+    console.log('>> MAX PAGE = ', Math.max(1, Math.ceil(filteredData.length / perPage)))
+  }, [filteredData, perPage, setMaxPage])
+
+  const setData = useCallback((data) => {
+    console.log('>> SET ALL DATA...', _data)
+    _setData(data || [])
+    reCalMaxPage()
+  }, [_setData, setRefresh])
+
+  const goNextPage = useCallback(() => {
+    console.log('>>> PAGINATOR: GO NEXT PAGE ...')
+    setCurrentPage(currentPage => Math.min(maxPage, currentPage + 1))
+    // setRefresh((r) => !r)
+    console.log('>>>> NEXT PAGE', currentPage)
+  }, [maxPage, currentPage, setRefresh])
+
+  const goPrevPage = useCallback(() => {
+    console.log('>>> PAGINATOR: GO PREV PAGE ...')
+    setCurrentPage(currentPage => Math.max(1, currentPage - 1))
+    // setRefresh((r) => !r)
+    console.log('>>>> PREV PAGE', currentPage)
+  }, [maxPage, currentPage, setRefresh])
+
+  const changePerPage = useCallback((perPage) => {
+    setPerPage(perPage)
+    setCurrentPage(1)
+    reCalMaxPage()
+  }, [setPerPage])
+
+  const resetPage = useCallback(() => {
+    setCurrentPage(1)
+  }, [currentPage])
+
+  const paginateData = useCallback(() => {
+    console.log('>> FILTERED DATA...', filteredData)
+    const sliceBegin = (currentPage - 1) * perPage
+    const sliceEnd = currentPage * perPage
+    setPagedData(filteredData.slice(sliceBegin, sliceEnd))
+    console.log('>> PAGED DATA = ', filteredData.slice(sliceBegin, sliceEnd))
+  }, [filteredData, perPage, currentPage, setPagedData])
+
+  useEffect(() => {
+    paginateData()
+  }, [refresh, perPage, filteredData, currentPage, paginateData])
+
+  useEffect(() => {

Review Comment:
   This effect can be removed after `maxPage` is converted to a memoized value



-- 
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: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] likyh commented on pull request #2780: feat: create paginator hook and paginate blueprints grid

Posted by GitBox <gi...@apache.org>.
likyh commented on PR #2780:
URL: https://github.com/apache/incubator-devlake/pull/2780#issuecomment-1227175491

   > @likyh Nice work, thanks for the updated changes. Are you able to now add pagination to the Historical Runs grid or do you want to add that under another PR?
   
   Which page? I'll do it on another PR.


-- 
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: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] e2corporation commented on a diff in pull request #2780: feat: create paginator hook and paginate blueprints grid

Posted by GitBox <gi...@apache.org>.
e2corporation commented on code in PR #2780:
URL: https://github.com/apache/incubator-devlake/pull/2780#discussion_r954255609


##########
config-ui/src/hooks/usePaginator.jsx:
##########
@@ -0,0 +1,217 @@
+/*
+ * 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, useRef, useCallback, useMemo } from 'react'
+import {
+  Popover,
+  Menu,
+  MenuItem,
+  Button
+} from '@blueprintjs/core'
+
+import { integrationsData } from '@/data/integrations'
+
+const PagingOptionsMenu = (props) => {
+  const { pageOptions = [10, 25, 50, 75, 100], perPage = 10, setPerPage = (page) => undefined } = props
+  return (
+    <Menu>
+      {pageOptions && pageOptions.map(pageOption => (
+        <MenuItem
+          key={pageOption}
+          active={perPage === pageOption}
+          icon='key-option'
+          text={`${pageOption} Records`}
+          onClick={() => setPerPage(pageOption)}
+        />))}
+    </Menu>
+  )
+}
+
+const Controls = (props) => {
+  const {
+    enabled = true,
+    pagingOptionsMenu,
+    currentPage,
+    perPage = 10,
+    maxPage,
+    onPrevPage = () => {},
+    onNextPage = () => {},
+    isLoading = false,
+  } = props
+
+  return (
+    <div
+      className='pagination-controls'
+      style={{ display: 'flex', whiteSpace: 'nowrap' }}
+    >
+      <Popover placement='bottom'>
+        <Button
+          className='btn-select-page-size'
+          style={{ whiteSpace: 'nowrap' }}
+          icon='numbered-list'
+          text={`Rows: ${perPage}`}
+          disabled={isLoading}
+          outlined
+          minimal
+        />
+        <>{pagingOptionsMenu}</>
+      </Popover>
+      <Button
+        onClick={onPrevPage}
+        className='pagination-btn btn-prev-page'
+        icon='step-backward'
+        small
+        text='PREV'
+        style={{ marginLeft: '5px', marginRight: '5px', whiteSpace: 'nowrap' }}
+        disabled={currentPage === 1 || isLoading}
+      />
+      <Button
+        style={{ whiteSpace: 'nowrap' }}
+        disabled={currentPage === maxPage || isLoading}
+        onClick={onNextPage}
+        className='pagination-btn btn-next-page'
+        rightIcon='step-forward'
+        text='NEXT'
+        small
+      />
+    </div>
+  )
+}
+
+function usePaginator (initialLoadingState = false) {
+  // const [integrations, setIntegrations] = useState(integrationsData)
+
+  const [_data, _setData] = useState([])

Review Comment:
   I don't utilize "_private" typed vars or setters elsewhere in the code base, I don't think we need this type of var distinction in the codebase. This should just be `data` and `setData` respectively.



-- 
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: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] e2corporation commented on a diff in pull request #2780: feat: create paginator hook and paginate blueprints grid

Posted by GitBox <gi...@apache.org>.
e2corporation commented on code in PR #2780:
URL: https://github.com/apache/incubator-devlake/pull/2780#discussion_r954255915


##########
config-ui/src/hooks/usePaginator.jsx:
##########
@@ -0,0 +1,217 @@
+/*
+ * 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, useRef, useCallback, useMemo } from 'react'
+import {
+  Popover,
+  Menu,
+  MenuItem,
+  Button
+} from '@blueprintjs/core'
+
+import { integrationsData } from '@/data/integrations'
+
+const PagingOptionsMenu = (props) => {
+  const { pageOptions = [10, 25, 50, 75, 100], perPage = 10, setPerPage = (page) => undefined } = props
+  return (
+    <Menu>
+      {pageOptions && pageOptions.map(pageOption => (
+        <MenuItem
+          key={pageOption}
+          active={perPage === pageOption}
+          icon='key-option'
+          text={`${pageOption} Records`}
+          onClick={() => setPerPage(pageOption)}
+        />))}
+    </Menu>
+  )
+}
+
+const Controls = (props) => {
+  const {
+    enabled = true,
+    pagingOptionsMenu,
+    currentPage,
+    perPage = 10,
+    maxPage,
+    onPrevPage = () => {},
+    onNextPage = () => {},
+    isLoading = false,
+  } = props
+
+  return (
+    <div
+      className='pagination-controls'
+      style={{ display: 'flex', whiteSpace: 'nowrap' }}
+    >
+      <Popover placement='bottom'>
+        <Button
+          className='btn-select-page-size'
+          style={{ whiteSpace: 'nowrap' }}
+          icon='numbered-list'
+          text={`Rows: ${perPage}`}
+          disabled={isLoading}
+          outlined
+          minimal
+        />
+        <>{pagingOptionsMenu}</>
+      </Popover>
+      <Button
+        onClick={onPrevPage}
+        className='pagination-btn btn-prev-page'
+        icon='step-backward'
+        small
+        text='PREV'
+        style={{ marginLeft: '5px', marginRight: '5px', whiteSpace: 'nowrap' }}
+        disabled={currentPage === 1 || isLoading}
+      />
+      <Button
+        style={{ whiteSpace: 'nowrap' }}
+        disabled={currentPage === maxPage || isLoading}
+        onClick={onNextPage}
+        className='pagination-btn btn-next-page'
+        rightIcon='step-forward'
+        text='NEXT'
+        small
+      />
+    </div>
+  )
+}
+
+function usePaginator (initialLoadingState = false) {
+  // const [integrations, setIntegrations] = useState(integrationsData)
+
+  const [_data, _setData] = useState([])

Review Comment:
   ```suggestion
   const [data, setData] = useState([])
   ```



-- 
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: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] likyh commented on a diff in pull request #2780: feat: create paginator hook and paginate blueprints grid

Posted by GitBox <gi...@apache.org>.
likyh commented on code in PR #2780:
URL: https://github.com/apache/incubator-devlake/pull/2780#discussion_r954437327


##########
config-ui/src/hooks/usePaginator.jsx:
##########
@@ -0,0 +1,217 @@
+/*
+ * 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, useRef, useCallback, useMemo } from 'react'
+import {
+  Popover,
+  Menu,
+  MenuItem,
+  Button
+} from '@blueprintjs/core'
+
+import { integrationsData } from '@/data/integrations'
+
+const PagingOptionsMenu = (props) => {
+  const { pageOptions = [10, 25, 50, 75, 100], perPage = 10, setPerPage = (page) => undefined } = props
+  return (
+    <Menu>
+      {pageOptions && pageOptions.map(pageOption => (
+        <MenuItem
+          key={pageOption}
+          active={perPage === pageOption}
+          icon='key-option'
+          text={`${pageOption} Records`}
+          onClick={() => setPerPage(pageOption)}
+        />))}
+    </Menu>
+  )
+}
+
+const Controls = (props) => {
+  const {
+    enabled = true,
+    pagingOptionsMenu,
+    currentPage,
+    perPage = 10,
+    maxPage,
+    onPrevPage = () => {},
+    onNextPage = () => {},
+    isLoading = false,
+  } = props
+
+  return (
+    <div
+      className='pagination-controls'
+      style={{ display: 'flex', whiteSpace: 'nowrap' }}
+    >
+      <Popover placement='bottom'>
+        <Button
+          className='btn-select-page-size'
+          style={{ whiteSpace: 'nowrap' }}
+          icon='numbered-list'
+          text={`Rows: ${perPage}`}
+          disabled={isLoading}
+          outlined
+          minimal
+        />
+        <>{pagingOptionsMenu}</>
+      </Popover>
+      <Button
+        onClick={onPrevPage}
+        className='pagination-btn btn-prev-page'
+        icon='step-backward'
+        small
+        text='PREV'
+        style={{ marginLeft: '5px', marginRight: '5px', whiteSpace: 'nowrap' }}
+        disabled={currentPage === 1 || isLoading}
+      />
+      <Button
+        style={{ whiteSpace: 'nowrap' }}
+        disabled={currentPage === maxPage || isLoading}
+        onClick={onNextPage}
+        className='pagination-btn btn-next-page'
+        rightIcon='step-forward'
+        text='NEXT'
+        small
+      />
+    </div>
+  )
+}
+
+function usePaginator (initialLoadingState = false) {
+  // const [integrations, setIntegrations] = useState(integrationsData)
+
+  const [_data, _setData] = useState([])
+
+  // filter related
+  const [filterParams, setFilterParams] = useState({})
+  const [filterFunc, setFilterFunc] = useState(() => (params, item) => true)
+  const filteredData = useMemo(() => {
+    console.log('>> SET FILTER DATA BY', filterParams, _data)
+    const filteredData = []
+    for (const item of _data) {
+      console.log(item)
+      if (filterFunc(filterParams, item)) {
+        filteredData.push(item)
+      }
+    }
+    return filteredData
+  }, [_data, filterParams, filterFunc])
+
+  // page related
+  const [pagedData, setPagedData] = useState([])
+  const [pageOptions, setPageOptions] = useState([5, 25, 50, 75, 100])
+  const [currentPage, setCurrentPage] = useState(1)
+  const [perPage, setPerPage] = useState(pageOptions[1])
+  const [maxPage, setMaxPage] = useState(0)

Review Comment:
   I kept it because maybe we need to set it by backend response. But we can delete it now.



-- 
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: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] e2corporation commented on pull request #2780: feat: create paginator hook and paginate blueprints grid

Posted by GitBox <gi...@apache.org>.
e2corporation commented on PR #2780:
URL: https://github.com/apache/incubator-devlake/pull/2780#issuecomment-1227200924

   > So delete `refresh` and `setRefresh`? @e2corporation
   
   Leave the definitions for the refresh feature it will be applied later, just don't include them in dependencies where not needed. For example on `Ln` 129, `setRefresh` is not being called in `setDataWithDefault` therefore it's not a needed dependency and should be in the array. 


-- 
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: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] likyh commented on pull request #2780: feat: create paginator hook and paginate blueprints grid (draft)

Posted by GitBox <gi...@apache.org>.
likyh commented on PR #2780:
URL: https://github.com/apache/incubator-devlake/pull/2780#issuecomment-1222254616

   @e2corporation I have added page and filter in it.


-- 
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: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] e2corporation commented on a diff in pull request #2780: feat: create paginator hook and paginate blueprints grid

Posted by GitBox <gi...@apache.org>.
e2corporation commented on code in PR #2780:
URL: https://github.com/apache/incubator-devlake/pull/2780#discussion_r954343834


##########
config-ui/src/hooks/usePaginator.jsx:
##########
@@ -0,0 +1,217 @@
+/*
+ * 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, useRef, useCallback, useMemo } from 'react'
+import {
+  Popover,
+  Menu,
+  MenuItem,
+  Button
+} from '@blueprintjs/core'
+
+import { integrationsData } from '@/data/integrations'
+
+const PagingOptionsMenu = (props) => {
+  const { pageOptions = [10, 25, 50, 75, 100], perPage = 10, setPerPage = (page) => undefined } = props
+  return (
+    <Menu>
+      {pageOptions && pageOptions.map(pageOption => (
+        <MenuItem
+          key={pageOption}
+          active={perPage === pageOption}
+          icon='key-option'
+          text={`${pageOption} Records`}
+          onClick={() => setPerPage(pageOption)}
+        />))}
+    </Menu>
+  )
+}
+
+const Controls = (props) => {
+  const {
+    enabled = true,
+    pagingOptionsMenu,
+    currentPage,
+    perPage = 10,
+    maxPage,
+    onPrevPage = () => {},
+    onNextPage = () => {},
+    isLoading = false,
+  } = props
+
+  return (
+    <div
+      className='pagination-controls'
+      style={{ display: 'flex', whiteSpace: 'nowrap' }}
+    >
+      <Popover placement='bottom'>
+        <Button
+          className='btn-select-page-size'
+          style={{ whiteSpace: 'nowrap' }}
+          icon='numbered-list'
+          text={`Rows: ${perPage}`}
+          disabled={isLoading}
+          outlined
+          minimal
+        />
+        <>{pagingOptionsMenu}</>
+      </Popover>
+      <Button
+        onClick={onPrevPage}
+        className='pagination-btn btn-prev-page'
+        icon='step-backward'
+        small
+        text='PREV'
+        style={{ marginLeft: '5px', marginRight: '5px', whiteSpace: 'nowrap' }}
+        disabled={currentPage === 1 || isLoading}
+      />
+      <Button
+        style={{ whiteSpace: 'nowrap' }}
+        disabled={currentPage === maxPage || isLoading}
+        onClick={onNextPage}
+        className='pagination-btn btn-next-page'
+        rightIcon='step-forward'
+        text='NEXT'
+        small
+      />
+    </div>
+  )
+}
+
+function usePaginator (initialLoadingState = false) {
+  // const [integrations, setIntegrations] = useState(integrationsData)
+
+  const [_data, _setData] = useState([])
+
+  // filter related
+  const [filterParams, setFilterParams] = useState({})
+  const [filterFunc, setFilterFunc] = useState(() => (params, item) => true)
+  const filteredData = useMemo(() => {
+    console.log('>> SET FILTER DATA BY', filterParams, _data)
+    const filteredData = []
+    for (const item of _data) {
+      console.log(item)
+      if (filterFunc(filterParams, item)) {
+        filteredData.push(item)
+      }
+    }
+    return filteredData
+  }, [_data, filterParams, filterFunc])
+
+  // page related
+  const [pagedData, setPagedData] = useState([])
+  const [pageOptions, setPageOptions] = useState([5, 25, 50, 75, 100])
+  const [currentPage, setCurrentPage] = useState(1)
+  const [perPage, setPerPage] = useState(pageOptions[1])
+  const [maxPage, setMaxPage] = useState(0)
+
+  // others
+  const [isLoading, setIsLoading] = useState(initialLoadingState || false)
+  const [isProcessing, setIsProcessing] = useState(false)
+  const [refresh, setRefresh] = useState(false)
+
+  const reCalMaxPage = useCallback(() => {
+    setMaxPage(Math.max(1, Math.ceil(filteredData.length / perPage)))
+    console.log('>> MAX PAGE = ', Math.max(1, Math.ceil(filteredData.length / perPage)))
+  }, [filteredData, perPage, setMaxPage])
+
+  const setData = useCallback((data) => {
+    console.log('>> SET ALL DATA...', _data)
+    _setData(data || [])
+    reCalMaxPage()
+  }, [_setData, setRefresh])
+
+  const goNextPage = useCallback(() => {
+    console.log('>>> PAGINATOR: GO NEXT PAGE ...')
+    setCurrentPage(currentPage => Math.min(maxPage, currentPage + 1))
+    // setRefresh((r) => !r)
+    console.log('>>>> NEXT PAGE', currentPage)
+  }, [maxPage, currentPage, setRefresh])
+
+  const goPrevPage = useCallback(() => {
+    console.log('>>> PAGINATOR: GO PREV PAGE ...')
+    setCurrentPage(currentPage => Math.max(1, currentPage - 1))
+    // setRefresh((r) => !r)
+    console.log('>>>> PREV PAGE', currentPage)
+  }, [maxPage, currentPage, setRefresh])
+
+  const changePerPage = useCallback((perPage) => {
+    setPerPage(perPage)
+    setCurrentPage(1)
+    reCalMaxPage()
+  }, [setPerPage])
+
+  const resetPage = useCallback(() => {
+    setCurrentPage(1)
+  }, [currentPage])
+
+  const paginateData = useCallback(() => {
+    console.log('>> FILTERED DATA...', filteredData)
+    const sliceBegin = (currentPage - 1) * perPage
+    const sliceEnd = currentPage * perPage
+    setPagedData(filteredData.slice(sliceBegin, sliceEnd))
+    console.log('>> PAGED DATA = ', filteredData.slice(sliceBegin, sliceEnd))
+  }, [filteredData, perPage, currentPage, setPagedData])
+
+  useEffect(() => {
+    paginateData()
+  }, [refresh, perPage, filteredData, currentPage, paginateData])
+
+  useEffect(() => {

Review Comment:
   This effect can be removed after `reCalMaxPage` is removed.



-- 
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: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] e2corporation commented on a diff in pull request #2780: feat: create paginator hook and paginate blueprints grid

Posted by GitBox <gi...@apache.org>.
e2corporation commented on code in PR #2780:
URL: https://github.com/apache/incubator-devlake/pull/2780#discussion_r954254213


##########
config-ui/src/hooks/usePaginator.jsx:
##########
@@ -0,0 +1,217 @@
+/*
+ * 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, useRef, useCallback, useMemo } from 'react'
+import {
+  Popover,
+  Menu,
+  MenuItem,
+  Button
+} from '@blueprintjs/core'
+
+import { integrationsData } from '@/data/integrations'
+
+const PagingOptionsMenu = (props) => {
+  const { pageOptions = [10, 25, 50, 75, 100], perPage = 10, setPerPage = (page) => undefined } = props
+  return (
+    <Menu>
+      {pageOptions && pageOptions.map(pageOption => (
+        <MenuItem
+          key={pageOption}
+          active={perPage === pageOption}
+          icon='key-option'
+          text={`${pageOption} Records`}
+          onClick={() => setPerPage(pageOption)}
+        />))}
+    </Menu>
+  )
+}
+
+const Controls = (props) => {
+  const {
+    enabled = true,
+    pagingOptionsMenu,
+    currentPage,
+    perPage = 10,
+    maxPage,
+    onPrevPage = () => {},
+    onNextPage = () => {},
+    isLoading = false,
+  } = props
+
+  return (
+    <div
+      className='pagination-controls'
+      style={{ display: 'flex', whiteSpace: 'nowrap' }}
+    >
+      <Popover placement='bottom'>
+        <Button
+          className='btn-select-page-size'
+          style={{ whiteSpace: 'nowrap' }}
+          icon='numbered-list'
+          text={`Rows: ${perPage}`}
+          disabled={isLoading}
+          outlined
+          minimal
+        />
+        <>{pagingOptionsMenu}</>
+      </Popover>
+      <Button
+        onClick={onPrevPage}
+        className='pagination-btn btn-prev-page'
+        icon='step-backward'
+        small
+        text='PREV'
+        style={{ marginLeft: '5px', marginRight: '5px', whiteSpace: 'nowrap' }}
+        disabled={currentPage === 1 || isLoading}
+      />
+      <Button
+        style={{ whiteSpace: 'nowrap' }}
+        disabled={currentPage === maxPage || isLoading}
+        onClick={onNextPage}
+        className='pagination-btn btn-next-page'
+        rightIcon='step-forward'
+        text='NEXT'
+        small
+      />
+    </div>
+  )
+}
+
+function usePaginator (initialLoadingState = false) {
+  // const [integrations, setIntegrations] = useState(integrationsData)
+
+  const [_data, _setData] = useState([])
+
+  // filter related
+  const [filterParams, setFilterParams] = useState({})
+  const [filterFunc, setFilterFunc] = useState(() => (params, item) => true)
+  const filteredData = useMemo(() => {
+    console.log('>> SET FILTER DATA BY', filterParams, _data)
+    const filteredData = []
+    for (const item of _data) {
+      console.log(item)
+      if (filterFunc(filterParams, item)) {
+        filteredData.push(item)
+      }
+    }
+    return filteredData
+  }, [_data, filterParams, filterFunc])
+
+  // page related
+  const [pagedData, setPagedData] = useState([])
+  const [pageOptions, setPageOptions] = useState([5, 25, 50, 75, 100])
+  const [currentPage, setCurrentPage] = useState(1)
+  const [perPage, setPerPage] = useState(pageOptions[1])
+  const [maxPage, setMaxPage] = useState(0)

Review Comment:
   Since `maxPage` is better suited to be an internal calculation and will rarely need to be established external caller using this hook service, lets convert this to a memoized calculation instead, and it will remove the need for having the `reCalMaxPage` helper.



-- 
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: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] e2corporation commented on a diff in pull request #2780: feat: create paginator hook and paginate blueprints grid

Posted by GitBox <gi...@apache.org>.
e2corporation commented on code in PR #2780:
URL: https://github.com/apache/incubator-devlake/pull/2780#discussion_r954868370


##########
config-ui/src/hooks/usePaginator.jsx:
##########
@@ -0,0 +1,217 @@
+/*
+ * 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, useRef, useCallback, useMemo } from 'react'
+import {
+  Popover,
+  Menu,
+  MenuItem,
+  Button
+} from '@blueprintjs/core'
+
+import { integrationsData } from '@/data/integrations'
+
+const PagingOptionsMenu = (props) => {
+  const { pageOptions = [10, 25, 50, 75, 100], perPage = 10, setPerPage = (page) => undefined } = props
+  return (
+    <Menu>
+      {pageOptions && pageOptions.map(pageOption => (
+        <MenuItem
+          key={pageOption}
+          active={perPage === pageOption}
+          icon='key-option'
+          text={`${pageOption} Records`}
+          onClick={() => setPerPage(pageOption)}
+        />))}
+    </Menu>
+  )
+}
+
+const Controls = (props) => {
+  const {
+    enabled = true,
+    pagingOptionsMenu,
+    currentPage,
+    perPage = 10,
+    maxPage,
+    onPrevPage = () => {},
+    onNextPage = () => {},
+    isLoading = false,
+  } = props
+
+  return (
+    <div
+      className='pagination-controls'
+      style={{ display: 'flex', whiteSpace: 'nowrap' }}
+    >
+      <Popover placement='bottom'>
+        <Button
+          className='btn-select-page-size'
+          style={{ whiteSpace: 'nowrap' }}
+          icon='numbered-list'
+          text={`Rows: ${perPage}`}
+          disabled={isLoading}
+          outlined
+          minimal
+        />
+        <>{pagingOptionsMenu}</>
+      </Popover>
+      <Button
+        onClick={onPrevPage}
+        className='pagination-btn btn-prev-page'
+        icon='step-backward'
+        small
+        text='PREV'
+        style={{ marginLeft: '5px', marginRight: '5px', whiteSpace: 'nowrap' }}
+        disabled={currentPage === 1 || isLoading}
+      />
+      <Button
+        style={{ whiteSpace: 'nowrap' }}
+        disabled={currentPage === maxPage || isLoading}
+        onClick={onNextPage}
+        className='pagination-btn btn-next-page'
+        rightIcon='step-forward'
+        text='NEXT'
+        small
+      />
+    </div>
+  )
+}
+
+function usePaginator (initialLoadingState = false) {
+  // const [integrations, setIntegrations] = useState(integrationsData)
+
+  const [_data, _setData] = useState([])
+
+  // filter related
+  const [filterParams, setFilterParams] = useState({})
+  const [filterFunc, setFilterFunc] = useState(() => (params, item) => true)
+  const filteredData = useMemo(() => {
+    console.log('>> SET FILTER DATA BY', filterParams, _data)
+    const filteredData = []
+    for (const item of _data) {
+      console.log(item)
+      if (filterFunc(filterParams, item)) {
+        filteredData.push(item)
+      }
+    }
+    return filteredData
+  }, [_data, filterParams, filterFunc])
+
+  // page related
+  const [pagedData, setPagedData] = useState([])
+  const [pageOptions, setPageOptions] = useState([5, 25, 50, 75, 100])
+  const [currentPage, setCurrentPage] = useState(1)
+  const [perPage, setPerPage] = useState(pageOptions[1])
+  const [maxPage, setMaxPage] = useState(0)

Review Comment:
   When `server-side` mode is added we may need to update the compute dependencies, hopefully we won't need a setter.



-- 
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: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] likyh commented on a diff in pull request #2780: feat: create paginator hook and paginate blueprints grid

Posted by GitBox <gi...@apache.org>.
likyh commented on code in PR #2780:
URL: https://github.com/apache/incubator-devlake/pull/2780#discussion_r954442193


##########
config-ui/src/hooks/usePaginator.jsx:
##########
@@ -0,0 +1,217 @@
+/*
+ * 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, useRef, useCallback, useMemo } from 'react'
+import {
+  Popover,
+  Menu,
+  MenuItem,
+  Button
+} from '@blueprintjs/core'
+
+import { integrationsData } from '@/data/integrations'
+
+const PagingOptionsMenu = (props) => {
+  const { pageOptions = [10, 25, 50, 75, 100], perPage = 10, setPerPage = (page) => undefined } = props
+  return (
+    <Menu>
+      {pageOptions && pageOptions.map(pageOption => (
+        <MenuItem
+          key={pageOption}
+          active={perPage === pageOption}
+          icon='key-option'
+          text={`${pageOption} Records`}
+          onClick={() => setPerPage(pageOption)}
+        />))}
+    </Menu>
+  )
+}
+
+const Controls = (props) => {
+  const {
+    enabled = true,
+    pagingOptionsMenu,
+    currentPage,
+    perPage = 10,
+    maxPage,
+    onPrevPage = () => {},
+    onNextPage = () => {},
+    isLoading = false,
+  } = props
+
+  return (
+    <div
+      className='pagination-controls'
+      style={{ display: 'flex', whiteSpace: 'nowrap' }}
+    >
+      <Popover placement='bottom'>
+        <Button
+          className='btn-select-page-size'
+          style={{ whiteSpace: 'nowrap' }}
+          icon='numbered-list'
+          text={`Rows: ${perPage}`}
+          disabled={isLoading}
+          outlined
+          minimal
+        />
+        <>{pagingOptionsMenu}</>
+      </Popover>
+      <Button
+        onClick={onPrevPage}
+        className='pagination-btn btn-prev-page'
+        icon='step-backward'
+        small
+        text='PREV'
+        style={{ marginLeft: '5px', marginRight: '5px', whiteSpace: 'nowrap' }}
+        disabled={currentPage === 1 || isLoading}
+      />
+      <Button
+        style={{ whiteSpace: 'nowrap' }}
+        disabled={currentPage === maxPage || isLoading}
+        onClick={onNextPage}
+        className='pagination-btn btn-next-page'
+        rightIcon='step-forward'
+        text='NEXT'
+        small
+      />
+    </div>
+  )
+}
+
+function usePaginator (initialLoadingState = false) {
+  // const [integrations, setIntegrations] = useState(integrationsData)
+
+  const [_data, _setData] = useState([])
+
+  // filter related
+  const [filterParams, setFilterParams] = useState({})
+  const [filterFunc, setFilterFunc] = useState(() => (params, item) => true)
+  const filteredData = useMemo(() => {
+    console.log('>> SET FILTER DATA BY', filterParams, _data)
+    const filteredData = []
+    for (const item of _data) {
+      console.log(item)
+      if (filterFunc(filterParams, item)) {
+        filteredData.push(item)
+      }
+    }
+    return filteredData
+  }, [_data, filterParams, filterFunc])
+
+  // page related
+  const [pagedData, setPagedData] = useState([])
+  const [pageOptions, setPageOptions] = useState([5, 25, 50, 75, 100])
+  const [currentPage, setCurrentPage] = useState(1)
+  const [perPage, setPerPage] = useState(pageOptions[1])
+  const [maxPage, setMaxPage] = useState(0)
+
+  // others
+  const [isLoading, setIsLoading] = useState(initialLoadingState || false)
+  const [isProcessing, setIsProcessing] = useState(false)
+  const [refresh, setRefresh] = useState(false)
+
+  const reCalMaxPage = useCallback(() => {
+    setMaxPage(Math.max(1, Math.ceil(filteredData.length / perPage)))
+    console.log('>> MAX PAGE = ', Math.max(1, Math.ceil(filteredData.length / perPage)))
+  }, [filteredData, perPage, setMaxPage])
+
+  const setData = useCallback((data) => {
+    console.log('>> SET ALL DATA...', _data)
+    _setData(data || [])
+    reCalMaxPage()
+  }, [_setData, setRefresh])
+
+  const goNextPage = useCallback(() => {
+    console.log('>>> PAGINATOR: GO NEXT PAGE ...')
+    setCurrentPage(currentPage => Math.min(maxPage, currentPage + 1))
+    // setRefresh((r) => !r)
+    console.log('>>>> NEXT PAGE', currentPage)
+  }, [maxPage, currentPage, setRefresh])
+
+  const goPrevPage = useCallback(() => {
+    console.log('>>> PAGINATOR: GO PREV PAGE ...')
+    setCurrentPage(currentPage => Math.max(1, currentPage - 1))
+    // setRefresh((r) => !r)
+    console.log('>>>> PREV PAGE', currentPage)
+  }, [maxPage, currentPage, setRefresh])
+
+  const changePerPage = useCallback((perPage) => {
+    setPerPage(perPage)
+    setCurrentPage(1)
+    reCalMaxPage()
+  }, [setPerPage])
+
+  const resetPage = useCallback(() => {
+    setCurrentPage(1)
+  }, [currentPage])
+
+  const paginateData = useCallback(() => {
+    console.log('>> FILTERED DATA...', filteredData)
+    const sliceBegin = (currentPage - 1) * perPage
+    const sliceEnd = currentPage * perPage
+    setPagedData(filteredData.slice(sliceBegin, sliceEnd))
+    console.log('>> PAGED DATA = ', filteredData.slice(sliceBegin, sliceEnd))
+  }, [filteredData, perPage, currentPage, setPagedData])
+
+  useEffect(() => {
+    paginateData()
+  }, [refresh, perPage, filteredData, currentPage, paginateData])
+
+  useEffect(() => {

Review Comment:
   fixed



-- 
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: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] e2corporation commented on a diff in pull request #2780: feat: create paginator hook and paginate blueprints grid

Posted by GitBox <gi...@apache.org>.
e2corporation commented on code in PR #2780:
URL: https://github.com/apache/incubator-devlake/pull/2780#discussion_r954257581


##########
config-ui/src/hooks/usePaginator.jsx:
##########
@@ -0,0 +1,217 @@
+/*
+ * 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, useRef, useCallback, useMemo } from 'react'
+import {
+  Popover,
+  Menu,
+  MenuItem,
+  Button
+} from '@blueprintjs/core'
+
+import { integrationsData } from '@/data/integrations'
+
+const PagingOptionsMenu = (props) => {
+  const { pageOptions = [10, 25, 50, 75, 100], perPage = 10, setPerPage = (page) => undefined } = props
+  return (
+    <Menu>
+      {pageOptions && pageOptions.map(pageOption => (
+        <MenuItem
+          key={pageOption}
+          active={perPage === pageOption}
+          icon='key-option'
+          text={`${pageOption} Records`}
+          onClick={() => setPerPage(pageOption)}
+        />))}
+    </Menu>
+  )
+}
+
+const Controls = (props) => {
+  const {
+    enabled = true,
+    pagingOptionsMenu,
+    currentPage,
+    perPage = 10,
+    maxPage,
+    onPrevPage = () => {},
+    onNextPage = () => {},
+    isLoading = false,
+  } = props
+
+  return (
+    <div
+      className='pagination-controls'
+      style={{ display: 'flex', whiteSpace: 'nowrap' }}
+    >
+      <Popover placement='bottom'>
+        <Button
+          className='btn-select-page-size'
+          style={{ whiteSpace: 'nowrap' }}
+          icon='numbered-list'
+          text={`Rows: ${perPage}`}
+          disabled={isLoading}
+          outlined
+          minimal
+        />
+        <>{pagingOptionsMenu}</>
+      </Popover>
+      <Button
+        onClick={onPrevPage}
+        className='pagination-btn btn-prev-page'
+        icon='step-backward'
+        small
+        text='PREV'
+        style={{ marginLeft: '5px', marginRight: '5px', whiteSpace: 'nowrap' }}
+        disabled={currentPage === 1 || isLoading}
+      />
+      <Button
+        style={{ whiteSpace: 'nowrap' }}
+        disabled={currentPage === maxPage || isLoading}
+        onClick={onNextPage}
+        className='pagination-btn btn-next-page'
+        rightIcon='step-forward'
+        text='NEXT'
+        small
+      />
+    </div>
+  )
+}
+
+function usePaginator (initialLoadingState = false) {
+  // const [integrations, setIntegrations] = useState(integrationsData)
+
+  const [_data, _setData] = useState([])
+
+  // filter related
+  const [filterParams, setFilterParams] = useState({})
+  const [filterFunc, setFilterFunc] = useState(() => (params, item) => true)
+  const filteredData = useMemo(() => {
+    console.log('>> SET FILTER DATA BY', filterParams, _data)
+    const filteredData = []
+    for (const item of _data) {
+      console.log(item)
+      if (filterFunc(filterParams, item)) {
+        filteredData.push(item)
+      }
+    }
+    return filteredData
+  }, [_data, filterParams, filterFunc])
+
+  // page related
+  const [pagedData, setPagedData] = useState([])
+  const [pageOptions, setPageOptions] = useState([5, 25, 50, 75, 100])
+  const [currentPage, setCurrentPage] = useState(1)
+  const [perPage, setPerPage] = useState(pageOptions[1])
+  const [maxPage, setMaxPage] = useState(0)
+
+  // others
+  const [isLoading, setIsLoading] = useState(initialLoadingState || false)
+  const [isProcessing, setIsProcessing] = useState(false)
+  const [refresh, setRefresh] = useState(false)
+
+  const reCalMaxPage = useCallback(() => {
+    setMaxPage(Math.max(1, Math.ceil(filteredData.length / perPage)))
+    console.log('>> MAX PAGE = ', Math.max(1, Math.ceil(filteredData.length / perPage)))
+  }, [filteredData, perPage, setMaxPage])
+
+  const setData = useCallback((data) => {
+    console.log('>> SET ALL DATA...', _data)
+    _setData(data || [])
+    reCalMaxPage()
+  }, [_setData, setRefresh])
+
+  const goNextPage = useCallback(() => {
+    console.log('>>> PAGINATOR: GO NEXT PAGE ...')
+    setCurrentPage(currentPage => Math.min(maxPage, currentPage + 1))
+    // setRefresh((r) => !r)
+    console.log('>>>> NEXT PAGE', currentPage)
+  }, [maxPage, currentPage, setRefresh])
+
+  const goPrevPage = useCallback(() => {
+    console.log('>>> PAGINATOR: GO PREV PAGE ...')
+    setCurrentPage(currentPage => Math.max(1, currentPage - 1))
+    // setRefresh((r) => !r)
+    console.log('>>>> PREV PAGE', currentPage)
+  }, [maxPage, currentPage, setRefresh])
+
+  const changePerPage = useCallback((perPage) => {
+    setPerPage(perPage)
+    setCurrentPage(1)
+    reCalMaxPage()
+  }, [setPerPage])
+
+  const resetPage = useCallback(() => {
+    setCurrentPage(1)
+  }, [currentPage])
+
+  const paginateData = useCallback(() => {
+    console.log('>> FILTERED DATA...', filteredData)
+    const sliceBegin = (currentPage - 1) * perPage
+    const sliceEnd = currentPage * perPage
+    setPagedData(filteredData.slice(sliceBegin, sliceEnd))
+    console.log('>> PAGED DATA = ', filteredData.slice(sliceBegin, sliceEnd))
+  }, [filteredData, perPage, currentPage, setPagedData])
+
+  useEffect(() => {
+    paginateData()
+  }, [refresh, perPage, filteredData, currentPage, paginateData])
+
+  useEffect(() => {
+    reCalMaxPage()
+  }, [refresh, reCalMaxPage, perPage, filteredData])
+
+  const renderControlsComponent = useCallback(() => {
+    return (
+      <Controls
+        currentPage={currentPage}
+        onNextPage={goNextPage}
+        onPrevPage={goPrevPage}
+        maxPage={maxPage}
+        perPage={perPage}
+        isLoading={isLoading}
+        pagingOptionsMenu={
+          <PagingOptionsMenu pageOptions={pageOptions} perPage={perPage} setPerPage={changePerPage} />
+        }
+      />
+    )
+  }, [currentPage, maxPage, perPage, isLoading, goNextPage, goPrevPage, changePerPage])
+
+  return {
+    goNextPage,
+    goPrevPage,
+    resetPage,
+    setPageOptions,
+    renderControlsComponent,
+    isLoading,
+    isProcessing,
+    data: _data,

Review Comment:
   This file should not alias its exports, aliases will be done during de-structuring when this hook is accessed.



##########
config-ui/src/hooks/usePaginator.jsx:
##########
@@ -0,0 +1,217 @@
+/*
+ * 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, useRef, useCallback, useMemo } from 'react'
+import {
+  Popover,
+  Menu,
+  MenuItem,
+  Button
+} from '@blueprintjs/core'
+
+import { integrationsData } from '@/data/integrations'
+
+const PagingOptionsMenu = (props) => {
+  const { pageOptions = [10, 25, 50, 75, 100], perPage = 10, setPerPage = (page) => undefined } = props
+  return (
+    <Menu>
+      {pageOptions && pageOptions.map(pageOption => (
+        <MenuItem
+          key={pageOption}
+          active={perPage === pageOption}
+          icon='key-option'
+          text={`${pageOption} Records`}
+          onClick={() => setPerPage(pageOption)}
+        />))}
+    </Menu>
+  )
+}
+
+const Controls = (props) => {
+  const {
+    enabled = true,
+    pagingOptionsMenu,
+    currentPage,
+    perPage = 10,
+    maxPage,
+    onPrevPage = () => {},
+    onNextPage = () => {},
+    isLoading = false,
+  } = props
+
+  return (
+    <div
+      className='pagination-controls'
+      style={{ display: 'flex', whiteSpace: 'nowrap' }}
+    >
+      <Popover placement='bottom'>
+        <Button
+          className='btn-select-page-size'
+          style={{ whiteSpace: 'nowrap' }}
+          icon='numbered-list'
+          text={`Rows: ${perPage}`}
+          disabled={isLoading}
+          outlined
+          minimal
+        />
+        <>{pagingOptionsMenu}</>
+      </Popover>
+      <Button
+        onClick={onPrevPage}
+        className='pagination-btn btn-prev-page'
+        icon='step-backward'
+        small
+        text='PREV'
+        style={{ marginLeft: '5px', marginRight: '5px', whiteSpace: 'nowrap' }}
+        disabled={currentPage === 1 || isLoading}
+      />
+      <Button
+        style={{ whiteSpace: 'nowrap' }}
+        disabled={currentPage === maxPage || isLoading}
+        onClick={onNextPage}
+        className='pagination-btn btn-next-page'
+        rightIcon='step-forward'
+        text='NEXT'
+        small
+      />
+    </div>
+  )
+}
+
+function usePaginator (initialLoadingState = false) {
+  // const [integrations, setIntegrations] = useState(integrationsData)
+
+  const [_data, _setData] = useState([])
+
+  // filter related
+  const [filterParams, setFilterParams] = useState({})
+  const [filterFunc, setFilterFunc] = useState(() => (params, item) => true)
+  const filteredData = useMemo(() => {
+    console.log('>> SET FILTER DATA BY', filterParams, _data)
+    const filteredData = []
+    for (const item of _data) {
+      console.log(item)
+      if (filterFunc(filterParams, item)) {
+        filteredData.push(item)
+      }
+    }
+    return filteredData
+  }, [_data, filterParams, filterFunc])
+
+  // page related
+  const [pagedData, setPagedData] = useState([])
+  const [pageOptions, setPageOptions] = useState([5, 25, 50, 75, 100])
+  const [currentPage, setCurrentPage] = useState(1)
+  const [perPage, setPerPage] = useState(pageOptions[1])
+  const [maxPage, setMaxPage] = useState(0)
+
+  // others
+  const [isLoading, setIsLoading] = useState(initialLoadingState || false)
+  const [isProcessing, setIsProcessing] = useState(false)
+  const [refresh, setRefresh] = useState(false)
+
+  const reCalMaxPage = useCallback(() => {
+    setMaxPage(Math.max(1, Math.ceil(filteredData.length / perPage)))
+    console.log('>> MAX PAGE = ', Math.max(1, Math.ceil(filteredData.length / perPage)))
+  }, [filteredData, perPage, setMaxPage])
+
+  const setData = useCallback((data) => {
+    console.log('>> SET ALL DATA...', _data)
+    _setData(data || [])
+    reCalMaxPage()
+  }, [_setData, setRefresh])
+
+  const goNextPage = useCallback(() => {
+    console.log('>>> PAGINATOR: GO NEXT PAGE ...')
+    setCurrentPage(currentPage => Math.min(maxPage, currentPage + 1))
+    // setRefresh((r) => !r)
+    console.log('>>>> NEXT PAGE', currentPage)
+  }, [maxPage, currentPage, setRefresh])
+
+  const goPrevPage = useCallback(() => {
+    console.log('>>> PAGINATOR: GO PREV PAGE ...')
+    setCurrentPage(currentPage => Math.max(1, currentPage - 1))
+    // setRefresh((r) => !r)
+    console.log('>>>> PREV PAGE', currentPage)
+  }, [maxPage, currentPage, setRefresh])
+
+  const changePerPage = useCallback((perPage) => {
+    setPerPage(perPage)
+    setCurrentPage(1)
+    reCalMaxPage()
+  }, [setPerPage])
+
+  const resetPage = useCallback(() => {
+    setCurrentPage(1)
+  }, [currentPage])
+
+  const paginateData = useCallback(() => {
+    console.log('>> FILTERED DATA...', filteredData)
+    const sliceBegin = (currentPage - 1) * perPage
+    const sliceEnd = currentPage * perPage
+    setPagedData(filteredData.slice(sliceBegin, sliceEnd))
+    console.log('>> PAGED DATA = ', filteredData.slice(sliceBegin, sliceEnd))
+  }, [filteredData, perPage, currentPage, setPagedData])
+
+  useEffect(() => {
+    paginateData()
+  }, [refresh, perPage, filteredData, currentPage, paginateData])
+
+  useEffect(() => {
+    reCalMaxPage()
+  }, [refresh, reCalMaxPage, perPage, filteredData])
+
+  const renderControlsComponent = useCallback(() => {
+    return (
+      <Controls
+        currentPage={currentPage}
+        onNextPage={goNextPage}
+        onPrevPage={goPrevPage}
+        maxPage={maxPage}
+        perPage={perPage}
+        isLoading={isLoading}
+        pagingOptionsMenu={
+          <PagingOptionsMenu pageOptions={pageOptions} perPage={perPage} setPerPage={changePerPage} />
+        }
+      />
+    )
+  }, [currentPage, maxPage, perPage, isLoading, goNextPage, goPrevPage, changePerPage])
+
+  return {
+    goNextPage,
+    goPrevPage,
+    resetPage,
+    setPageOptions,
+    renderControlsComponent,
+    isLoading,
+    isProcessing,
+    data: _data,

Review Comment:
   ```suggestion
       data,
   ```



-- 
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: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] e2corporation commented on a diff in pull request #2780: feat: create paginator hook and paginate blueprints grid

Posted by GitBox <gi...@apache.org>.
e2corporation commented on code in PR #2780:
URL: https://github.com/apache/incubator-devlake/pull/2780#discussion_r954254213


##########
config-ui/src/hooks/usePaginator.jsx:
##########
@@ -0,0 +1,217 @@
+/*
+ * 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, useRef, useCallback, useMemo } from 'react'
+import {
+  Popover,
+  Menu,
+  MenuItem,
+  Button
+} from '@blueprintjs/core'
+
+import { integrationsData } from '@/data/integrations'
+
+const PagingOptionsMenu = (props) => {
+  const { pageOptions = [10, 25, 50, 75, 100], perPage = 10, setPerPage = (page) => undefined } = props
+  return (
+    <Menu>
+      {pageOptions && pageOptions.map(pageOption => (
+        <MenuItem
+          key={pageOption}
+          active={perPage === pageOption}
+          icon='key-option'
+          text={`${pageOption} Records`}
+          onClick={() => setPerPage(pageOption)}
+        />))}
+    </Menu>
+  )
+}
+
+const Controls = (props) => {
+  const {
+    enabled = true,
+    pagingOptionsMenu,
+    currentPage,
+    perPage = 10,
+    maxPage,
+    onPrevPage = () => {},
+    onNextPage = () => {},
+    isLoading = false,
+  } = props
+
+  return (
+    <div
+      className='pagination-controls'
+      style={{ display: 'flex', whiteSpace: 'nowrap' }}
+    >
+      <Popover placement='bottom'>
+        <Button
+          className='btn-select-page-size'
+          style={{ whiteSpace: 'nowrap' }}
+          icon='numbered-list'
+          text={`Rows: ${perPage}`}
+          disabled={isLoading}
+          outlined
+          minimal
+        />
+        <>{pagingOptionsMenu}</>
+      </Popover>
+      <Button
+        onClick={onPrevPage}
+        className='pagination-btn btn-prev-page'
+        icon='step-backward'
+        small
+        text='PREV'
+        style={{ marginLeft: '5px', marginRight: '5px', whiteSpace: 'nowrap' }}
+        disabled={currentPage === 1 || isLoading}
+      />
+      <Button
+        style={{ whiteSpace: 'nowrap' }}
+        disabled={currentPage === maxPage || isLoading}
+        onClick={onNextPage}
+        className='pagination-btn btn-next-page'
+        rightIcon='step-forward'
+        text='NEXT'
+        small
+      />
+    </div>
+  )
+}
+
+function usePaginator (initialLoadingState = false) {
+  // const [integrations, setIntegrations] = useState(integrationsData)
+
+  const [_data, _setData] = useState([])
+
+  // filter related
+  const [filterParams, setFilterParams] = useState({})
+  const [filterFunc, setFilterFunc] = useState(() => (params, item) => true)
+  const filteredData = useMemo(() => {
+    console.log('>> SET FILTER DATA BY', filterParams, _data)
+    const filteredData = []
+    for (const item of _data) {
+      console.log(item)
+      if (filterFunc(filterParams, item)) {
+        filteredData.push(item)
+      }
+    }
+    return filteredData
+  }, [_data, filterParams, filterFunc])
+
+  // page related
+  const [pagedData, setPagedData] = useState([])
+  const [pageOptions, setPageOptions] = useState([5, 25, 50, 75, 100])
+  const [currentPage, setCurrentPage] = useState(1)
+  const [perPage, setPerPage] = useState(pageOptions[1])
+  const [maxPage, setMaxPage] = useState(0)

Review Comment:
   Since `maxPage` is better suited to be an internal calculation and will rarely need to be established by the external caller using this hook service, lets convert this to a memoized calculation instead, and it will remove the need for having the `reCalMaxPage` helper.



-- 
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: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] likyh commented on a diff in pull request #2780: feat: create paginator hook and paginate blueprints grid

Posted by GitBox <gi...@apache.org>.
likyh commented on code in PR #2780:
URL: https://github.com/apache/incubator-devlake/pull/2780#discussion_r954442119


##########
config-ui/src/hooks/usePaginator.jsx:
##########
@@ -0,0 +1,217 @@
+/*
+ * 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, useRef, useCallback, useMemo } from 'react'
+import {
+  Popover,
+  Menu,
+  MenuItem,
+  Button
+} from '@blueprintjs/core'
+
+import { integrationsData } from '@/data/integrations'
+
+const PagingOptionsMenu = (props) => {
+  const { pageOptions = [10, 25, 50, 75, 100], perPage = 10, setPerPage = (page) => undefined } = props
+  return (
+    <Menu>
+      {pageOptions && pageOptions.map(pageOption => (
+        <MenuItem
+          key={pageOption}
+          active={perPage === pageOption}
+          icon='key-option'
+          text={`${pageOption} Records`}
+          onClick={() => setPerPage(pageOption)}
+        />))}
+    </Menu>
+  )
+}
+
+const Controls = (props) => {
+  const {
+    enabled = true,
+    pagingOptionsMenu,
+    currentPage,
+    perPage = 10,
+    maxPage,
+    onPrevPage = () => {},
+    onNextPage = () => {},
+    isLoading = false,
+  } = props
+
+  return (
+    <div
+      className='pagination-controls'
+      style={{ display: 'flex', whiteSpace: 'nowrap' }}
+    >
+      <Popover placement='bottom'>
+        <Button
+          className='btn-select-page-size'
+          style={{ whiteSpace: 'nowrap' }}
+          icon='numbered-list'
+          text={`Rows: ${perPage}`}
+          disabled={isLoading}
+          outlined
+          minimal
+        />
+        <>{pagingOptionsMenu}</>
+      </Popover>
+      <Button
+        onClick={onPrevPage}
+        className='pagination-btn btn-prev-page'
+        icon='step-backward'
+        small
+        text='PREV'
+        style={{ marginLeft: '5px', marginRight: '5px', whiteSpace: 'nowrap' }}
+        disabled={currentPage === 1 || isLoading}
+      />
+      <Button
+        style={{ whiteSpace: 'nowrap' }}
+        disabled={currentPage === maxPage || isLoading}
+        onClick={onNextPage}
+        className='pagination-btn btn-next-page'
+        rightIcon='step-forward'
+        text='NEXT'
+        small
+      />
+    </div>
+  )
+}
+
+function usePaginator (initialLoadingState = false) {
+  // const [integrations, setIntegrations] = useState(integrationsData)
+
+  const [_data, _setData] = useState([])
+
+  // filter related
+  const [filterParams, setFilterParams] = useState({})
+  const [filterFunc, setFilterFunc] = useState(() => (params, item) => true)
+  const filteredData = useMemo(() => {
+    console.log('>> SET FILTER DATA BY', filterParams, _data)
+    const filteredData = []
+    for (const item of _data) {
+      console.log(item)
+      if (filterFunc(filterParams, item)) {
+        filteredData.push(item)
+      }
+    }
+    return filteredData
+  }, [_data, filterParams, filterFunc])
+
+  // page related
+  const [pagedData, setPagedData] = useState([])
+  const [pageOptions, setPageOptions] = useState([5, 25, 50, 75, 100])
+  const [currentPage, setCurrentPage] = useState(1)
+  const [perPage, setPerPage] = useState(pageOptions[1])
+  const [maxPage, setMaxPage] = useState(0)
+
+  // others
+  const [isLoading, setIsLoading] = useState(initialLoadingState || false)
+  const [isProcessing, setIsProcessing] = useState(false)
+  const [refresh, setRefresh] = useState(false)
+
+  const reCalMaxPage = useCallback(() => {
+    setMaxPage(Math.max(1, Math.ceil(filteredData.length / perPage)))
+    console.log('>> MAX PAGE = ', Math.max(1, Math.ceil(filteredData.length / perPage)))
+  }, [filteredData, perPage, setMaxPage])
+
+  const setData = useCallback((data) => {

Review Comment:
   It also set the default value. So `setDataWithDefault`



##########
config-ui/src/pages/blueprints/index.jsx:
##########
@@ -89,6 +90,14 @@ const Blueprints = (props) => {
     detectPipelineProviders
   } = usePipelineManager()
 
+  const {
+    pagedData,
+    setFilterParams,
+    setFilterFunc,
+    setData,

Review Comment:
   setDataWithDefault



-- 
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: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] e2corporation commented on pull request #2780: feat: create paginator hook and paginate blueprints grid (draft)

Posted by GitBox <gi...@apache.org>.
e2corporation commented on PR #2780:
URL: https://github.com/apache/incubator-devlake/pull/2780#issuecomment-1220603687

   The JSX/Markup Fragments for controls etc can be extracted later into child components (`<Controls />` etc) once functionality is working stable. 


-- 
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: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] e2corporation commented on pull request #2780: feat: create paginator hook and paginate blueprints grid

Posted by GitBox <gi...@apache.org>.
e2corporation commented on PR #2780:
URL: https://github.com/apache/incubator-devlake/pull/2780#issuecomment-1227187684

   > > @likyh Nice work, thanks for the updated changes. Are you able to now add pagination to the Historical Runs grid or do you want to add that under another PR?
   > 
   > Which page? I'll do it on another PR.
   
   Historial Runs on Blueprint Status -- deferred to another PR.


-- 
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: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] e2corporation commented on pull request #2780: feat: create paginator hook and paginate blueprints grid

Posted by GitBox <gi...@apache.org>.
e2corporation commented on PR #2780:
URL: https://github.com/apache/incubator-devlake/pull/2780#issuecomment-1227467950

   @klesh @likyh PR Ready for `main` after rebase.


-- 
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: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] e2corporation commented on a diff in pull request #2780: feat: create paginator hook and paginate blueprints grid

Posted by GitBox <gi...@apache.org>.
e2corporation commented on code in PR #2780:
URL: https://github.com/apache/incubator-devlake/pull/2780#discussion_r954282442


##########
config-ui/src/pages/blueprints/index.jsx:
##########
@@ -89,6 +90,14 @@ const Blueprints = (props) => {
     detectPipelineProviders
   } = usePipelineManager()
 
+  const {
+    pagedData,
+    setFilterParams,
+    setFilterFunc,
+    setData,

Review Comment:
   For less ambiguity surrounding the context of the data that is being set, we can alias this to `setPaginatorData`.
   
   ```suggestion
       setData: setPaginatorData,
   ```
   Afterwards, update the associated effect call on `Ln 284` to use `setPaginatorData`



-- 
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: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] likyh commented on pull request #2780: feat: create paginator hook and paginate blueprints grid

Posted by GitBox <gi...@apache.org>.
likyh commented on PR #2780:
URL: https://github.com/apache/incubator-devlake/pull/2780#issuecomment-1227197460

   So delete `refresh` and `setRefresh`? @e2corporation 


-- 
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: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] e2corporation commented on a diff in pull request #2780: feat: create paginator hook and paginate blueprints grid

Posted by GitBox <gi...@apache.org>.
e2corporation commented on code in PR #2780:
URL: https://github.com/apache/incubator-devlake/pull/2780#discussion_r954256741


##########
config-ui/src/hooks/usePaginator.jsx:
##########
@@ -0,0 +1,217 @@
+/*
+ * 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, useRef, useCallback, useMemo } from 'react'
+import {
+  Popover,
+  Menu,
+  MenuItem,
+  Button
+} from '@blueprintjs/core'
+
+import { integrationsData } from '@/data/integrations'
+
+const PagingOptionsMenu = (props) => {
+  const { pageOptions = [10, 25, 50, 75, 100], perPage = 10, setPerPage = (page) => undefined } = props
+  return (
+    <Menu>
+      {pageOptions && pageOptions.map(pageOption => (
+        <MenuItem
+          key={pageOption}
+          active={perPage === pageOption}
+          icon='key-option'
+          text={`${pageOption} Records`}
+          onClick={() => setPerPage(pageOption)}
+        />))}
+    </Menu>
+  )
+}
+
+const Controls = (props) => {
+  const {
+    enabled = true,
+    pagingOptionsMenu,
+    currentPage,
+    perPage = 10,
+    maxPage,
+    onPrevPage = () => {},
+    onNextPage = () => {},
+    isLoading = false,
+  } = props
+
+  return (
+    <div
+      className='pagination-controls'
+      style={{ display: 'flex', whiteSpace: 'nowrap' }}
+    >
+      <Popover placement='bottom'>
+        <Button
+          className='btn-select-page-size'
+          style={{ whiteSpace: 'nowrap' }}
+          icon='numbered-list'
+          text={`Rows: ${perPage}`}
+          disabled={isLoading}
+          outlined
+          minimal
+        />
+        <>{pagingOptionsMenu}</>
+      </Popover>
+      <Button
+        onClick={onPrevPage}
+        className='pagination-btn btn-prev-page'
+        icon='step-backward'
+        small
+        text='PREV'
+        style={{ marginLeft: '5px', marginRight: '5px', whiteSpace: 'nowrap' }}
+        disabled={currentPage === 1 || isLoading}
+      />
+      <Button
+        style={{ whiteSpace: 'nowrap' }}
+        disabled={currentPage === maxPage || isLoading}
+        onClick={onNextPage}
+        className='pagination-btn btn-next-page'
+        rightIcon='step-forward'
+        text='NEXT'
+        small
+      />
+    </div>
+  )
+}
+
+function usePaginator (initialLoadingState = false) {
+  // const [integrations, setIntegrations] = useState(integrationsData)
+
+  const [_data, _setData] = useState([])
+
+  // filter related
+  const [filterParams, setFilterParams] = useState({})
+  const [filterFunc, setFilterFunc] = useState(() => (params, item) => true)
+  const filteredData = useMemo(() => {
+    console.log('>> SET FILTER DATA BY', filterParams, _data)
+    const filteredData = []
+    for (const item of _data) {
+      console.log(item)
+      if (filterFunc(filterParams, item)) {
+        filteredData.push(item)
+      }
+    }
+    return filteredData
+  }, [_data, filterParams, filterFunc])
+
+  // page related
+  const [pagedData, setPagedData] = useState([])
+  const [pageOptions, setPageOptions] = useState([5, 25, 50, 75, 100])
+  const [currentPage, setCurrentPage] = useState(1)
+  const [perPage, setPerPage] = useState(pageOptions[1])
+  const [maxPage, setMaxPage] = useState(0)
+
+  // others
+  const [isLoading, setIsLoading] = useState(initialLoadingState || false)
+  const [isProcessing, setIsProcessing] = useState(false)
+  const [refresh, setRefresh] = useState(false)
+
+  const reCalMaxPage = useCallback(() => {
+    setMaxPage(Math.max(1, Math.ceil(filteredData.length / perPage)))
+    console.log('>> MAX PAGE = ', Math.max(1, Math.ceil(filteredData.length / perPage)))
+  }, [filteredData, perPage, setMaxPage])
+
+  const setData = useCallback((data) => {
+    console.log('>> SET ALL DATA...', _data)
+    _setData(data || [])
+    reCalMaxPage()
+  }, [_setData, setRefresh])
+
+  const goNextPage = useCallback(() => {
+    console.log('>>> PAGINATOR: GO NEXT PAGE ...')
+    setCurrentPage(currentPage => Math.min(maxPage, currentPage + 1))
+    // setRefresh((r) => !r)
+    console.log('>>>> NEXT PAGE', currentPage)
+  }, [maxPage, currentPage, setRefresh])
+
+  const goPrevPage = useCallback(() => {
+    console.log('>>> PAGINATOR: GO PREV PAGE ...')
+    setCurrentPage(currentPage => Math.max(1, currentPage - 1))
+    // setRefresh((r) => !r)
+    console.log('>>>> PREV PAGE', currentPage)
+  }, [maxPage, currentPage, setRefresh])
+
+  const changePerPage = useCallback((perPage) => {
+    setPerPage(perPage)
+    setCurrentPage(1)
+    reCalMaxPage()
+  }, [setPerPage])
+
+  const resetPage = useCallback(() => {
+    setCurrentPage(1)
+  }, [currentPage])
+
+  const paginateData = useCallback(() => {
+    console.log('>> FILTERED DATA...', filteredData)
+    const sliceBegin = (currentPage - 1) * perPage
+    const sliceEnd = currentPage * perPage
+    setPagedData(filteredData.slice(sliceBegin, sliceEnd))
+    console.log('>> PAGED DATA = ', filteredData.slice(sliceBegin, sliceEnd))
+  }, [filteredData, perPage, currentPage, setPagedData])
+
+  useEffect(() => {
+    paginateData()
+  }, [refresh, perPage, filteredData, currentPage, paginateData])
+
+  useEffect(() => {

Review Comment:
   This effect can be removed after `maxPage` is converted to a memoized value



-- 
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: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] e2corporation commented on a diff in pull request #2780: feat: create paginator hook and paginate blueprints grid

Posted by GitBox <gi...@apache.org>.
e2corporation commented on code in PR #2780:
URL: https://github.com/apache/incubator-devlake/pull/2780#discussion_r954256285


##########
config-ui/src/hooks/usePaginator.jsx:
##########
@@ -0,0 +1,217 @@
+/*
+ * 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, useRef, useCallback, useMemo } from 'react'
+import {
+  Popover,
+  Menu,
+  MenuItem,
+  Button
+} from '@blueprintjs/core'
+
+import { integrationsData } from '@/data/integrations'
+
+const PagingOptionsMenu = (props) => {
+  const { pageOptions = [10, 25, 50, 75, 100], perPage = 10, setPerPage = (page) => undefined } = props
+  return (
+    <Menu>
+      {pageOptions && pageOptions.map(pageOption => (
+        <MenuItem
+          key={pageOption}
+          active={perPage === pageOption}
+          icon='key-option'
+          text={`${pageOption} Records`}
+          onClick={() => setPerPage(pageOption)}
+        />))}
+    </Menu>
+  )
+}
+
+const Controls = (props) => {
+  const {
+    enabled = true,
+    pagingOptionsMenu,
+    currentPage,
+    perPage = 10,
+    maxPage,
+    onPrevPage = () => {},
+    onNextPage = () => {},
+    isLoading = false,
+  } = props
+
+  return (
+    <div
+      className='pagination-controls'
+      style={{ display: 'flex', whiteSpace: 'nowrap' }}
+    >
+      <Popover placement='bottom'>
+        <Button
+          className='btn-select-page-size'
+          style={{ whiteSpace: 'nowrap' }}
+          icon='numbered-list'
+          text={`Rows: ${perPage}`}
+          disabled={isLoading}
+          outlined
+          minimal
+        />
+        <>{pagingOptionsMenu}</>
+      </Popover>
+      <Button
+        onClick={onPrevPage}
+        className='pagination-btn btn-prev-page'
+        icon='step-backward'
+        small
+        text='PREV'
+        style={{ marginLeft: '5px', marginRight: '5px', whiteSpace: 'nowrap' }}
+        disabled={currentPage === 1 || isLoading}
+      />
+      <Button
+        style={{ whiteSpace: 'nowrap' }}
+        disabled={currentPage === maxPage || isLoading}
+        onClick={onNextPage}
+        className='pagination-btn btn-next-page'
+        rightIcon='step-forward'
+        text='NEXT'
+        small
+      />
+    </div>
+  )
+}
+
+function usePaginator (initialLoadingState = false) {
+  // const [integrations, setIntegrations] = useState(integrationsData)
+
+  const [_data, _setData] = useState([])
+
+  // filter related
+  const [filterParams, setFilterParams] = useState({})
+  const [filterFunc, setFilterFunc] = useState(() => (params, item) => true)
+  const filteredData = useMemo(() => {
+    console.log('>> SET FILTER DATA BY', filterParams, _data)
+    const filteredData = []
+    for (const item of _data) {
+      console.log(item)
+      if (filterFunc(filterParams, item)) {
+        filteredData.push(item)
+      }
+    }
+    return filteredData
+  }, [_data, filterParams, filterFunc])
+
+  // page related
+  const [pagedData, setPagedData] = useState([])
+  const [pageOptions, setPageOptions] = useState([5, 25, 50, 75, 100])
+  const [currentPage, setCurrentPage] = useState(1)
+  const [perPage, setPerPage] = useState(pageOptions[1])
+  const [maxPage, setMaxPage] = useState(0)
+
+  // others
+  const [isLoading, setIsLoading] = useState(initialLoadingState || false)
+  const [isProcessing, setIsProcessing] = useState(false)
+  const [refresh, setRefresh] = useState(false)
+
+  const reCalMaxPage = useCallback(() => {

Review Comment:
   Delete this callback after `maxPage` is converted to a memoized value.



-- 
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: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] e2corporation commented on pull request #2780: feat: create paginator hook and paginate blueprints grid (draft)

Posted by GitBox <gi...@apache.org>.
e2corporation commented on PR #2780:
URL: https://github.com/apache/incubator-devlake/pull/2780#issuecomment-1220598658

   @likyh This is a Draft PR for the Paginator Hook feature we previously discussed. The logic is already partially working on the Blueprints Grid, at the moment it seems the updated paging data is not reflected on the grid after clicking next. Your first objective is to complete the paginator hook and integrate with the Blueprints Grid page (`blueprints/index.jsx`).


-- 
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: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] e2corporation commented on pull request #2780: feat: create paginator hook and paginate blueprints grid

Posted by GitBox <gi...@apache.org>.
e2corporation commented on PR #2780:
URL: https://github.com/apache/incubator-devlake/pull/2780#issuecomment-1227192884

   @likyh Final cleanup tasks before merge, please resolve the `Lint` warnings on the `usePaginator` Hook outlined below.
   
   ```bash
   /config-ui/src/hooks/usePaginator.jsx
     129:6  warning  React Hook useCallback has an unnecessary dependency: 'setRefresh'. Either exclude it or remove the dependency array                 react-hooks/exhaustive-deps
     136:6  warning  React Hook useCallback has an unnecessary dependency: 'setRefresh'. Either exclude it or remove the dependency array                 react-hooks/exhaustive-deps
     143:6  warning  React Hook useCallback has unnecessary dependencies: 'maxPage' and 'setRefresh'. Either exclude them or remove the dependency array  react-hooks/exhaustive-deps
     152:6  warning  React Hook useCallback has an unnecessary dependency: 'currentPage'. Either exclude it or remove the dependency array                react-hooks/exhaustive-deps
     184:6  warning  React Hook useCallback has a missing dependency: 'pageOptions'. Either include it or remove the dependency array                     react-hooks/exhaustive-deps
   ```
   
   <img width="1264" alt="Screen Shot 2022-08-25 at 8 29 17 AM" src="https://user-images.githubusercontent.com/1742233/186664777-5d7ca82d-5030-4b6e-9d36-659fd028ddb5.png">
   
   


-- 
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: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] e2corporation commented on a diff in pull request #2780: feat: create paginator hook and paginate blueprints grid

Posted by GitBox <gi...@apache.org>.
e2corporation commented on code in PR #2780:
URL: https://github.com/apache/incubator-devlake/pull/2780#discussion_r954871812


##########
config-ui/src/hooks/usePaginator.jsx:
##########
@@ -0,0 +1,217 @@
+/*
+ * 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, useRef, useCallback, useMemo } from 'react'
+import {
+  Popover,
+  Menu,
+  MenuItem,
+  Button
+} from '@blueprintjs/core'
+
+import { integrationsData } from '@/data/integrations'
+
+const PagingOptionsMenu = (props) => {
+  const { pageOptions = [10, 25, 50, 75, 100], perPage = 10, setPerPage = (page) => undefined } = props
+  return (
+    <Menu>
+      {pageOptions && pageOptions.map(pageOption => (
+        <MenuItem
+          key={pageOption}
+          active={perPage === pageOption}
+          icon='key-option'
+          text={`${pageOption} Records`}
+          onClick={() => setPerPage(pageOption)}
+        />))}
+    </Menu>
+  )
+}
+
+const Controls = (props) => {
+  const {
+    enabled = true,
+    pagingOptionsMenu,
+    currentPage,
+    perPage = 10,
+    maxPage,
+    onPrevPage = () => {},
+    onNextPage = () => {},
+    isLoading = false,
+  } = props
+
+  return (
+    <div
+      className='pagination-controls'
+      style={{ display: 'flex', whiteSpace: 'nowrap' }}
+    >
+      <Popover placement='bottom'>
+        <Button
+          className='btn-select-page-size'
+          style={{ whiteSpace: 'nowrap' }}
+          icon='numbered-list'
+          text={`Rows: ${perPage}`}
+          disabled={isLoading}
+          outlined
+          minimal
+        />
+        <>{pagingOptionsMenu}</>
+      </Popover>
+      <Button
+        onClick={onPrevPage}
+        className='pagination-btn btn-prev-page'
+        icon='step-backward'
+        small
+        text='PREV'
+        style={{ marginLeft: '5px', marginRight: '5px', whiteSpace: 'nowrap' }}
+        disabled={currentPage === 1 || isLoading}
+      />
+      <Button
+        style={{ whiteSpace: 'nowrap' }}
+        disabled={currentPage === maxPage || isLoading}
+        onClick={onNextPage}
+        className='pagination-btn btn-next-page'
+        rightIcon='step-forward'
+        text='NEXT'
+        small
+      />
+    </div>
+  )
+}
+
+function usePaginator (initialLoadingState = false) {
+  // const [integrations, setIntegrations] = useState(integrationsData)
+
+  const [_data, _setData] = useState([])
+
+  // filter related
+  const [filterParams, setFilterParams] = useState({})
+  const [filterFunc, setFilterFunc] = useState(() => (params, item) => true)
+  const filteredData = useMemo(() => {
+    console.log('>> SET FILTER DATA BY', filterParams, _data)
+    const filteredData = []
+    for (const item of _data) {
+      console.log(item)
+      if (filterFunc(filterParams, item)) {
+        filteredData.push(item)
+      }
+    }
+    return filteredData
+  }, [_data, filterParams, filterFunc])
+
+  // page related
+  const [pagedData, setPagedData] = useState([])
+  const [pageOptions, setPageOptions] = useState([5, 25, 50, 75, 100])
+  const [currentPage, setCurrentPage] = useState(1)
+  const [perPage, setPerPage] = useState(pageOptions[1])
+  const [maxPage, setMaxPage] = useState(0)
+
+  // others
+  const [isLoading, setIsLoading] = useState(initialLoadingState || false)
+  const [isProcessing, setIsProcessing] = useState(false)
+  const [refresh, setRefresh] = useState(false)
+
+  const reCalMaxPage = useCallback(() => {
+    setMaxPage(Math.max(1, Math.ceil(filteredData.length / perPage)))
+    console.log('>> MAX PAGE = ', Math.max(1, Math.ceil(filteredData.length / perPage)))
+  }, [filteredData, perPage, setMaxPage])
+
+  const setData = useCallback((data) => {

Review Comment:
   @likyh We can leave for now though I don't think we really need this extra setter, there shouldn't be a need for a default value, it is already initialized as an empty array when `[data, ...]` is defined.



-- 
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: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] e2corporation commented on pull request #2780: feat: create paginator hook and paginate blueprints grid

Posted by GitBox <gi...@apache.org>.
e2corporation commented on PR #2780:
URL: https://github.com/apache/incubator-devlake/pull/2780#issuecomment-1227160177

   @likyh Nice work, thanks for the updated changes. Are you able to now add pagination to the Historical Runs grid or do you want to add that under another PR?


-- 
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: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] e2corporation commented on a diff in pull request #2780: feat: create paginator hook and paginate blueprints grid

Posted by GitBox <gi...@apache.org>.
e2corporation commented on code in PR #2780:
URL: https://github.com/apache/incubator-devlake/pull/2780#discussion_r954254683


##########
config-ui/src/hooks/usePaginator.jsx:
##########
@@ -0,0 +1,217 @@
+/*
+ * 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, useRef, useCallback, useMemo } from 'react'
+import {
+  Popover,
+  Menu,
+  MenuItem,
+  Button
+} from '@blueprintjs/core'
+
+import { integrationsData } from '@/data/integrations'
+
+const PagingOptionsMenu = (props) => {
+  const { pageOptions = [10, 25, 50, 75, 100], perPage = 10, setPerPage = (page) => undefined } = props
+  return (
+    <Menu>
+      {pageOptions && pageOptions.map(pageOption => (
+        <MenuItem
+          key={pageOption}
+          active={perPage === pageOption}
+          icon='key-option'
+          text={`${pageOption} Records`}
+          onClick={() => setPerPage(pageOption)}
+        />))}
+    </Menu>
+  )
+}
+
+const Controls = (props) => {
+  const {
+    enabled = true,
+    pagingOptionsMenu,
+    currentPage,
+    perPage = 10,
+    maxPage,
+    onPrevPage = () => {},
+    onNextPage = () => {},
+    isLoading = false,
+  } = props
+
+  return (
+    <div
+      className='pagination-controls'
+      style={{ display: 'flex', whiteSpace: 'nowrap' }}
+    >
+      <Popover placement='bottom'>
+        <Button
+          className='btn-select-page-size'
+          style={{ whiteSpace: 'nowrap' }}
+          icon='numbered-list'
+          text={`Rows: ${perPage}`}
+          disabled={isLoading}
+          outlined
+          minimal
+        />
+        <>{pagingOptionsMenu}</>
+      </Popover>
+      <Button
+        onClick={onPrevPage}
+        className='pagination-btn btn-prev-page'
+        icon='step-backward'
+        small
+        text='PREV'
+        style={{ marginLeft: '5px', marginRight: '5px', whiteSpace: 'nowrap' }}
+        disabled={currentPage === 1 || isLoading}
+      />
+      <Button
+        style={{ whiteSpace: 'nowrap' }}
+        disabled={currentPage === maxPage || isLoading}
+        onClick={onNextPage}
+        className='pagination-btn btn-next-page'
+        rightIcon='step-forward'
+        text='NEXT'
+        small
+      />
+    </div>
+  )
+}
+
+function usePaginator (initialLoadingState = false) {
+  // const [integrations, setIntegrations] = useState(integrationsData)
+
+  const [_data, _setData] = useState([])
+
+  // filter related
+  const [filterParams, setFilterParams] = useState({})
+  const [filterFunc, setFilterFunc] = useState(() => (params, item) => true)
+  const filteredData = useMemo(() => {
+    console.log('>> SET FILTER DATA BY', filterParams, _data)
+    const filteredData = []
+    for (const item of _data) {
+      console.log(item)
+      if (filterFunc(filterParams, item)) {
+        filteredData.push(item)
+      }
+    }
+    return filteredData
+  }, [_data, filterParams, filterFunc])
+
+  // page related
+  const [pagedData, setPagedData] = useState([])
+  const [pageOptions, setPageOptions] = useState([5, 25, 50, 75, 100])
+  const [currentPage, setCurrentPage] = useState(1)
+  const [perPage, setPerPage] = useState(pageOptions[1])
+  const [maxPage, setMaxPage] = useState(0)

Review Comment:
   ```suggestion
   const maxPage = useMemo(() => Math.max(1, Math.ceil(filteredData.length / perPage)), [filteredData, perPage])
   ```



-- 
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: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] e2corporation commented on a diff in pull request #2780: feat: create paginator hook and paginate blueprints grid

Posted by GitBox <gi...@apache.org>.
e2corporation commented on code in PR #2780:
URL: https://github.com/apache/incubator-devlake/pull/2780#discussion_r954259315


##########
config-ui/src/hooks/usePaginator.jsx:
##########
@@ -0,0 +1,217 @@
+/*
+ * 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, useRef, useCallback, useMemo } from 'react'
+import {
+  Popover,
+  Menu,
+  MenuItem,
+  Button
+} from '@blueprintjs/core'
+
+import { integrationsData } from '@/data/integrations'
+
+const PagingOptionsMenu = (props) => {
+  const { pageOptions = [10, 25, 50, 75, 100], perPage = 10, setPerPage = (page) => undefined } = props
+  return (
+    <Menu>
+      {pageOptions && pageOptions.map(pageOption => (
+        <MenuItem
+          key={pageOption}
+          active={perPage === pageOption}
+          icon='key-option'
+          text={`${pageOption} Records`}
+          onClick={() => setPerPage(pageOption)}
+        />))}
+    </Menu>
+  )
+}
+
+const Controls = (props) => {
+  const {
+    enabled = true,
+    pagingOptionsMenu,
+    currentPage,
+    perPage = 10,
+    maxPage,
+    onPrevPage = () => {},
+    onNextPage = () => {},
+    isLoading = false,
+  } = props
+
+  return (
+    <div
+      className='pagination-controls'
+      style={{ display: 'flex', whiteSpace: 'nowrap' }}
+    >
+      <Popover placement='bottom'>
+        <Button
+          className='btn-select-page-size'
+          style={{ whiteSpace: 'nowrap' }}
+          icon='numbered-list'
+          text={`Rows: ${perPage}`}
+          disabled={isLoading}
+          outlined
+          minimal
+        />
+        <>{pagingOptionsMenu}</>
+      </Popover>
+      <Button
+        onClick={onPrevPage}
+        className='pagination-btn btn-prev-page'
+        icon='step-backward'
+        small
+        text='PREV'
+        style={{ marginLeft: '5px', marginRight: '5px', whiteSpace: 'nowrap' }}
+        disabled={currentPage === 1 || isLoading}
+      />
+      <Button
+        style={{ whiteSpace: 'nowrap' }}
+        disabled={currentPage === maxPage || isLoading}
+        onClick={onNextPage}
+        className='pagination-btn btn-next-page'
+        rightIcon='step-forward'
+        text='NEXT'
+        small
+      />
+    </div>
+  )
+}
+
+function usePaginator (initialLoadingState = false) {
+  // const [integrations, setIntegrations] = useState(integrationsData)
+
+  const [_data, _setData] = useState([])
+
+  // filter related
+  const [filterParams, setFilterParams] = useState({})
+  const [filterFunc, setFilterFunc] = useState(() => (params, item) => true)
+  const filteredData = useMemo(() => {
+    console.log('>> SET FILTER DATA BY', filterParams, _data)
+    const filteredData = []
+    for (const item of _data) {
+      console.log(item)
+      if (filterFunc(filterParams, item)) {
+        filteredData.push(item)
+      }
+    }
+    return filteredData
+  }, [_data, filterParams, filterFunc])
+
+  // page related
+  const [pagedData, setPagedData] = useState([])
+  const [pageOptions, setPageOptions] = useState([5, 25, 50, 75, 100])
+  const [currentPage, setCurrentPage] = useState(1)
+  const [perPage, setPerPage] = useState(pageOptions[1])
+  const [maxPage, setMaxPage] = useState(0)
+
+  // others
+  const [isLoading, setIsLoading] = useState(initialLoadingState || false)
+  const [isProcessing, setIsProcessing] = useState(false)
+  const [refresh, setRefresh] = useState(false)
+
+  const reCalMaxPage = useCallback(() => {
+    setMaxPage(Math.max(1, Math.ceil(filteredData.length / perPage)))
+    console.log('>> MAX PAGE = ', Math.max(1, Math.ceil(filteredData.length / perPage)))
+  }, [filteredData, perPage, setMaxPage])
+
+  const setData = useCallback((data) => {

Review Comment:
   This callback is unnecessary and should be removed since `setData` will be exported after `Ln 98` is refactored.



-- 
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: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] likyh commented on a diff in pull request #2780: feat: create paginator hook and paginate blueprints grid

Posted by GitBox <gi...@apache.org>.
likyh commented on code in PR #2780:
URL: https://github.com/apache/incubator-devlake/pull/2780#discussion_r954441719


##########
config-ui/src/hooks/usePaginator.jsx:
##########
@@ -0,0 +1,217 @@
+/*
+ * 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, useRef, useCallback, useMemo } from 'react'
+import {
+  Popover,
+  Menu,
+  MenuItem,
+  Button
+} from '@blueprintjs/core'
+
+import { integrationsData } from '@/data/integrations'
+
+const PagingOptionsMenu = (props) => {
+  const { pageOptions = [10, 25, 50, 75, 100], perPage = 10, setPerPage = (page) => undefined } = props
+  return (
+    <Menu>
+      {pageOptions && pageOptions.map(pageOption => (
+        <MenuItem
+          key={pageOption}
+          active={perPage === pageOption}
+          icon='key-option'
+          text={`${pageOption} Records`}
+          onClick={() => setPerPage(pageOption)}
+        />))}
+    </Menu>
+  )
+}
+
+const Controls = (props) => {
+  const {
+    enabled = true,
+    pagingOptionsMenu,
+    currentPage,
+    perPage = 10,
+    maxPage,
+    onPrevPage = () => {},
+    onNextPage = () => {},
+    isLoading = false,
+  } = props
+
+  return (
+    <div
+      className='pagination-controls'
+      style={{ display: 'flex', whiteSpace: 'nowrap' }}
+    >
+      <Popover placement='bottom'>
+        <Button
+          className='btn-select-page-size'
+          style={{ whiteSpace: 'nowrap' }}
+          icon='numbered-list'
+          text={`Rows: ${perPage}`}
+          disabled={isLoading}
+          outlined
+          minimal
+        />
+        <>{pagingOptionsMenu}</>
+      </Popover>
+      <Button
+        onClick={onPrevPage}
+        className='pagination-btn btn-prev-page'
+        icon='step-backward'
+        small
+        text='PREV'
+        style={{ marginLeft: '5px', marginRight: '5px', whiteSpace: 'nowrap' }}
+        disabled={currentPage === 1 || isLoading}
+      />
+      <Button
+        style={{ whiteSpace: 'nowrap' }}
+        disabled={currentPage === maxPage || isLoading}
+        onClick={onNextPage}
+        className='pagination-btn btn-next-page'
+        rightIcon='step-forward'
+        text='NEXT'
+        small
+      />
+    </div>
+  )
+}
+
+function usePaginator (initialLoadingState = false) {
+  // const [integrations, setIntegrations] = useState(integrationsData)
+
+  const [_data, _setData] = useState([])
+
+  // filter related
+  const [filterParams, setFilterParams] = useState({})
+  const [filterFunc, setFilterFunc] = useState(() => (params, item) => true)
+  const filteredData = useMemo(() => {
+    console.log('>> SET FILTER DATA BY', filterParams, _data)
+    const filteredData = []
+    for (const item of _data) {
+      console.log(item)
+      if (filterFunc(filterParams, item)) {
+        filteredData.push(item)
+      }
+    }
+    return filteredData
+  }, [_data, filterParams, filterFunc])
+
+  // page related
+  const [pagedData, setPagedData] = useState([])
+  const [pageOptions, setPageOptions] = useState([5, 25, 50, 75, 100])
+  const [currentPage, setCurrentPage] = useState(1)
+  const [perPage, setPerPage] = useState(pageOptions[1])
+  const [maxPage, setMaxPage] = useState(0)
+
+  // others
+  const [isLoading, setIsLoading] = useState(initialLoadingState || false)
+  const [isProcessing, setIsProcessing] = useState(false)
+  const [refresh, setRefresh] = useState(false)
+
+  const reCalMaxPage = useCallback(() => {

Review Comment:
   fixed



##########
config-ui/src/hooks/usePaginator.jsx:
##########
@@ -0,0 +1,217 @@
+/*
+ * 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, useRef, useCallback, useMemo } from 'react'
+import {
+  Popover,
+  Menu,
+  MenuItem,
+  Button
+} from '@blueprintjs/core'
+
+import { integrationsData } from '@/data/integrations'
+
+const PagingOptionsMenu = (props) => {
+  const { pageOptions = [10, 25, 50, 75, 100], perPage = 10, setPerPage = (page) => undefined } = props
+  return (
+    <Menu>
+      {pageOptions && pageOptions.map(pageOption => (
+        <MenuItem
+          key={pageOption}
+          active={perPage === pageOption}
+          icon='key-option'
+          text={`${pageOption} Records`}
+          onClick={() => setPerPage(pageOption)}
+        />))}
+    </Menu>
+  )
+}
+
+const Controls = (props) => {
+  const {
+    enabled = true,
+    pagingOptionsMenu,
+    currentPage,
+    perPage = 10,
+    maxPage,
+    onPrevPage = () => {},
+    onNextPage = () => {},
+    isLoading = false,
+  } = props
+
+  return (
+    <div
+      className='pagination-controls'
+      style={{ display: 'flex', whiteSpace: 'nowrap' }}
+    >
+      <Popover placement='bottom'>
+        <Button
+          className='btn-select-page-size'
+          style={{ whiteSpace: 'nowrap' }}
+          icon='numbered-list'
+          text={`Rows: ${perPage}`}
+          disabled={isLoading}
+          outlined
+          minimal
+        />
+        <>{pagingOptionsMenu}</>
+      </Popover>
+      <Button
+        onClick={onPrevPage}
+        className='pagination-btn btn-prev-page'
+        icon='step-backward'
+        small
+        text='PREV'
+        style={{ marginLeft: '5px', marginRight: '5px', whiteSpace: 'nowrap' }}
+        disabled={currentPage === 1 || isLoading}
+      />
+      <Button
+        style={{ whiteSpace: 'nowrap' }}
+        disabled={currentPage === maxPage || isLoading}
+        onClick={onNextPage}
+        className='pagination-btn btn-next-page'
+        rightIcon='step-forward'
+        text='NEXT'
+        small
+      />
+    </div>
+  )
+}
+
+function usePaginator (initialLoadingState = false) {
+  // const [integrations, setIntegrations] = useState(integrationsData)
+
+  const [_data, _setData] = useState([])
+
+  // filter related
+  const [filterParams, setFilterParams] = useState({})
+  const [filterFunc, setFilterFunc] = useState(() => (params, item) => true)
+  const filteredData = useMemo(() => {
+    console.log('>> SET FILTER DATA BY', filterParams, _data)
+    const filteredData = []
+    for (const item of _data) {
+      console.log(item)
+      if (filterFunc(filterParams, item)) {
+        filteredData.push(item)
+      }
+    }
+    return filteredData
+  }, [_data, filterParams, filterFunc])
+
+  // page related
+  const [pagedData, setPagedData] = useState([])
+  const [pageOptions, setPageOptions] = useState([5, 25, 50, 75, 100])
+  const [currentPage, setCurrentPage] = useState(1)
+  const [perPage, setPerPage] = useState(pageOptions[1])
+  const [maxPage, setMaxPage] = useState(0)
+
+  // others
+  const [isLoading, setIsLoading] = useState(initialLoadingState || false)
+  const [isProcessing, setIsProcessing] = useState(false)
+  const [refresh, setRefresh] = useState(false)
+
+  const reCalMaxPage = useCallback(() => {
+    setMaxPage(Math.max(1, Math.ceil(filteredData.length / perPage)))
+    console.log('>> MAX PAGE = ', Math.max(1, Math.ceil(filteredData.length / perPage)))
+  }, [filteredData, perPage, setMaxPage])
+
+  const setData = useCallback((data) => {
+    console.log('>> SET ALL DATA...', _data)
+    _setData(data || [])
+    reCalMaxPage()
+  }, [_setData, setRefresh])
+
+  const goNextPage = useCallback(() => {
+    console.log('>>> PAGINATOR: GO NEXT PAGE ...')
+    setCurrentPage(currentPage => Math.min(maxPage, currentPage + 1))
+    // setRefresh((r) => !r)
+    console.log('>>>> NEXT PAGE', currentPage)
+  }, [maxPage, currentPage, setRefresh])
+
+  const goPrevPage = useCallback(() => {
+    console.log('>>> PAGINATOR: GO PREV PAGE ...')
+    setCurrentPage(currentPage => Math.max(1, currentPage - 1))
+    // setRefresh((r) => !r)
+    console.log('>>>> PREV PAGE', currentPage)
+  }, [maxPage, currentPage, setRefresh])
+
+  const changePerPage = useCallback((perPage) => {
+    setPerPage(perPage)
+    setCurrentPage(1)
+    reCalMaxPage()
+  }, [setPerPage])
+
+  const resetPage = useCallback(() => {
+    setCurrentPage(1)
+  }, [currentPage])
+
+  const paginateData = useCallback(() => {
+    console.log('>> FILTERED DATA...', filteredData)
+    const sliceBegin = (currentPage - 1) * perPage
+    const sliceEnd = currentPage * perPage
+    setPagedData(filteredData.slice(sliceBegin, sliceEnd))
+    console.log('>> PAGED DATA = ', filteredData.slice(sliceBegin, sliceEnd))
+  }, [filteredData, perPage, currentPage, setPagedData])
+
+  useEffect(() => {
+    paginateData()
+  }, [refresh, perPage, filteredData, currentPage, paginateData])
+
+  useEffect(() => {
+    reCalMaxPage()
+  }, [refresh, reCalMaxPage, perPage, filteredData])
+
+  const renderControlsComponent = useCallback(() => {
+    return (
+      <Controls
+        currentPage={currentPage}
+        onNextPage={goNextPage}
+        onPrevPage={goPrevPage}
+        maxPage={maxPage}
+        perPage={perPage}
+        isLoading={isLoading}
+        pagingOptionsMenu={
+          <PagingOptionsMenu pageOptions={pageOptions} perPage={perPage} setPerPage={changePerPage} />
+        }
+      />
+    )
+  }, [currentPage, maxPage, perPage, isLoading, goNextPage, goPrevPage, changePerPage])
+
+  return {
+    goNextPage,
+    goPrevPage,
+    resetPage,
+    setPageOptions,
+    renderControlsComponent,
+    isLoading,
+    isProcessing,
+    data: _data,

Review Comment:
   fixed



-- 
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: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] likyh commented on a diff in pull request #2780: feat: create paginator hook and paginate blueprints grid

Posted by GitBox <gi...@apache.org>.
likyh commented on code in PR #2780:
URL: https://github.com/apache/incubator-devlake/pull/2780#discussion_r954441586


##########
config-ui/src/hooks/usePaginator.jsx:
##########
@@ -0,0 +1,217 @@
+/*
+ * 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, useRef, useCallback, useMemo } from 'react'
+import {
+  Popover,
+  Menu,
+  MenuItem,
+  Button
+} from '@blueprintjs/core'
+
+import { integrationsData } from '@/data/integrations'
+
+const PagingOptionsMenu = (props) => {
+  const { pageOptions = [10, 25, 50, 75, 100], perPage = 10, setPerPage = (page) => undefined } = props
+  return (
+    <Menu>
+      {pageOptions && pageOptions.map(pageOption => (
+        <MenuItem
+          key={pageOption}
+          active={perPage === pageOption}
+          icon='key-option'
+          text={`${pageOption} Records`}
+          onClick={() => setPerPage(pageOption)}
+        />))}
+    </Menu>
+  )
+}
+
+const Controls = (props) => {
+  const {
+    enabled = true,
+    pagingOptionsMenu,
+    currentPage,
+    perPage = 10,
+    maxPage,
+    onPrevPage = () => {},
+    onNextPage = () => {},
+    isLoading = false,
+  } = props
+
+  return (
+    <div
+      className='pagination-controls'
+      style={{ display: 'flex', whiteSpace: 'nowrap' }}
+    >
+      <Popover placement='bottom'>
+        <Button
+          className='btn-select-page-size'
+          style={{ whiteSpace: 'nowrap' }}
+          icon='numbered-list'
+          text={`Rows: ${perPage}`}
+          disabled={isLoading}
+          outlined
+          minimal
+        />
+        <>{pagingOptionsMenu}</>
+      </Popover>
+      <Button
+        onClick={onPrevPage}
+        className='pagination-btn btn-prev-page'
+        icon='step-backward'
+        small
+        text='PREV'
+        style={{ marginLeft: '5px', marginRight: '5px', whiteSpace: 'nowrap' }}
+        disabled={currentPage === 1 || isLoading}
+      />
+      <Button
+        style={{ whiteSpace: 'nowrap' }}
+        disabled={currentPage === maxPage || isLoading}
+        onClick={onNextPage}
+        className='pagination-btn btn-next-page'
+        rightIcon='step-forward'
+        text='NEXT'
+        small
+      />
+    </div>
+  )
+}
+
+function usePaginator (initialLoadingState = false) {
+  // const [integrations, setIntegrations] = useState(integrationsData)
+
+  const [_data, _setData] = useState([])

Review Comment:
   fixed



##########
config-ui/src/hooks/usePaginator.jsx:
##########
@@ -0,0 +1,217 @@
+/*
+ * 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, useRef, useCallback, useMemo } from 'react'
+import {
+  Popover,
+  Menu,
+  MenuItem,
+  Button
+} from '@blueprintjs/core'
+
+import { integrationsData } from '@/data/integrations'
+
+const PagingOptionsMenu = (props) => {
+  const { pageOptions = [10, 25, 50, 75, 100], perPage = 10, setPerPage = (page) => undefined } = props
+  return (
+    <Menu>
+      {pageOptions && pageOptions.map(pageOption => (
+        <MenuItem
+          key={pageOption}
+          active={perPage === pageOption}
+          icon='key-option'
+          text={`${pageOption} Records`}
+          onClick={() => setPerPage(pageOption)}
+        />))}
+    </Menu>
+  )
+}
+
+const Controls = (props) => {
+  const {
+    enabled = true,
+    pagingOptionsMenu,
+    currentPage,
+    perPage = 10,
+    maxPage,
+    onPrevPage = () => {},
+    onNextPage = () => {},
+    isLoading = false,
+  } = props
+
+  return (
+    <div
+      className='pagination-controls'
+      style={{ display: 'flex', whiteSpace: 'nowrap' }}
+    >
+      <Popover placement='bottom'>
+        <Button
+          className='btn-select-page-size'
+          style={{ whiteSpace: 'nowrap' }}
+          icon='numbered-list'
+          text={`Rows: ${perPage}`}
+          disabled={isLoading}
+          outlined
+          minimal
+        />
+        <>{pagingOptionsMenu}</>
+      </Popover>
+      <Button
+        onClick={onPrevPage}
+        className='pagination-btn btn-prev-page'
+        icon='step-backward'
+        small
+        text='PREV'
+        style={{ marginLeft: '5px', marginRight: '5px', whiteSpace: 'nowrap' }}
+        disabled={currentPage === 1 || isLoading}
+      />
+      <Button
+        style={{ whiteSpace: 'nowrap' }}
+        disabled={currentPage === maxPage || isLoading}
+        onClick={onNextPage}
+        className='pagination-btn btn-next-page'
+        rightIcon='step-forward'
+        text='NEXT'
+        small
+      />
+    </div>
+  )
+}
+
+function usePaginator (initialLoadingState = false) {
+  // const [integrations, setIntegrations] = useState(integrationsData)
+
+  const [_data, _setData] = useState([])

Review Comment:
   fixed



-- 
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: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] e2corporation commented on a diff in pull request #2780: feat: create paginator hook and paginate blueprints grid

Posted by GitBox <gi...@apache.org>.
e2corporation commented on code in PR #2780:
URL: https://github.com/apache/incubator-devlake/pull/2780#discussion_r954256285


##########
config-ui/src/hooks/usePaginator.jsx:
##########
@@ -0,0 +1,217 @@
+/*
+ * 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, useRef, useCallback, useMemo } from 'react'
+import {
+  Popover,
+  Menu,
+  MenuItem,
+  Button
+} from '@blueprintjs/core'
+
+import { integrationsData } from '@/data/integrations'
+
+const PagingOptionsMenu = (props) => {
+  const { pageOptions = [10, 25, 50, 75, 100], perPage = 10, setPerPage = (page) => undefined } = props
+  return (
+    <Menu>
+      {pageOptions && pageOptions.map(pageOption => (
+        <MenuItem
+          key={pageOption}
+          active={perPage === pageOption}
+          icon='key-option'
+          text={`${pageOption} Records`}
+          onClick={() => setPerPage(pageOption)}
+        />))}
+    </Menu>
+  )
+}
+
+const Controls = (props) => {
+  const {
+    enabled = true,
+    pagingOptionsMenu,
+    currentPage,
+    perPage = 10,
+    maxPage,
+    onPrevPage = () => {},
+    onNextPage = () => {},
+    isLoading = false,
+  } = props
+
+  return (
+    <div
+      className='pagination-controls'
+      style={{ display: 'flex', whiteSpace: 'nowrap' }}
+    >
+      <Popover placement='bottom'>
+        <Button
+          className='btn-select-page-size'
+          style={{ whiteSpace: 'nowrap' }}
+          icon='numbered-list'
+          text={`Rows: ${perPage}`}
+          disabled={isLoading}
+          outlined
+          minimal
+        />
+        <>{pagingOptionsMenu}</>
+      </Popover>
+      <Button
+        onClick={onPrevPage}
+        className='pagination-btn btn-prev-page'
+        icon='step-backward'
+        small
+        text='PREV'
+        style={{ marginLeft: '5px', marginRight: '5px', whiteSpace: 'nowrap' }}
+        disabled={currentPage === 1 || isLoading}
+      />
+      <Button
+        style={{ whiteSpace: 'nowrap' }}
+        disabled={currentPage === maxPage || isLoading}
+        onClick={onNextPage}
+        className='pagination-btn btn-next-page'
+        rightIcon='step-forward'
+        text='NEXT'
+        small
+      />
+    </div>
+  )
+}
+
+function usePaginator (initialLoadingState = false) {
+  // const [integrations, setIntegrations] = useState(integrationsData)
+
+  const [_data, _setData] = useState([])
+
+  // filter related
+  const [filterParams, setFilterParams] = useState({})
+  const [filterFunc, setFilterFunc] = useState(() => (params, item) => true)
+  const filteredData = useMemo(() => {
+    console.log('>> SET FILTER DATA BY', filterParams, _data)
+    const filteredData = []
+    for (const item of _data) {
+      console.log(item)
+      if (filterFunc(filterParams, item)) {
+        filteredData.push(item)
+      }
+    }
+    return filteredData
+  }, [_data, filterParams, filterFunc])
+
+  // page related
+  const [pagedData, setPagedData] = useState([])
+  const [pageOptions, setPageOptions] = useState([5, 25, 50, 75, 100])
+  const [currentPage, setCurrentPage] = useState(1)
+  const [perPage, setPerPage] = useState(pageOptions[1])
+  const [maxPage, setMaxPage] = useState(0)
+
+  // others
+  const [isLoading, setIsLoading] = useState(initialLoadingState || false)
+  const [isProcessing, setIsProcessing] = useState(false)
+  const [refresh, setRefresh] = useState(false)
+
+  const reCalMaxPage = useCallback(() => {

Review Comment:
   Delete this callback `reCalMaxPage` after `maxPage` is converted to a memoized value.



-- 
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: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org