diff --git a/client/packages/lowcoder-sdk-webpack-bundle/webpack.config.cjs b/client/packages/lowcoder-sdk-webpack-bundle/webpack.config.cjs
index 02efbc1572..a5be4cc8b3 100644
--- a/client/packages/lowcoder-sdk-webpack-bundle/webpack.config.cjs
+++ b/client/packages/lowcoder-sdk-webpack-bundle/webpack.config.cjs
@@ -14,7 +14,8 @@ buildVars.forEach(({ name, defaultValue }) => {
   define[name] = JSON.stringify(process.env[name] || defaultValue);
 });
 
-const apiBaseUrl = "http://localhost:8000";
+//const apiBaseUrl = "http://localhost:8000";
+const apiBaseUrl = "http://localhost:8080";
 
 module.exports = {
   mode: 'production',
diff --git a/client/packages/lowcoder-sdk/index.tsx b/client/packages/lowcoder-sdk/index.tsx
index 54fc1bb97f..7c700089e7 100644
--- a/client/packages/lowcoder-sdk/index.tsx
+++ b/client/packages/lowcoder-sdk/index.tsx
@@ -5,7 +5,8 @@ import { AppViewInstance, bootstrapAppAt, LowcoderAppView } from "./src/index";
 
 const url = new URL(location.href);
 const appId = url.searchParams.get("appId");
-const baseUrl = url.searchParams.get("baseUrl") || "http://localhost:8000";
+//const baseUrl = url.searchParams.get("baseUrl") || "http://localhost:8000";
+const baseUrl = url.searchParams.get("baseUrl") || "http://localhost:8080";
 
 function ReactDemoApp() {
   const ref = useRef<AppViewInstance | null>(null);
diff --git a/client/packages/lowcoder-sdk/vite.config.mts b/client/packages/lowcoder-sdk/vite.config.mts
index 3cd7b5c454..8169957ebd 100644
--- a/client/packages/lowcoder-sdk/vite.config.mts
+++ b/client/packages/lowcoder-sdk/vite.config.mts
@@ -18,7 +18,8 @@ buildVars.forEach(({ name, defaultValue }) => {
   define[name] = JSON.stringify(process.env[name] || defaultValue);
 });
 
-const apiBaseUrl = "http://localhost:8000";
+//const apiBaseUrl = "http://localhost:8000";
+const apiBaseUrl = "http://localhost:8080";
 
 export const viteConfig: UserConfig = {
   define: {
diff --git a/client/packages/lowcoder/src/api/configApi.ts b/client/packages/lowcoder/src/api/configApi.ts
index fc756069ed..bb36df0ef3 100644
--- a/client/packages/lowcoder/src/api/configApi.ts
+++ b/client/packages/lowcoder/src/api/configApi.ts
@@ -15,6 +15,7 @@ class ConfigApi extends Api {
     if(orgId?.length) {
       authConfigURL += `?orgId=${orgId}`;
     }
+    console.log('authConfigURL:', authConfigURL);
     return Api.get(authConfigURL);
   }
 
diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnLinkComp.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnLinkComp.tsx
index e93b3082a6..adda461edb 100644
--- a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnLinkComp.tsx
+++ b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnLinkComp.tsx
@@ -39,7 +39,8 @@ const StyledLink = styled.a<{ $disabled: boolean }>`
 `;
 
 // Memoized link component
-export const ColumnLink = React.memo(({ disabled, label, onClick }: { disabled: boolean; label: string; onClick: (eventName: string) => void }) => {
+// export const ColumnLink = React.memo(({ disabled, label, onClick }: { disabled: boolean; label: string; onClick: (eventName: string) => void }) => {
+export const ColumnLink = React.memo(({ disabled, label, onClick }: { disabled: boolean; label: React.ReactNode; onClick: (eventName: string) => void }) => {
   const handleClickEvent = useCompClickEventHandler({onEvent: onClick})
   const handleClick = useCallback(() => {
     if (!disabled) {
diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnLinksComp.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnLinksComp.tsx
index 5a7fae3d3e..6f0a2f033f 100644
--- a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnLinksComp.tsx
+++ b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnLinksComp.tsx
@@ -13,6 +13,7 @@ import { clickEvent, eventHandlerControl, doubleClickEvent } from "comps/control
 import { useCompClickEventHandler } from "@lowcoder-ee/comps/utils/useCompClickEventHandler";
 import { migrateOldData } from "@lowcoder-ee/comps/generators/simpleGenerators";
 import { fixOldActionData } from "comps/comps/tableComp/column/simpleColumnTypeComps";
+import { IconControl } from "comps/controls/iconControl"; // thêm thư viện icon
 
 const MenuLinkWrapper = styled.div`
   > a {
@@ -48,7 +49,13 @@ const MenuItem = React.memo(({ option, index }: { option: any; index: number })
     <MenuLinkWrapper>
       <ColumnLink
         disabled={option.disabled}
-        label={option.label}
+        label={
+          <span style={{ color: option.color || undefined }}>
+            {option.prefixIcon && <span style={{marginRight: 4}}>{option.prefixIcon}</span>}
+            {option.label}
+            {option.suffixIcon && <span style={{marginLeft: 4}}>{option.suffixIcon}</span>}
+          </span>
+        }
         onClick={option.onClick}
       />
     </MenuLinkWrapper>
@@ -60,6 +67,9 @@ MenuItem.displayName = 'MenuItem';
 const OptionItemTmp = new MultiCompBuilder(
   {
     label: StringControl,
+    prefixIcon: IconControl, // thêm prefix icon
+    suffixIcon: IconControl, // thêm suffix icon
+    color: StringControl, // thêm trường chỉnh màu chữ
     onClick: eventHandlerControl(LinkEventOptions),
     hidden: BoolCodeControl,
     disabled: BoolCodeControl,
@@ -72,6 +82,9 @@ const OptionItemTmp = new MultiCompBuilder(
     return (
       <>
         {children.label.propertyView({ label: trans("label") })}
+        {children.prefixIcon.propertyView({ label: trans("button.prefixIcon") })} 
+        {children.suffixIcon.propertyView({ label: trans("button.suffixIcon") })} 
+        {children.color.propertyView({ label: trans("button.textColor") })}
         {hiddenPropertyView(children)}
         {disabledPropertyView(children)}
         {children.onClick.propertyView()}
@@ -79,7 +92,7 @@ const OptionItemTmp = new MultiCompBuilder(
     );
   })
   .build();
-
+// hàm chuyển đổi dữ liệu cấu hình cũ đã có(fixOldActionData) tương thích với cấu hình OptionItem mới(OptionItemTmp) và lưu thành OptionItem
 const OptionItem = migrateOldData(OptionItemTmp, fixOldActionData);
 
 // Memoized menu component
diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/column/simpleColumnTypeComps.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/column/simpleColumnTypeComps.tsx
index 8ec51c6a1a..39c15bdd91 100644
--- a/client/packages/lowcoder/src/comps/comps/tableComp/column/simpleColumnTypeComps.tsx
+++ b/client/packages/lowcoder/src/comps/comps/tableComp/column/simpleColumnTypeComps.tsx
@@ -18,15 +18,32 @@ import { migrateOldData } from "@lowcoder-ee/comps/generators/simpleGenerators";
 import { useCompClickEventHandler } from "@lowcoder-ee/comps/utils/useCompClickEventHandler";
 
 export const fixOldActionData = (oldData: any) => {
-  if (!oldData) return oldData;
+  // check if oldData is null
+  if (!oldData) { 
+    return oldData; 
+  }
   if (Boolean(oldData.onClick)) {
+    // Nếu là mảng, giữ nguyên
+    if (Array.isArray(oldData.onClick)) {
+      return oldData;
+    }
+    // Nếu là object, chuyển thành mảng 1 phần tử
     return {
       ...oldData,
       onClick: [{
         name: "click",
-        handler: oldData.onClick,
+        handler: oldData.onClick.handler || oldData.onClick[0]?.handler,
       }],
     };
+    // tạm che để fix lỗi hiển thị 1 event cho operation
+    // return {
+    //   ...oldData,
+    //   onClick: [{
+    //     name: "click",
+    //     // handler: oldData.onClick,
+    //     handler: oldData.onClick[0].handler, // fix lỗi không render được operation - date: 02/07/2025
+    //   }],
+    // };
   }
   return oldData;
 }
diff --git a/client/packages/lowcoder/src/constants/configConstants.ts b/client/packages/lowcoder/src/constants/configConstants.ts
index 1a0077009a..a195fcff5d 100644
--- a/client/packages/lowcoder/src/constants/configConstants.ts
+++ b/client/packages/lowcoder/src/constants/configConstants.ts
@@ -71,6 +71,7 @@ export type SystemConfig = {
   authConfigs: ThirdPartyConfigType[];
 } & ConfigBaseInfo;
 
+// xu ly du lieu cau hinh tra ve tu server
 export const transToSystemConfig = (responseData: ConfigResponseData): SystemConfig => {
   const thirdPartyAuthConfigs: ThirdPartyConfigType[] = [];
   responseData.authConfigs?.forEach((authConfig) => {
@@ -106,6 +107,18 @@ export const transToSystemConfig = (responseData: ConfigResponseData): SystemCon
     (c) => c.source === UserConnectionSource.email
   ) as FormConfig | undefined;
 
+  const tmp = {
+    ...responseData,
+    form: {
+      enableRegister: !!emailConfig?.enableRegister,
+      enableLogin: !!emailConfig?.enable,
+      id: emailConfig?.id,
+      type: "EMAIL",
+    },
+    authConfigs: thirdPartyAuthConfigs,
+  };
+  console.log('AuthContext login:', tmp);
+
   return {
     ...responseData,
     form: {
diff --git a/client/packages/lowcoder/src/i18n/locales/en.ts b/client/packages/lowcoder/src/i18n/locales/en.ts
index de24d5b64a..c89f73b314 100644
--- a/client/packages/lowcoder/src/i18n/locales/en.ts
+++ b/client/packages/lowcoder/src/i18n/locales/en.ts
@@ -1938,6 +1938,7 @@ export const en = {
     "prefixIcon": "Prefix Icon",
     "prefixText": "Prefix Text",
     "suffixIcon": "Suffix Icon",
+    "textColor": "Text Color",
     "icon": "Icon",
     "iconSize": "Icon Size",
     "button": "Form Button",
diff --git a/client/packages/lowcoder/src/pages/userAuth/formLoginAdmin.tsx b/client/packages/lowcoder/src/pages/userAuth/formLoginAdmin.tsx
index 16cd72ad39..4305801dae 100644
--- a/client/packages/lowcoder/src/pages/userAuth/formLoginAdmin.tsx
+++ b/client/packages/lowcoder/src/pages/userAuth/formLoginAdmin.tsx
@@ -39,14 +39,15 @@ export default function FormLogin(props: FormLoginProps) {
   }
 
   const { onSubmit, loading } = useAuthSubmit(
-    () =>
-      UserApi.formLogin({
+    () => {
+      return UserApi.formLogin({
         register: false,
         loginId: account,
         password: password,
         source: UserConnectionSource.email,
         orgId: props.organizationId,
-      }),
+      });
+    },
     false,
     null,
     afterLoginSuccess,
diff --git a/client/packages/lowcoder/src/pages/userAuth/formLoginSteps.tsx b/client/packages/lowcoder/src/pages/userAuth/formLoginSteps.tsx
index 9b88b019cf..f24ce69ec9 100644
--- a/client/packages/lowcoder/src/pages/userAuth/formLoginSteps.tsx
+++ b/client/packages/lowcoder/src/pages/userAuth/formLoginSteps.tsx
@@ -124,10 +124,13 @@ export default function FormLoginSteps(props: FormLoginProps) {
   const [currentPage, setCurrentPage] = useState(1);
   const [pageSize, setPageSize] = useState(10);
 
+  // Tạm che để cho phép đăng nhập với email
   const isEmailLoginEnabled = useMemo(() => {
     return isFormLoginEnabled && signinEnabled;
   }, [isFormLoginEnabled, signinEnabled]);
   
+  // const isEmailLoginEnabled = true;
+
   const isEnterpriseMode = useMemo(() => {
     return serverSettings?.LOWCODER_WORKSPACE_MODE === "ENTERPRISE" || serverSettings?.LOWCODER_WORKSPACE_MODE === "SINGLEWORKSPACE";
   }, [serverSettings]);
@@ -164,8 +167,8 @@ export default function FormLoginSteps(props: FormLoginProps) {
   }
 
   const { onSubmit, loading } = useAuthSubmit(
-    () =>
-      UserApi.formLogin({
+    () => {
+      return UserApi.formLogin({
         register: false,
         loginId: account,
         password: password,
@@ -173,7 +176,8 @@ export default function FormLoginSteps(props: FormLoginProps) {
         source: UserConnectionSource.email,
         orgId: organizationId,
         authId,
-      }),
+      });
+    },
     false,
     redirectUrl,
     afterLoginSuccess,
@@ -260,7 +264,6 @@ export default function FormLoginSteps(props: FormLoginProps) {
       </Spin>
     );
   }
-
   if(currentStep === CurrentStepEnum.EMAIL) {
     return (
       <>
diff --git a/client/packages/lowcoder/src/pages/userAuth/login.tsx b/client/packages/lowcoder/src/pages/userAuth/login.tsx
index acc36e234e..0499e5f13b 100644
--- a/client/packages/lowcoder/src/pages/userAuth/login.tsx
+++ b/client/packages/lowcoder/src/pages/userAuth/login.tsx
@@ -61,7 +61,7 @@ const ThirdAuthWrapper = styled.div`
   }
 `;
 
-// this is used to bind multiple third party logins to an sngle account
+// this is used to bind multiple third party logins to an single account
 const thirdPartyLoginLabel = (name: string) => trans("userAuth.signInLabel", { name: name });
 
 export const ThirdPartyBindCard = () => {
@@ -92,9 +92,13 @@ function Login() {
   const queryParams = new URLSearchParams(location.search);
   const { orgId } = useParams<{orgId?: string}>();
 
+  const tmp1 = useContext(AuthContext);
+  console.log('AuthContext after login:', tmp1);
+  
   const loginType = systemConfig?.authConfigs.find(
     (config) => config.sourceType === queryParams.get(AuthSearchParams.loginType)
   )?.sourceType;
+  
   let autoJumpSource: string | undefined;
   if (loginType) {
     autoJumpSource = loginType;
diff --git a/client/packages/lowcoder/src/util/pagination/axios.ts b/client/packages/lowcoder/src/util/pagination/axios.ts
index d03bf1800c..dc64183b3d 100644
--- a/client/packages/lowcoder/src/util/pagination/axios.ts
+++ b/client/packages/lowcoder/src/util/pagination/axios.ts
@@ -162,7 +162,9 @@ export const fetchJsDSPaginationByApp = async (request: fetchDataSourcePaginatio
 
 export const fetchOrgPaginationByEmail = async (request: fetchOrgsByEmailRequestType)=> {
     try {
+        console.log('fetchOrgPaginationByEmail:', request);
         const response = await OrgApi.fetchOrgsPaginationByEmail(request);
+        console.log('fetchOrgPaginationByEmail response:', response);
         return {
             success: true,
             data: response.data.data,
diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/serversetting/service/ServerSettingServiceImpl.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/serversetting/service/ServerSettingServiceImpl.java
index 64e1847ab6..8eaae58c5c 100644
--- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/serversetting/service/ServerSettingServiceImpl.java
+++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/serversetting/service/ServerSettingServiceImpl.java
@@ -62,7 +62,7 @@ public void saveEnvironmentVariables() {
         Flux.fromIterable(merged.keySet())
                 .map(key -> {
                     String value = envVariables.getOrDefault(key, "");
-                    if(EXCLUDED_KEYS.contains(key)) {
+                    if (EXCLUDED_KEYS.contains(key)) {
                         value = "stored on the server";
                     }
                     return ServerSetting.builder()
@@ -74,7 +74,6 @@ public void saveEnvironmentVariables() {
                 .subscribe();
     }
 
-
     private Map<String, String> getEnvironmentVariablesDefaults() {
         Map<String, String> defaults = new HashMap<>();
 
diff --git a/server/api-service/lowcoder-server/src/main/resources/application-lowcoder.yaml b/server/api-service/lowcoder-server/src/main/resources/application-lowcoder.yaml
new file mode 100644
index 0000000000..0b323b7b43
--- /dev/null
+++ b/server/api-service/lowcoder-server/src/main/resources/application-lowcoder.yaml
@@ -0,0 +1,135 @@
+auth:
+  api-key:
+    secret: ${LOWCODER_API_KEY_SECRET:5a41b090758b39b226603177ef48d73ae9839dd458ccb7e66f7e7cc028d5a50b}
+  email:
+    enable: ${LOWCODER_EMAIL_AUTH_ENABLED:true}
+    enable-register: ${LOWCODER_EMAIL_SIGNUP_ENABLED:true}
+  workspace-creation: ${LOWCODER_CREATE_WORKSPACE_ON_SIGNUP:true}
+
+spring:
+  data:
+    mongodb:
+      authentication-database: admin
+      auto-index-creation: false
+      uri: ${LOWCODER_MONGODB_URL:mongodb://lowcoder:secret123@localhost:27017/lowcoder?retryWrites=true&loadBalanced=false&connectTimeoutMS=10000&authSource=admin&authMechanism=SCRAM-SHA-256}
+    redis:
+      url: ${LOWCODER_REDIS_URL:redis://localhost:6379}
+  main:
+    allow-bean-definition-overriding: false
+    allow-circular-references: false
+  codec:
+    max-in-memory-size: 20MB
+  webflux:
+    base-path: /
+  mail:
+    host: ${LOWCODER_ADMIN_SMTP_HOST:localhost}
+    port: ${LOWCODER_ADMIN_SMTP_PORT:587}
+    username: ${LOWCODER_ADMIN_SMTP_USERNAME:info@localhost}
+    password: ${LOWCODER_ADMIN_SMTP_PASSWORD:s3cr3t}
+    properties:
+      mail:
+        smtp:
+          auth: ${LOWCODER_ADMIN_SMTP_AUTH:true}
+          ssl:
+            enable: ${LOWCODER_ADMIN_SMTP_SSL_ENABLED:false}
+          starttls:
+            enable: ${LOWCODER_ADMIN_SMTP_STARTTLS_ENABLED:true}
+            required: ${LOWCODER_ADMIN_SMTP_STARTTLS_REQUIRED:true}
+        transport:
+          protocol: smtp
+  mvc:
+    pathmatch:
+      trailing-slash-match: true
+server:
+  compression:
+    enabled: true
+  forward-headers-strategy: NATIVE
+  http2:
+    enabled: true
+  port: 8080
+  shutdown: graceful
+
+default:
+  orgs-per-user: ${LOWCODER_MAX_ORGS_PER_USER:100}
+  org-member-count: ${LOWCODER_MAX_MEMBERS_PER_ORG:1000}
+  org-group-count: ${LOWCODER_MAX_GROUPS_PER_ORG:100}
+  org-app-count: ${LOWCODER_MAX_APPS_PER_ORG:1000}
+  developer-count: ${LOWCODER_MAX_DEVELOPERS:50}
+  api-rate-limit: ${LOWCODER_API_RATE_LIMIT:50}
+  query-timeout: ${LOWCODER_DEFAULT_QUERY_TIMEOUT:10}
+
+common:
+  cookie-name: ${LOWCODER_COOKIE_NAME:LOWCODER_CE_SELFHOST_TOKEN}
+  product: lowcoder
+  domain:
+    default-value: lowcoder.org
+  cloud: false
+  version: 2.7.2
+  apiVersion: 1.2
+  block-hound-enable: false
+  encrypt:
+    password: ${LOWCODER_DB_ENCRYPTION_PASSWORD:lowcoder.org}
+    salt: ${LOWCODER_DB_ENCRYPTION_SALT:lowcoder.org}
+  security:
+    corsAllowedDomainString: ${LOWCODER_CORS_DOMAINS:*}
+  js-executor:
+    host: ${LOWCODER_NODE_SERVICE_URL:http://127.0.0.1:6060}
+    password: ${LOWCODER_NODE_SERVICE_SECRET:}
+    salt: ${LOWCODER_NODE_SERVICE_SECRET_SALT:}
+  max-query-request-size: ${LOWCODER_MAX_REQUEST_SIZE:20m}
+  max-query-response-size: ${LOWCODER_MAX_REQUEST_SIZE:20m}
+  max-upload-size: ${LOWCODER_MAX_REQUEST_SIZE:20m}
+  max-query-timeout: ${LOWCODER_MAX_QUERY_TIMEOUT:120}
+  workspace:
+    mode: ${LOWCODER_WORKSPACE_MODE:SAAS}
+  plugin-dirs:
+    - ${LOWCODER_PLUGINS_DIR:../plugins}
+  super-admin:
+    username: ${LOWCODER_SUPERUSER_USERNAME:admin@localhost}
+    password: ${LOWCODER_SUPERUSER_PASSWORD:secret123}
+  marketplace:
+    private-mode: ${LOWCODER_MARKETPLACE_PRIVATE_MODE:true}
+  lowcoder-public-url: ${LOWCODER_PUBLIC_URL:http://localhost:3000}
+  notifications-email-sender: ${LOWCODER_EMAIL_NOTIFICATIONS_SENDER:info@localhost}
+  cookie:
+    max-age-in-hours: ${LOWCODER_COOKIE_MAX_AGE:24}
+  query:
+    app-snapshot-keep-duration: ${LOWCODER_APP_SNAPSHOT_RETENTIONTIME:30}
+
+material:
+  mongodb-grid-fs:
+    bucket-name: material
+
+springdoc:
+  api-docs:
+    path: /api/docs/openapi.json
+  swagger-ui:
+    path: /api/docs/swagger-ui
+    operations-sorter: method
+  paths-to-exclude: /api/v1/**
+
+management:
+  endpoints:
+    enabled-by-default: false
+    web:
+      base-path: "/api/status"
+      exposure:
+        include: "health,metrics,prometheus"
+  endpoint:
+    health:
+      show-details: never
+      show-components: always
+      enabled: true
+    metrics:
+      enabled: true
+    prometheus:
+      enabled: true
+  health:
+    mail:
+      enabled: false
+    db:
+      enabled: true
+    redis:
+      enabled: true
+    diskspace:
+      enabled: false
\ No newline at end of file
