From 0d98992bb6fca0755f57281142cf93ec2e5ccce9 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 4 Feb 2025 14:50:04 +0000
Subject: [PATCH 1/5] Bump net.snowflake:snowflake-jdbc

Bumps [net.snowflake:snowflake-jdbc](https://github.com/snowflakedb/snowflake-jdbc) from 3.13.33 to 3.22.0.
- [Release notes](https://github.com/snowflakedb/snowflake-jdbc/releases)
- [Changelog](https://github.com/snowflakedb/snowflake-jdbc/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/snowflakedb/snowflake-jdbc/compare/v3.13.33...v3.22.0)

---
updated-dependencies:
- dependency-name: net.snowflake:snowflake-jdbc
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
---
 server/api-service/lowcoder-plugins/snowflakePlugin/pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/server/api-service/lowcoder-plugins/snowflakePlugin/pom.xml b/server/api-service/lowcoder-plugins/snowflakePlugin/pom.xml
index a2cb0e729..9b114063b 100644
--- a/server/api-service/lowcoder-plugins/snowflakePlugin/pom.xml
+++ b/server/api-service/lowcoder-plugins/snowflakePlugin/pom.xml
@@ -30,7 +30,7 @@
         <dependency>
             <groupId>net.snowflake</groupId>
             <artifactId>snowflake-jdbc</artifactId>
-            <version>3.13.33</version>
+            <version>3.22.0</version>
         </dependency>
         <dependency>
             <groupId>org.lowcoder</groupId>

From 082e574c2ff23c8a7753870d02a55850fca107df Mon Sep 17 00:00:00 2001
From: Faran Javed <faran1997@outlook.com>
Date: Sat, 1 Mar 2025 03:09:31 +0500
Subject: [PATCH 2/5] add time component in dropdown #1549

---
 .../comps/tableComp/column/columnTypeComp.tsx |  7 ++
 .../column/columnTypeComps/columnTimeComp.tsx | 71 +++++++++++++++++++
 .../packages/lowcoder/src/i18n/locales/en.ts  |  1 +
 3 files changed, 79 insertions(+)
 create mode 100644 client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnTimeComp.tsx

diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComp.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComp.tsx
index 3757e6bc8..58e0b7df4 100644
--- a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComp.tsx
+++ b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComp.tsx
@@ -1,5 +1,6 @@
 import { CellProps } from "components/table/EditableCell";
 import { DateTimeComp } from "comps/comps/tableComp/column/columnTypeComps/columnDateTimeComp";
+import { TimeComp } from "./columnTypeComps/columnTimeComp";
 import { ButtonComp } from "comps/comps/tableComp/column/simpleColumnTypeComps";
 import { withType } from "comps/generators";
 import { trans } from "i18n";
@@ -67,6 +68,11 @@ const actionOptions = [
     label: trans("table.image"),
     value: "image",
   },
+  {
+    label: trans("table.time"),
+    value: "time",
+  },
+
   {
     label: trans("table.date"),
     value: "date",
@@ -116,6 +122,7 @@ export const ColumnTypeCompMap = {
   rating: RatingComp,
   progress: ProgressComp,
   date: DateComp,
+  time: TimeComp,
 };
 
 type ColumnTypeMapType = typeof ColumnTypeCompMap;
diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnTimeComp.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnTimeComp.tsx
new file mode 100644
index 000000000..be29e3d14
--- /dev/null
+++ b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnTimeComp.tsx
@@ -0,0 +1,71 @@
+import {
+    ColumnTypeCompBuilder,
+    ColumnTypeViewFn,
+  } from "comps/comps/tableComp/column/columnTypeCompBuilder";
+  import { ColumnValueTooltip } from "comps/comps/tableComp/column/simpleColumnTypeComps";
+  import { StringControl } from "comps/controls/codeControl";
+  import { withDefault } from "comps/generators";
+  import { formatPropertyView } from "comps/utils/propertyUtils";
+  import { trans } from "i18n";
+  import {
+    TIME_FORMAT,
+    formatTimestamp,
+    timestampToHumanReadable,
+  } from "util/dateTimeUtils";
+  import { DateEdit } from "./columnDateComp";
+  
+  const childrenMap = {
+    text: StringControl,
+    format: withDefault(StringControl, TIME_FORMAT),
+    inputFormat: withDefault(StringControl, TIME_FORMAT),
+  };
+  
+  let inputFormat = TIME_FORMAT;
+  
+  const getBaseValue: ColumnTypeViewFn<typeof childrenMap, string, string> = (props) =>
+    props.text;
+  
+  export const TimeComp = (function () {
+    return new ColumnTypeCompBuilder(
+      childrenMap,
+      (props, dispatch) => {
+        inputFormat = props.inputFormat;
+        const value = props.changeValue ?? getBaseValue(props, dispatch);
+  
+        // Convert value to a number if it's a valid timestamp
+        const timestamp = Number(value);
+        if (!isNaN(timestamp)) {
+          return formatTimestamp(timestamp);
+        }
+  
+        return timestampToHumanReadable(timestamp) ?? value; // Returns readable time
+      },
+      (nodeValue) => {
+        const timestamp = Number(nodeValue.text.value);
+        return !isNaN(timestamp)
+          ? timestampToHumanReadable(timestamp) // Convert to readable format if valid timestamp
+          : nodeValue.text.value; // Otherwise, return original value
+      },
+      getBaseValue
+    )
+      .setEditViewFn((props) => (
+        <DateEdit
+          value={props.value}
+          onChange={props.onChange}
+          onChangeEnd={props.onChangeEnd}
+          showTime={true} // Ensures only time is shown
+          inputFormat={inputFormat}
+        />
+      ))
+      .setPropertyViewFn((children) => (
+        <>
+          {children.text.propertyView({
+            label: trans("table.columnValue"),
+            tooltip: ColumnValueTooltip,
+          })}
+          {formatPropertyView({ children, placeholder: TIME_FORMAT })}
+        </>
+      ))
+      .build();
+  })();
+  
\ No newline at end of file
diff --git a/client/packages/lowcoder/src/i18n/locales/en.ts b/client/packages/lowcoder/src/i18n/locales/en.ts
index 48d4cbdc4..054b58153 100644
--- a/client/packages/lowcoder/src/i18n/locales/en.ts
+++ b/client/packages/lowcoder/src/i18n/locales/en.ts
@@ -2029,6 +2029,7 @@ export const en = {
     "tag": "Tag",
     "select": "Select",
     "dropdown": "Dropdown",
+    "time" : "Time",
     "date": "Date",
     "dateTime": "Date Time",
     "badgeStatus": "Status",

From 76a3b3e0b652944d1bd7967d745b70df76244cbc Mon Sep 17 00:00:00 2001
From: Faran Javed <faran1997@outlook.com>
Date: Sat, 1 Mar 2025 16:07:50 +0500
Subject: [PATCH 3/5] add suffix/prefix functionality in time #1549

---
 .../column/columnTypeComps/columnTimeComp.tsx | 151 ++++++++++--------
 1 file changed, 83 insertions(+), 68 deletions(-)

diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnTimeComp.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnTimeComp.tsx
index be29e3d14..e817b852b 100644
--- a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnTimeComp.tsx
+++ b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnTimeComp.tsx
@@ -1,71 +1,86 @@
 import {
-    ColumnTypeCompBuilder,
-    ColumnTypeViewFn,
-  } from "comps/comps/tableComp/column/columnTypeCompBuilder";
-  import { ColumnValueTooltip } from "comps/comps/tableComp/column/simpleColumnTypeComps";
-  import { StringControl } from "comps/controls/codeControl";
-  import { withDefault } from "comps/generators";
-  import { formatPropertyView } from "comps/utils/propertyUtils";
-  import { trans } from "i18n";
-  import {
-    TIME_FORMAT,
-    formatTimestamp,
-    timestampToHumanReadable,
-  } from "util/dateTimeUtils";
-  import { DateEdit } from "./columnDateComp";
-  
-  const childrenMap = {
-    text: StringControl,
-    format: withDefault(StringControl, TIME_FORMAT),
-    inputFormat: withDefault(StringControl, TIME_FORMAT),
-  };
-  
-  let inputFormat = TIME_FORMAT;
-  
-  const getBaseValue: ColumnTypeViewFn<typeof childrenMap, string, string> = (props) =>
-    props.text;
-  
-  export const TimeComp = (function () {
-    return new ColumnTypeCompBuilder(
-      childrenMap,
-      (props, dispatch) => {
-        inputFormat = props.inputFormat;
-        const value = props.changeValue ?? getBaseValue(props, dispatch);
-  
-        // Convert value to a number if it's a valid timestamp
-        const timestamp = Number(value);
-        if (!isNaN(timestamp)) {
-          return formatTimestamp(timestamp);
-        }
-  
-        return timestampToHumanReadable(timestamp) ?? value; // Returns readable time
-      },
-      (nodeValue) => {
-        const timestamp = Number(nodeValue.text.value);
-        return !isNaN(timestamp)
-          ? timestampToHumanReadable(timestamp) // Convert to readable format if valid timestamp
-          : nodeValue.text.value; // Otherwise, return original value
-      },
-      getBaseValue
-    )
-      .setEditViewFn((props) => (
-        <DateEdit
-          value={props.value}
-          onChange={props.onChange}
-          onChangeEnd={props.onChangeEnd}
-          showTime={true} // Ensures only time is shown
-          inputFormat={inputFormat}
-        />
-      ))
-      .setPropertyViewFn((children) => (
+  ColumnTypeCompBuilder,
+  ColumnTypeViewFn,
+} from "comps/comps/tableComp/column/columnTypeCompBuilder";
+import { ColumnValueTooltip } from "comps/comps/tableComp/column/simpleColumnTypeComps";
+import { StringControl } from "comps/controls/codeControl";
+import { withDefault } from "comps/generators";
+import { formatPropertyView } from "comps/utils/propertyUtils";
+import { trans } from "i18n";
+import {
+  TIME_FORMAT,
+  formatTimestamp,
+  timestampToHumanReadable,
+} from "util/dateTimeUtils";
+import { DateEdit } from "./columnDateComp";
+import { IconControl } from "comps/controls/iconControl";
+import { hasIcon } from "comps/utils";
+
+const childrenMap = {
+  text: StringControl,
+  format: withDefault(StringControl, TIME_FORMAT),
+  inputFormat: withDefault(StringControl, TIME_FORMAT),
+  prefixIcon: IconControl,
+  suffixIcon: IconControl,
+};
+
+let inputFormat = TIME_FORMAT;
+
+const getBaseValue: ColumnTypeViewFn<typeof childrenMap, string, string> = (props) =>
+  props.text;
+
+export const TimeComp = (function () {
+  return new ColumnTypeCompBuilder(
+    childrenMap,
+    (props, dispatch) => {
+      inputFormat = props.inputFormat;
+      const value = props.changeValue ?? getBaseValue(props, dispatch);
+
+      // Convert value to a number if it's a valid timestamp
+      const timestamp = Number(value);
+      const formattedValue = !isNaN(timestamp)
+        ? formatTimestamp(timestamp)
+        : timestampToHumanReadable(timestamp) ?? value;
+
+      return (
         <>
-          {children.text.propertyView({
-            label: trans("table.columnValue"),
-            tooltip: ColumnValueTooltip,
-          })}
-          {formatPropertyView({ children, placeholder: TIME_FORMAT })}
+          {hasIcon(props.prefixIcon) && <span>{props.prefixIcon}</span>}
+          <span>{formattedValue}</span>
+          {hasIcon(props.suffixIcon) && <span>{props.suffixIcon}</span>}
         </>
-      ))
-      .build();
-  })();
-  
\ No newline at end of file
+      );
+    },
+    (nodeValue) => {
+      const timestamp = Number(nodeValue.text.value);
+      return !isNaN(timestamp)
+        ? timestampToHumanReadable(timestamp)
+        : nodeValue.text.value;
+    },
+    getBaseValue
+  )
+    .setEditViewFn((props) => (
+      <DateEdit
+        value={props.value}
+        onChange={props.onChange}
+        onChangeEnd={props.onChangeEnd}
+        showTime={true} // Ensures only time is shown
+        inputFormat={inputFormat}
+      />
+    ))
+    .setPropertyViewFn((children) => (
+      <>
+        {children.text.propertyView({
+          label: trans("table.columnValue"),
+          tooltip: ColumnValueTooltip,
+        })}
+        {children.prefixIcon.propertyView({
+          label: trans("button.prefixIcon"),
+        })}
+        {children.suffixIcon.propertyView({
+          label: trans("button.suffixIcon"),
+        })}
+        {formatPropertyView({ children, placeholder: TIME_FORMAT })}
+      </>
+    ))
+    .build();
+})();

From 8a100b5a2e9c96beeadc66b8ec21953a0d3ed5ca Mon Sep 17 00:00:00 2001
From: Faran Javed <faran1997@outlook.com>
Date: Mon, 3 Mar 2025 17:33:18 +0500
Subject: [PATCH 4/5] [Fix]: Address Issues in Time-Only Column Type Table
 Component (#1549)

---
 .../column/columnTypeComps/columnTimeComp.tsx | 138 +++++++++++++-----
 1 file changed, 98 insertions(+), 40 deletions(-)

diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnTimeComp.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnTimeComp.tsx
index e817b852b..d07fba00a 100644
--- a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnTimeComp.tsx
+++ b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnTimeComp.tsx
@@ -1,3 +1,4 @@
+import { default as TimePicker } from "antd/es/time-picker";
 import {
   ColumnTypeCompBuilder,
   ColumnTypeViewFn,
@@ -7,27 +8,109 @@ import { StringControl } from "comps/controls/codeControl";
 import { withDefault } from "comps/generators";
 import { formatPropertyView } from "comps/utils/propertyUtils";
 import { trans } from "i18n";
-import {
-  TIME_FORMAT,
-  formatTimestamp,
-  timestampToHumanReadable,
-} from "util/dateTimeUtils";
-import { DateEdit } from "./columnDateComp";
-import { IconControl } from "comps/controls/iconControl";
-import { hasIcon } from "comps/utils";
+import dayjs from "dayjs";
+import { useEffect, useRef, useState } from "react";
+import styled from "styled-components";
+import { TIME_FORMAT } from "util/dateTimeUtils";
+
+const TimePickerStyled = styled(TimePicker)<{ $open: boolean }>`
+  width: 100%;
+  height: 100%;
+  position: absolute;
+  top: 0;
+  padding: 0;
+  padding-left: 11px;
+  .ant-picker-input {
+    height: 100%;
+  }
+  input {
+    padding-right: 18px;
+    cursor: pointer;
+  }
+  &.ant-picker-focused .ant-picker-suffix svg g {
+    stroke: ${(props) => props.$open && "#315EFB"};
+  }
+  .ant-picker-suffix {
+    height: calc(100% - 1px);
+    position: absolute;
+    right: 0;
+    top: 0.5px;
+    display: flex;
+    align-items: center;
+    padding: 0 3px;
+  }
+`;
+
+const Wrapper = styled.div`
+  background: transparent !important;
+`;
+
+export function formatTime(time: string, format: string) {
+  const parsedTime = dayjs(time, TIME_FORMAT);
+  return parsedTime.isValid() ? parsedTime.format(format) : "";
+}
 
 const childrenMap = {
   text: StringControl,
   format: withDefault(StringControl, TIME_FORMAT),
   inputFormat: withDefault(StringControl, TIME_FORMAT),
-  prefixIcon: IconControl,
-  suffixIcon: IconControl,
 };
 
 let inputFormat = TIME_FORMAT;
 
-const getBaseValue: ColumnTypeViewFn<typeof childrenMap, string, string> = (props) =>
-  props.text;
+const getBaseValue: ColumnTypeViewFn<typeof childrenMap, string, string> = (props) => props.text;
+
+type TimeEditProps = {
+  value: string;
+  onChange: (value: string) => void;
+  onChangeEnd: () => void;
+  inputFormat: string;
+};
+
+export const TimeEdit = (props: TimeEditProps) => {
+  const pickerRef = useRef<any>();
+  const [panelOpen, setPanelOpen] = useState(true);
+  let value = dayjs(props.value, TIME_FORMAT);
+  if (!value.isValid()) {
+    value = dayjs("00:00:00", TIME_FORMAT);
+  }
+
+  const [tempValue, setTempValue] = useState<dayjs.Dayjs | null>(value);
+
+  useEffect(() => {
+    const value = props.value ? dayjs(props.value, TIME_FORMAT) : null;
+    setTempValue(value);
+  }, [props.value]);
+
+  return (
+    <Wrapper
+      onKeyDown={(e) => {
+        if (e.key === "Enter" && !panelOpen) {
+          props.onChangeEnd();
+        }
+      }}
+      onMouseDown={(e) => {
+        e.stopPropagation();
+        e.preventDefault();
+      }}
+    >
+      <TimePickerStyled
+        ref={pickerRef}
+        $open={panelOpen}
+        format={props.inputFormat}
+        allowClear={true}
+        autoFocus
+        value={tempValue}
+        defaultOpen={true}
+        onOpenChange={(open) => setPanelOpen(open)}
+        onChange={(value, timeString) => {
+          props.onChange(timeString as string);
+        }}
+        onBlur={() => props.onChangeEnd()}
+      />
+    </Wrapper>
+  );
+};
 
 export const TimeComp = (function () {
   return new ColumnTypeCompBuilder(
@@ -35,35 +118,16 @@ export const TimeComp = (function () {
     (props, dispatch) => {
       inputFormat = props.inputFormat;
       const value = props.changeValue ?? getBaseValue(props, dispatch);
-
-      // Convert value to a number if it's a valid timestamp
-      const timestamp = Number(value);
-      const formattedValue = !isNaN(timestamp)
-        ? formatTimestamp(timestamp)
-        : timestampToHumanReadable(timestamp) ?? value;
-
-      return (
-        <>
-          {hasIcon(props.prefixIcon) && <span>{props.prefixIcon}</span>}
-          <span>{formattedValue}</span>
-          {hasIcon(props.suffixIcon) && <span>{props.suffixIcon}</span>}
-        </>
-      );
-    },
-    (nodeValue) => {
-      const timestamp = Number(nodeValue.text.value);
-      return !isNaN(timestamp)
-        ? timestampToHumanReadable(timestamp)
-        : nodeValue.text.value;
+      return formatTime(value, props.format);
     },
+    (nodeValue) => formatTime(nodeValue.text.value, nodeValue.format.value),
     getBaseValue
   )
     .setEditViewFn((props) => (
-      <DateEdit
+      <TimeEdit
         value={props.value}
         onChange={props.onChange}
         onChangeEnd={props.onChangeEnd}
-        showTime={true} // Ensures only time is shown
         inputFormat={inputFormat}
       />
     ))
@@ -73,12 +137,6 @@ export const TimeComp = (function () {
           label: trans("table.columnValue"),
           tooltip: ColumnValueTooltip,
         })}
-        {children.prefixIcon.propertyView({
-          label: trans("button.prefixIcon"),
-        })}
-        {children.suffixIcon.propertyView({
-          label: trans("button.suffixIcon"),
-        })}
         {formatPropertyView({ children, placeholder: TIME_FORMAT })}
       </>
     ))

From ce21056a5f525afc615363bce0afbd4a3c30533e Mon Sep 17 00:00:00 2001
From: Faran Javed <faran1997@outlook.com>
Date: Mon, 3 Mar 2025 19:32:52 +0500
Subject: [PATCH 5/5] [Fix]: Add Prefix/Suffix icons in Time-Only Column Type
 Table Component (#1549)

---
 .../column/columnTypeComps/columnTimeComp.tsx | 24 ++++++++++++++++++-
 1 file changed, 23 insertions(+), 1 deletion(-)

diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnTimeComp.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnTimeComp.tsx
index d07fba00a..b4ad2d73d 100644
--- a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnTimeComp.tsx
+++ b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnTimeComp.tsx
@@ -12,6 +12,9 @@ import dayjs from "dayjs";
 import { useEffect, useRef, useState } from "react";
 import styled from "styled-components";
 import { TIME_FORMAT } from "util/dateTimeUtils";
+import { hasIcon } from "comps/utils";
+import { IconControl } from "comps/controls/iconControl";
+
 
 const TimePickerStyled = styled(TimePicker)<{ $open: boolean }>`
   width: 100%;
@@ -52,6 +55,8 @@ export function formatTime(time: string, format: string) {
 
 const childrenMap = {
   text: StringControl,
+  prefixIcon: IconControl,
+  suffixIcon: IconControl,
   format: withDefault(StringControl, TIME_FORMAT),
   inputFormat: withDefault(StringControl, TIME_FORMAT),
 };
@@ -118,7 +123,18 @@ export const TimeComp = (function () {
     (props, dispatch) => {
       inputFormat = props.inputFormat;
       const value = props.changeValue ?? getBaseValue(props, dispatch);
-      return formatTime(value, props.format);
+      return(
+        <>
+          {hasIcon(props.prefixIcon) && (
+            <span>{props.prefixIcon}</span>
+          )}
+          <span>{value}</span>
+          {hasIcon(props.suffixIcon) && (
+            <span>{props.suffixIcon}</span>
+          )}
+        </>
+      );
+      
     },
     (nodeValue) => formatTime(nodeValue.text.value, nodeValue.format.value),
     getBaseValue
@@ -137,6 +153,12 @@ export const TimeComp = (function () {
           label: trans("table.columnValue"),
           tooltip: ColumnValueTooltip,
         })}
+         {children.prefixIcon.propertyView({
+            label: trans("button.prefixIcon"),
+          })}
+          {children.suffixIcon.propertyView({
+            label: trans("button.suffixIcon"),
+          })}
         {formatPropertyView({ children, placeholder: TIME_FORMAT })}
       </>
     ))