refactor(config-ui): sync policy settings (#4157)

* refactor(config-ui): move plugins/common/sync-policy to pages/blueprint/components

* refactor(config-ui): rename StartFormSelector to start-form-selector

* refactor(config-ui): start from selector
diff --git a/config-ui/src/pages/blueprint/components/index.ts b/config-ui/src/pages/blueprint/components/index.ts
index 516c190..109693d 100644
--- a/config-ui/src/pages/blueprint/components/index.ts
+++ b/config-ui/src/pages/blueprint/components/index.ts
@@ -17,3 +17,4 @@
  */
 
 export * from './advanced-editor';
+export * from './sync-policy';
diff --git a/config-ui/src/plugins/common/sync-policy/index.tsx b/config-ui/src/pages/blueprint/components/sync-policy/index.tsx
similarity index 96%
rename from config-ui/src/plugins/common/sync-policy/index.tsx
rename to config-ui/src/pages/blueprint/components/sync-policy/index.tsx
index e6f1d0b..795eabf 100644
--- a/config-ui/src/plugins/common/sync-policy/index.tsx
+++ b/config-ui/src/pages/blueprint/components/sync-policy/index.tsx
@@ -23,7 +23,7 @@
 import { getCron, getCronOptions } from '@/config';
 import CronHelp from '@/images/cron-help.png';
 
-import StartFromSelector from './StartFromSelector';
+import StartFromSelector from './start-from-selector';
 import * as S from './styled';
 
 interface Props {
@@ -72,7 +72,7 @@
         <div className="block">
           <h3>Time Filter *</h3>
           <p>Select the data range you wish to collect. DevLake will collect the last six months of data by default.</p>
-          <StartFromSelector autoFillDefault={true} date={createdDateAfter} onSave={onChangeCreatedDateAfter} />
+          <StartFromSelector value={createdDateAfter} onChange={onChangeCreatedDateAfter} />
         </div>
       )}
       <div className="block">
diff --git a/config-ui/src/pages/blueprint/components/sync-policy/start-from-selector.tsx b/config-ui/src/pages/blueprint/components/sync-policy/start-from-selector.tsx
new file mode 100644
index 0000000..983ca5c
--- /dev/null
+++ b/config-ui/src/pages/blueprint/components/sync-policy/start-from-selector.tsx
@@ -0,0 +1,97 @@
+/*
+ * 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, { useCallback, useEffect, useMemo } from 'react';
+import { Tag } from '@blueprintjs/core';
+import { TimePrecision } from '@blueprintjs/datetime';
+import { DateInput2 } from '@blueprintjs/datetime2';
+
+import { formatTime } from '@/utils';
+
+import * as S from './styled';
+
+interface Props {
+  value: string | null;
+  onChange: (val: string | null) => void;
+}
+
+const StartFromSelector = ({ value, onChange }: Props) => {
+  const formatDate = useCallback((date: Date) => formatTime(date), []);
+  const parseDate = useCallback((str: string) => new Date(str), []);
+
+  const quickDates = useMemo(() => {
+    const now = new Date();
+    now.setHours(0, 0, 0, 0);
+    const ago6m = new Date(now);
+    ago6m.setMonth(now.getMonth() - 6);
+    const ago90d = new Date(now);
+    ago90d.setDate(ago90d.getDate() - 90);
+    const ago30d = new Date(now);
+    ago30d.setDate(ago30d.getDate() - 30);
+    const ago1y = new Date(now);
+    ago1y.setUTCFullYear(ago1y.getFullYear() - 1);
+    return [
+      { label: 'Last 6 months', date: ago6m },
+      { label: 'Last 90 days', date: ago90d },
+      { label: 'Last 30 days', date: ago30d },
+      { label: 'Last Year', date: ago1y },
+    ];
+  }, []);
+
+  const handleChangeDate = (val: string | Date | null) => {
+    onChange(val ? formatTime(val, 'YYYY-MM-DD[T]HH:mm:ssZ') : null);
+  };
+
+  useEffect(() => {
+    if (!value) {
+      handleChangeDate(quickDates[0].date);
+    }
+  }, [value]);
+
+  return (
+    <S.FromTimeWrapper>
+      <div className="quick-selection">
+        {quickDates.map((quickDate) => (
+          <Tag
+            key={quickDate.date.toISOString()}
+            minimal={formatDate(quickDate.date) !== formatTime(value)}
+            intent="primary"
+            onClick={() => handleChangeDate(quickDate.date)}
+            style={{ marginRight: 5 }}
+          >
+            {quickDate.label}
+          </Tag>
+        ))}
+      </div>
+
+      <div className="time-selection">
+        <DateInput2
+          timePrecision={TimePrecision.MINUTE}
+          formatDate={formatDate}
+          parseDate={parseDate}
+          placeholder="Select start from"
+          popoverProps={{ placement: 'bottom' }}
+          value={value}
+          onChange={handleChangeDate}
+        />{' '}
+        <strong>to Now</strong>
+      </div>
+    </S.FromTimeWrapper>
+  );
+};
+
+export default StartFromSelector;
diff --git a/config-ui/src/plugins/common/sync-policy/styled.ts b/config-ui/src/pages/blueprint/components/sync-policy/styled.ts
similarity index 82%
rename from config-ui/src/plugins/common/sync-policy/styled.ts
rename to config-ui/src/pages/blueprint/components/sync-policy/styled.ts
index 1878e08..cea6c13 100644
--- a/config-ui/src/plugins/common/sync-policy/styled.ts
+++ b/config-ui/src/pages/blueprint/components/sync-policy/styled.ts
@@ -23,6 +23,7 @@
     margin-top: 24px;
   }
 `;
+
 export const Input = styled.div`
   display: flex;
   align-items: center;
@@ -47,3 +48,22 @@
     width: 100%;
   }
 `;
+
+export const FromTimeWrapper = styled.div`
+  .quick-selection {
+    margin-bottom: 16px;
+
+    & > .bp4-tag {
+      cursor: pointer;
+    }
+  }
+
+  .time-selection {
+    display: flex;
+    align-items: center;
+
+    & > strong {
+      margin-left: 4px;
+    }
+  }
+`;
diff --git a/config-ui/src/pages/blueprint/create/step-four/index.tsx b/config-ui/src/pages/blueprint/create/step-four/index.tsx
index 24bb53d..2907740 100644
--- a/config-ui/src/pages/blueprint/create/step-four/index.tsx
+++ b/config-ui/src/pages/blueprint/create/step-four/index.tsx
@@ -18,11 +18,11 @@
 
 import React from 'react';
 
-import { SyncPolicy } from '@/plugins';
 import { Card, Divider } from '@/components';
 
 import { ModeEnum } from '../../types';
 import { useCreateBP } from '../bp-context';
+import { SyncPolicy } from '../../components';
 
 export const StepFour = () => {
   const {
diff --git a/config-ui/src/pages/blueprint/detail/components/update-policy-dialog/index.tsx b/config-ui/src/pages/blueprint/detail/components/update-policy-dialog/index.tsx
index d572451..5ba881b 100644
--- a/config-ui/src/pages/blueprint/detail/components/update-policy-dialog/index.tsx
+++ b/config-ui/src/pages/blueprint/detail/components/update-policy-dialog/index.tsx
@@ -19,10 +19,10 @@
 import React, { useState, useEffect } from 'react';
 
 import { Dialog } from '@/components';
-import { SyncPolicy } from '@/plugins';
 
 import type { BlueprintType } from '../../../types';
 import { ModeEnum } from '../../../types';
+import { SyncPolicy } from '../../../components';
 
 interface Props {
   blueprint: BlueprintType;
diff --git a/config-ui/src/plugins/common/index.ts b/config-ui/src/plugins/common/index.ts
index b19d137..1fdd733 100644
--- a/config-ui/src/plugins/common/index.ts
+++ b/config-ui/src/plugins/common/index.ts
@@ -19,4 +19,3 @@
 export * from './data-scope-list';
 export * from './data-scope';
 export * from './transformation';
-export * from './sync-policy';
diff --git a/config-ui/src/plugins/common/sync-policy/StartFromSelector.tsx b/config-ui/src/plugins/common/sync-policy/StartFromSelector.tsx
deleted file mode 100644
index a83072c..0000000
--- a/config-ui/src/plugins/common/sync-policy/StartFromSelector.tsx
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * 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, { useCallback, useEffect, useMemo } from 'react';
-import { Tag } from '@blueprintjs/core';
-import { TimePrecision } from '@blueprintjs/datetime';
-import { DateInput2 } from '@blueprintjs/datetime2';
-import dayjs from 'dayjs';
-
-const StartFromSelector = ({
-  placeholder = 'Select start from',
-  disabled = false,
-  autoFillDefault = false,
-  date,
-  onSave,
-}: {
-  placeholder?: string;
-  disabled?: boolean;
-  autoFillDefault?: boolean;
-  date: string | null;
-  onSave: (newDate: string | null, isUserChange?: boolean) => void;
-}) => {
-  const formatDate = useCallback((date: Date | string) => dayjs(date).format('YYYY-MM-DD[T]HH:mm:ssZ'), []);
-  const displayDate = useCallback((date: Date) => dayjs(date).format('L LTS'), []);
-  const parseDate = useCallback((str: string) => dayjs(str).toDate(), []);
-  const chooseDate = (date: Date | string | null) => {
-    onSave(date ? formatDate(date) : null);
-  };
-
-  const quickDates = useMemo(() => {
-    const now = new Date();
-    now.setHours(0, 0, 0, 0);
-    const ago6m = new Date(now);
-    ago6m.setMonth(now.getMonth() - 6);
-    const ago90d = new Date(now);
-    ago90d.setDate(ago90d.getDate() - 90);
-    const ago30d = new Date(now);
-    ago30d.setDate(ago30d.getDate() - 30);
-    const ago1y = new Date(now);
-    ago1y.setUTCFullYear(ago1y.getFullYear() - 1);
-    return [
-      { label: 'Last 6 months', date: ago6m },
-      { label: 'Last 90 days', date: ago90d },
-      { label: 'Last 30 days', date: ago30d },
-      { label: 'Last Year', date: ago1y },
-    ];
-  }, []);
-
-  useEffect(() => {
-    if (!date && autoFillDefault) {
-      onSave(formatDate(quickDates[0].date));
-    }
-  }, [date]);
-
-  return (
-    <>
-      <div className="start-from">
-        <div className="123" style={{ display: 'flex', marginBottom: '10px' }}>
-          {quickDates.map((quickDate) => (
-            <Tag
-              key={quickDate.date.toISOString()}
-              minimal={formatDate(quickDate.date) !== date}
-              intent="primary"
-              interactive={!disabled}
-              onClick={() => chooseDate(quickDate.date)}
-              style={{ marginRight: 5 }}
-            >
-              {quickDate.label}
-            </Tag>
-          ))}
-        </div>
-
-        <div style={{ display: 'flex', alignItems: 'baseline' }}>
-          <DateInput2
-            disabled={disabled}
-            timePrecision={TimePrecision.MINUTE}
-            formatDate={displayDate}
-            parseDate={parseDate}
-            fill={false}
-            placeholder={placeholder}
-            onChange={chooseDate}
-            popoverProps={{ placement: 'bottom' }}
-            value={date}
-          />
-          <span style={{ fontWeight: 'bold' }}> to Now</span>
-        </div>
-      </div>
-    </>
-  );
-};
-
-export default StartFromSelector;