refactor(config-ui): the blueprints list page (#4047)

diff --git a/config-ui/src/App.js b/config-ui/src/App.js
index 91c2b91..9e0d779 100644
--- a/config-ui/src/App.js
+++ b/config-ui/src/App.js
@@ -31,13 +31,12 @@
   ConnectionHomePage,
   WebHookConnectionPage,
   CreateBlueprintPage,
+  BlueprintHomePage,
   BlueprintDetailPage
 } from '@/pages'
-import Integration from '@/pages/configure/integration/index'
 import ManageIntegration from '@/pages/configure/integration/manage'
 import AddConnection from '@/pages/configure/connections/AddConnection'
 import ConfigureConnection from '@/pages/configure/connections/ConfigureConnection'
-import Blueprints from '@/pages/blueprints/index'
 
 function App() {
   return (
@@ -80,7 +79,11 @@
           path='/connections/configure/:providerId/:connectionId'
           component={() => <ConfigureConnection />}
         />
-        <Route exact path='/blueprints' component={() => <Blueprints />} />
+        <Route
+          exact
+          path='/blueprints'
+          component={() => <BlueprintHomePage />}
+        />
         <Route
           exact
           path='/blueprints/create'
diff --git a/config-ui/src/pages/blueprint/home/api.ts b/config-ui/src/pages/blueprint/home/api.ts
new file mode 100644
index 0000000..869eca9
--- /dev/null
+++ b/config-ui/src/pages/blueprint/home/api.ts
@@ -0,0 +1,21 @@
+/*
+ * 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 request from '@/components/utils/request'
+
+export const getBlueprints = () => request('/blueprints')
diff --git a/config-ui/src/pages/blueprint/home/index.tsx b/config-ui/src/pages/blueprint/home/index.tsx
new file mode 100644
index 0000000..a6ec6da
--- /dev/null
+++ b/config-ui/src/pages/blueprint/home/index.tsx
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+import React, { useMemo } from 'react'
+import { useHistory } from 'react-router-dom'
+import { ButtonGroup, Button, Intent } from '@blueprintjs/core'
+
+import { PageLoading, PageHeader, Table, ColumnType } from '@/components'
+import { getCron, getCronOptions } from '@/config'
+import { formatTime } from '@/utils'
+
+import type { BlueprintType } from '../types'
+import { ModeEnum } from '../types'
+
+import { useHome } from './use-home'
+import * as S from './styled'
+
+export const BlueprintHomePage = () => {
+  const history = useHistory()
+
+  const { loading, dataSource, type, onChangeType } = useHome()
+
+  const options = useMemo(() => getCronOptions(), [])
+
+  const columns = useMemo(
+    () =>
+      [
+        {
+          title: 'Blueprint Name',
+          dataIndex: 'name',
+          key: 'name'
+        },
+        {
+          title: 'Data Connections',
+          key: 'connections',
+          render: (_, row) => {
+            if (row.mode === ModeEnum.advanced) {
+              return 'Advanced Mode'
+            }
+            return row.settings.connections.map((cs) => cs.plugin).join(',')
+          }
+        },
+        {
+          title: 'Frequency',
+          key: 'frequency',
+          render: (_, row) => {
+            const cron = getCron(row.isManual, row.cronConfig)
+            return cron.label
+          }
+        },
+        {
+          title: 'Next Run Time',
+          key: 'nextRunTime',
+          render: (_, row) => {
+            const cron = getCron(row.isManual, row.cronConfig)
+            return formatTime(cron.nextTime)
+          }
+        },
+        {
+          title: '',
+          dataIndex: 'id',
+          key: 'action',
+          align: 'center',
+          render: (val) => (
+            <Button
+              minimal
+              intent={Intent.PRIMARY}
+              icon='cog'
+              onClick={() => history.push(`/blueprints/${val}`)}
+            />
+          )
+        }
+      ] as ColumnType<BlueprintType>,
+    []
+  )
+
+  if (loading) {
+    return <PageLoading />
+  }
+
+  return (
+    <PageHeader breadcrumbs={[{ name: 'Blueprints', path: '/blueprints' }]}>
+      <S.Wrapper>
+        <div className='action'>
+          <ButtonGroup>
+            <Button
+              intent={type === 'all' ? Intent.PRIMARY : Intent.NONE}
+              text='All'
+              onClick={() => onChangeType('all')}
+            />
+            {options.map(({ label, value }) => (
+              <Button
+                key={value}
+                intent={type === value ? Intent.PRIMARY : Intent.NONE}
+                text={label}
+                onClick={() => onChangeType(value)}
+              />
+            ))}
+          </ButtonGroup>
+          <Button
+            intent={Intent.PRIMARY}
+            text='Create Blueprint'
+            onClick={() => history.push('/blueprints/create')}
+          />
+        </div>
+        <Table columns={columns} dataSource={dataSource} />
+      </S.Wrapper>
+    </PageHeader>
+  )
+}
diff --git a/config-ui/src/pages/blueprint/home/styled.ts b/config-ui/src/pages/blueprint/home/styled.ts
new file mode 100644
index 0000000..fc47e76
--- /dev/null
+++ b/config-ui/src/pages/blueprint/home/styled.ts
@@ -0,0 +1,28 @@
+/*
+ * 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 styled from 'styled-components'
+
+export const Wrapper = styled.div`
+  .action {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 16px;
+  }
+`
diff --git a/config-ui/src/pages/blueprint/home/use-home.ts b/config-ui/src/pages/blueprint/home/use-home.ts
new file mode 100644
index 0000000..dd6c23a
--- /dev/null
+++ b/config-ui/src/pages/blueprint/home/use-home.ts
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+import { useState, useEffect, useMemo } from 'react'
+
+import { cronPresets } from '@/config'
+
+import type { BlueprintType } from '../types'
+
+import * as API from './api'
+
+export const useHome = () => {
+  const [loading, setLoading] = useState(false)
+  const [blueprints, setBlueprints] = useState<BlueprintType[]>([])
+  const [dataSource, setDataSource] = useState<BlueprintType[]>([])
+  const [type, setType] = useState('all')
+
+  const presets = cronPresets.map((preset) => preset.config)
+
+  const getBlueprints = async () => {
+    setLoading(true)
+    try {
+      const res = await API.getBlueprints()
+      setBlueprints(res.blueprints)
+    } finally {
+      setLoading(false)
+    }
+  }
+
+  useEffect(() => {
+    getBlueprints()
+  }, [])
+
+  useEffect(() => {
+    setDataSource(
+      blueprints.filter((bp) => {
+        switch (type) {
+          case 'all':
+            return true
+          case 'manual':
+            return bp.isManual
+          case 'custom':
+            return !presets.includes(bp.cronConfig)
+          default:
+            return bp.cronConfig === type
+        }
+      })
+    )
+  }, [blueprints, type])
+
+  return useMemo(
+    () => ({
+      loading,
+      blueprints,
+      dataSource,
+      type,
+      onChangeType: setType
+    }),
+    [loading, blueprints, dataSource, type]
+  )
+}
diff --git a/config-ui/src/pages/blueprint/index.ts b/config-ui/src/pages/blueprint/index.ts
index 824bde2..52e04f1 100644
--- a/config-ui/src/pages/blueprint/index.ts
+++ b/config-ui/src/pages/blueprint/index.ts
@@ -17,5 +17,6 @@
  */
 
 export * from './types'
+export * from './home'
 export * from './create'
 export * from './detail'