Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 34 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ jobs:
outputs:
i18n_files: ${{ steps.changed.outputs.i18n_files }}
has_i18n_files: ${{ steps.changed.outputs.has_i18n_files }}
format_files: ${{ steps.changed.outputs.format_files }}
has_format_files: ${{ steps.changed.outputs.has_format_files }}
steps:
- uses: actions/checkout@v4
with:
Expand All @@ -35,6 +37,38 @@ jobs:
echo "i18n_files=" >> $GITHUB_OUTPUT
fi

FORMAT_FILES=$(echo "$FILES" | grep -E '\.(vue|js|jsx|cjs|mjs|ts|tsx|cts|mts|json|json5|css|scss|less|html|md|mdx|yaml|yml)$' || true)
if [ -n "$FORMAT_FILES" ]; then
echo "has_format_files=true" >> $GITHUB_OUTPUT
echo "format_files=$(echo "$FORMAT_FILES" | tr '\n' ' ')" >> $GITHUB_OUTPUT
else
echo "has_format_files=false" >> $GITHUB_OUTPUT
echo "format_files=" >> $GITHUB_OUTPUT
fi

check-format:
name: Check formatting
runs-on: ubuntu-latest
needs: changed-files
if: needs.changed-files.outputs.has_format_files == 'true'
steps:
- uses: actions/checkout@v4

- uses: pnpm/action-setup@v4
with:
version: 10.32.1

- uses: actions/setup-node@v4
with:
node-version: 20
cache: pnpm

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Check formatting
run: pnpm format:check -- ${{ needs.changed-files.outputs.format_files }}

check-i18n:
name: Check i18n
runs-on: ubuntu-latest
Expand All @@ -45,4 +79,3 @@ jobs:

- name: Check for hardcoded Chinese text
run: node scripts/check-i18n.js ${{ needs.changed-files.outputs.i18n_files }}

1 change: 1 addition & 0 deletions .lintstagedrc.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export default {
'*.{vue,js,ts,tsx,jsx}': (filenames) => {
const files = filenames.map((f) => `'${f}'`).join(' ')
return [
`prettier --write ${files}`,
`bash -c "eslint --fix --no-warn-ignored --quiet ${files} || true"`,
`node scripts/check-i18n.js ${files}`,
]
Expand Down
10 changes: 8 additions & 2 deletions apps/daas/src/i18n/langs/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -890,8 +890,7 @@ export default {
setting_IdP_Initiated_Enabled: 'Allow IdP-Initiated SSO',
setting_JIT_Provisioning_Enabled: 'Enable JIT Provisioning',
setting_Login_Redirect_URL: 'Post-Login Redirect URL',
setting_Saml_Login_Enable_doc:
'Enable SAML 2.0 single sign-on login',
setting_Saml_Login_Enable_doc: 'Enable SAML 2.0 single sign-on login',
setting_Saml_Sp_Entity_Id_doc:
'Service Provider unique identifier. Recommended to use the ACS base URL, e.g. https://tapdata.example.com/api/sso/saml',
setting_Saml_Sp_Acs_Url_doc:
Expand Down Expand Up @@ -935,6 +934,13 @@ export default {
setting_Saml_Login_Redirect_Url_doc:
'Post-login redirect URL after a successful SSO login',
setting_saml_generate_keypair: 'Generate Key Pair',
setting_saml_test_config: 'Test Configuration',
setting_saml_static_check: 'Static Configuration Check',
setting_saml_test_success: 'SAML configuration test passed',
setting_saml_test_failed:
'SAML configuration test failed. See the details below.',
setting_saml_test_no_result:
'No SAML test result was returned. Please try again.',
setting_saml_export_sp_metadata: 'Export SP Metadata',
setting_saml_import_idp_metadata: 'Import IdP Metadata',
setting_saml_import_idp_metadata_label: 'Upload the IdP metadata XML file',
Expand Down
17 changes: 13 additions & 4 deletions apps/daas/src/i18n/langs/zh-CN.js
Original file line number Diff line number Diff line change
Expand Up @@ -763,7 +763,8 @@ export default {
setting_Switch_to_batch_insert_mode_interval__s__in_cdc_:
'切换到cdc中的批量插入模式间隔。',
setting_share_cdc: '共享增量',
setting_global_share_cdc_enable_doc: '默认开启时,使用外存列表中指定的默认外存,并且作为默认设置应用于后续新建的连接和任务。(开启后才能在数据追溯中查询变更日志)',
setting_global_share_cdc_enable_doc:
'默认开启时,使用外存列表中指定的默认外存,并且作为默认设置应用于后续新建的连接和任务。(开启后才能在数据追溯中查询变更日志)',
setting_global_share_cdc_enable: '默认全局开启共享增量',
setting_share_cdc_persistence_mode: '共享增量存储模式',
setting_share_cdc_persistence_memory_size: '共享增量内存缓存行数',
Expand All @@ -781,7 +782,8 @@ export default {
setting_share_cdc_persistence_rocksdb_path_doc:
'该项配置只有模式选择RocksDB时生效,RocksDB存储的本地路径',
setting_task_start_transform_wait_seconds: '任务启动推演等待时长(秒)',
setting_task_start_transform_wait_seconds_doc: '任务点击启动后会进行推演或试运行,当超出设置的等待时长后,此次启动会失败,需要再次点击启动,或者调大推演等待时长即可,默认等待时长为60s',
setting_task_start_transform_wait_seconds_doc:
'任务点击启动后会进行推演或试运行,当超出设置的等待时长后,此次启动会失败,需要再次点击启动,或者调大推演等待时长即可,默认等待时长为60s',
setting_task_log_file_save_time: '任务日志留存时长(天)',
setting_task_log_file_save_size: '任务日志留存大小(MB)',
setting_task_log_file_save_count: '任务日志保留份数',
Expand All @@ -795,7 +797,8 @@ export default {
setting_Login_Brief_Tips: '登录简要提示',
setting_Login_Brief_Tips_doc: '开启后,登录提示将简化',
setting_Access_Token_Idle_Timeout_Minutes: '会话空闲超时时间(单位:分钟)',
setting_Access_Token_Idle_Timeout_Minutes_doc: '当会话不活跃时间超过设置的值时,会话失效需重新登录',
setting_Access_Token_Idle_Timeout_Minutes_doc:
'当会话不活跃时间超过设置的值时,会话失效需重新登录',
setting_LDAP: 'LDAP登录设置',
setting_Ldap_Login_Enable: '使用LDAP登录',
setting_Ldap_Server_Host: 'LDAP服务器地址',
Expand Down Expand Up @@ -847,7 +850,8 @@ export default {
'服务提供方私钥(静态加密存储,只写),与 SP 证书通过「生成密钥对」成对生成',
setting_Saml_Sp_Certificate_doc:
'SP 证书(公钥,PEM),会被打包进导出的 SP 元数据。请通过「生成密钥对」生成',
setting_Saml_Idp_Entity_Id_doc: '身份提供方(IdP)实体 ID,由「导入 IdP 元数据」自动填充',
setting_Saml_Idp_Entity_Id_doc:
'身份提供方(IdP)实体 ID,由「导入 IdP 元数据」自动填充',
setting_Saml_Idp_Sso_Url_doc:
'身份提供方 SSO(登录)地址。ADFS 示例:https://adfs.example.com/adfs/ls/',
setting_Saml_Idp_Slo_Url_doc:
Expand Down Expand Up @@ -878,6 +882,11 @@ export default {
'即时(JIT)预配:首次 SSO 登录时自动创建用户(默认关闭)',
setting_Saml_Login_Redirect_Url_doc: 'SSO 登录成功后的跳转地址',
setting_saml_generate_keypair: '生成密钥对',
setting_saml_test_config: '测试配置',
setting_saml_static_check: '配置静态检查',
setting_saml_test_success: 'SAML 配置测试通过',
setting_saml_test_failed: 'SAML 配置测试失败,请查看详细提示',
setting_saml_test_no_result: '未获取到 SAML 测试结果,请稍后重试',
setting_saml_export_sp_metadata: '导出 SP 元数据',
setting_saml_import_idp_metadata: '导入 IdP 元数据',
setting_saml_import_idp_metadata_label: '上传 IdP 元数据 XML 文件',
Expand Down
17 changes: 13 additions & 4 deletions apps/daas/src/i18n/langs/zh-TW.js
Original file line number Diff line number Diff line change
Expand Up @@ -761,7 +761,8 @@ export default {
'切換到cdc中的批量插入模式間隔。 ',
setting_share_cdc: '共享增量',
setting_global_share_cdc_enable: '默認全域開啟共亯增量',
setting_global_share_cdc_enable_doc: '默認開啟時,使用外存清單中指定的默認外存,並且作為默認設置應用於後續新建的連接和任務。(開啟後才能在數據追溯中査詢變更日誌)',
setting_global_share_cdc_enable_doc:
'默認開啟時,使用外存清單中指定的默認外存,並且作為默認設置應用於後續新建的連接和任務。(開啟後才能在數據追溯中査詢變更日誌)',
setting_share_cdc_persistence_mode: '共享增量存儲模式',
setting_share_cdc_persistence_memory_size: '共享增量內存緩存行數',
setting_share_cdc_persistence_memory_size_doc:
Expand All @@ -778,7 +779,8 @@ export default {
setting_share_cdc_persistence_rocksdb_path_doc:
'該項配置只有模式選擇RocksDB時生效,RocksDB存儲的本地路徑',
setting_task_start_transform_wait_seconds: '任務啓動推演等待時長(秒)',
setting_task_start_transform_wait_seconds_doc: '任務點擊啓動後會進行推演或試運行,當超出設置的等待時長後,此次啓動會失敗,需要再次點擊啓動,或者調大推演等待時長即可,默認等待時長爲60s',
setting_task_start_transform_wait_seconds_doc:
'任務點擊啓動後會進行推演或試運行,當超出設置的等待時長後,此次啓動會失敗,需要再次點擊啓動,或者調大推演等待時長即可,默認等待時長爲60s',
setting_task_log_file_save_time: '任務日誌留存時長(天)',
setting_task_log_file_save_size: '任務日誌留存大小(MB)',
setting_task_log_file_save_count: '任務日誌留存份數',
Expand All @@ -792,7 +794,8 @@ export default {
setting_Login_Brief_Tips: '登錄簡要提示',
setting_Login_Brief_Tips_doc: '開啟後,登錄提示將簡化',
setting_Access_Token_Idle_Timeout_Minutes: '會話空閑超時時間(單位:分鍾)',
setting_Access_Token_Idle_Timeout_Minutes_doc: '當會話不活躍時間超過設置的值時,會話失效需重新登錄',
setting_Access_Token_Idle_Timeout_Minutes_doc:
'當會話不活躍時間超過設置的值時,會話失效需重新登錄',
setting_LDAP: 'LDAP登入設置',
setting_Ldap_Login_Enable: '使用LDAP登入',
setting_Ldap_Server_Host: 'LDAP伺服器地址',
Expand Down Expand Up @@ -843,7 +846,8 @@ export default {
'服務提供方私鑰(靜態加密存儲,只寫),與 SP 憑證透過「產生金鑰對」成對產生',
setting_Saml_Sp_Certificate_doc:
'SP 憑證(公鑰,PEM),會被打包進匯出的 SP 中繼資料。請透過「產生金鑰對」產生',
setting_Saml_Idp_Entity_Id_doc: '身份提供方(IdP)實體 ID,由「匯入 IdP 中繼資料」自動填充',
setting_Saml_Idp_Entity_Id_doc:
'身份提供方(IdP)實體 ID,由「匯入 IdP 中繼資料」自動填充',
setting_Saml_Idp_Sso_Url_doc:
'身份提供方 SSO(登入)地址。ADFS 範例:https://adfs.example.com/adfs/ls/',
setting_Saml_Idp_Slo_Url_doc:
Expand Down Expand Up @@ -874,6 +878,11 @@ export default {
'即時(JIT)佈建:首次 SSO 登入時自動創建用戶(預設關閉)',
setting_Saml_Login_Redirect_Url_doc: 'SSO 登入成功後的跳轉地址',
setting_saml_generate_keypair: '產生金鑰對',
setting_saml_test_config: '測試設定',
setting_saml_static_check: '設定靜態檢查',
setting_saml_test_success: 'SAML 設定測試通過',
setting_saml_test_failed: 'SAML 設定測試失敗,請查看詳細提示',
setting_saml_test_no_result: '未取得 SAML 測試結果,請稍後重試',
setting_saml_export_sp_metadata: '匯出 SP 中繼資料',
setting_saml_import_idp_metadata: '匯入 IdP 中繼資料',
setting_saml_import_idp_metadata_label: '上傳 IdP 中繼資料 XML 檔案',
Expand Down
15 changes: 14 additions & 1 deletion apps/daas/src/router/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,22 @@ router.beforeEach(async (to, from, next) => {
'registyResult',
].includes(to.name as string)
) {
next()
if (to.name === 'login' && to.query?.sso === '1') {
sessionStorage.setItem('samlManualLogin', '1')
next({ name: 'login' })
} else {
next()
}
} else {
sessionStorage.setItem('lastLocationHref', location.href)
const ssoFromRoute = to.query?.sso === '1'
const ssoFromUrl =
new URLSearchParams(window.location.search).get('sso') === '1'
if (ssoFromRoute || ssoFromUrl) {
// Keep the control flag out of the visible login URL. The login page
// consumes this one-time flag and stays available for manual SSO.
sessionStorage.setItem('samlManualLogin', '1')
}
next('/login')
}
})
Expand Down
57 changes: 51 additions & 6 deletions apps/daas/src/views/login/Login.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
<script>
import { fetchSettings } from '@tap/api/core/settings'
import {
checkSamlLoginEnable,
getSamlLoginUrl,
} from '@tap/api/src/core/sso'
import { checkSamlLoginEnable, getSamlLoginUrl } from '@tap/api/src/core/sso'
import { fetchTimestamp } from '@tap/api/src/core/timestamp'
import {
checkLdapLoginEnable,
Expand Down Expand Up @@ -33,12 +30,13 @@ export default {
errorMessage: '',
adEnable: false,
samlEnable: false,
samlChecking: true,
samlRedirecting: false,
}
},
created() {
useDark()
this.loadAdEnable()
this.loadSamlEnable()
if (this.$route.query) {
this.form.email = this.$route.query.email
const ssoError = this.$route.query.sso_error
Expand All @@ -47,6 +45,12 @@ export default {
}
}
},
mounted() {
// Wait until the login route has finished mounting before starting the
// browser redirect. This keeps the automatic flow aligned with the
// existing button flow and avoids navigating during router resolution.
this.loadSamlEnable()
},
methods: {
getSsoErrorMessage(code) {
const messages = {
Expand All @@ -64,10 +68,38 @@ export default {
async loadSamlEnable() {
try {
this.samlEnable = await checkSamlLoginEnable()
if (this.samlEnable && this.shouldRedirectToSaml()) {
this.samlRedirecting = true
this.loginWithSaml()
return
}
} catch {
this.samlEnable = false
} finally {
if (!this.samlRedirecting) {
this.samlChecking = false
}
}
},
shouldRedirectToSaml() {
const routeQuery = this.$route.query || {}
const ssoError = routeQuery.sso_error

// sso=1 is used to bring an admin to the login page. It must not start
// an IdP redirect automatically; the SSO button remains available there.
if (sessionStorage.getItem('samlManualLogin') === '1') {
sessionStorage.removeItem('samlManualLogin')
return false
}

// Keep the login page visible after an SSO failure so the user can read
// the error and use the original password login flow if needed.
if (ssoError) {
return false
}

return true
},
loginWithSaml() {
// Full browser navigation so the IdP redirect chain runs in the tab.
window.location.href = getSamlLoginUrl()
Expand Down Expand Up @@ -160,7 +192,15 @@ export default {
<template>
<LoginPage>
<template #main>
<section class="page-sign-in">
<section
v-if="samlChecking || samlRedirecting"
class="page-sign-in saml-auto-login"
>
<div class="saml-auto-login-message">
{{ $t('app_signIn_ssoProcessing') }}
</div>
</section>
<section v-else class="page-sign-in">
<div class="sign-in-panel">
<div class="title">
{{ $t('app_signIn_signIn') }}
Expand Down Expand Up @@ -325,4 +365,9 @@ export default {
}
}
}

.saml-auto-login-message {
color: var(--text-light);
font-size: 16px;
}
</style>
Loading
Loading