forked from baron/baron-sso
5b345fcf 기준 병합 code-check 오류 수정
This commit is contained in:
@@ -1,4 +1,7 @@
|
|||||||
{
|
{
|
||||||
"root": true,
|
"root": true,
|
||||||
"extends": ["../common/config/biome.base.json"]
|
"extends": ["../common/config/biome.base.json"],
|
||||||
|
"files": {
|
||||||
|
"includes": [".vite"]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
{
|
{
|
||||||
"root": true,
|
"root": true,
|
||||||
"extends": ["../common/config/biome.base.json"]
|
"extends": ["../common/config/biome.base.json"],
|
||||||
|
"files": {
|
||||||
|
"includes": [".vite"]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ const configuredWorkers = process.env.PLAYWRIGHT_WORKERS
|
|||||||
const skipWebServer =
|
const skipWebServer =
|
||||||
process.env.PLAYWRIGHT_SKIP_WEBSERVER === "1" ||
|
process.env.PLAYWRIGHT_SKIP_WEBSERVER === "1" ||
|
||||||
process.env.PLAYWRIGHT_SKIP_WEBSERVER === "true";
|
process.env.PLAYWRIGHT_SKIP_WEBSERVER === "true";
|
||||||
const baseURL = process.env.PLAYWRIGHT_BASE_URL || "http://127.0.0.1:5174";
|
const baseURL = process.env.PLAYWRIGHT_BASE_URL || "http://127.0.0.1:5176";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read environment variables from file.
|
* Read environment variables from file.
|
||||||
@@ -73,10 +73,9 @@ export default defineConfig({
|
|||||||
webServer: skipWebServer
|
webServer: skipWebServer
|
||||||
? undefined
|
? undefined
|
||||||
: {
|
: {
|
||||||
command: process.env.CI
|
command:
|
||||||
? "VITE_OIDC_AUTHORITY=http://localhost:5000/oidc pnpm build && pnpm exec vite preview --host 127.0.0.1 --strictPort --port 5174"
|
"VITE_OIDC_AUTHORITY=http://localhost:5000/oidc ./node_modules/.bin/vite build && ./node_modules/.bin/vite preview --host 127.0.0.1 --strictPort --port 5176",
|
||||||
: "VITE_OIDC_AUTHORITY=http://localhost:5000/oidc pnpm exec vite --host 127.0.0.1 --strictPort --port 5174",
|
|
||||||
url: baseURL,
|
url: baseURL,
|
||||||
reuseExistingServer: !process.env.CI,
|
reuseExistingServer: false,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
178
devfront/pnpm-lock.yaml
generated
178
devfront/pnpm-lock.yaml
generated
@@ -89,7 +89,7 @@ importers:
|
|||||||
version: 19.2.3(@types/react@19.2.14)
|
version: 19.2.3(@types/react@19.2.14)
|
||||||
'@vitejs/plugin-react':
|
'@vitejs/plugin-react':
|
||||||
specifier: ^6.0.1
|
specifier: ^6.0.1
|
||||||
version: 6.0.1(vite@8.0.13(@types/node@25.7.0)(jiti@1.21.7))
|
version: 6.0.1(vite@8.0.14(@types/node@25.7.0)(jiti@1.21.7))
|
||||||
'@vitest/coverage-v8':
|
'@vitest/coverage-v8':
|
||||||
specifier: 4.1.6
|
specifier: 4.1.6
|
||||||
version: 4.1.6(vitest@4.1.6)
|
version: 4.1.6(vitest@4.1.6)
|
||||||
@@ -112,11 +112,11 @@ importers:
|
|||||||
specifier: ^6.0.3
|
specifier: ^6.0.3
|
||||||
version: 6.0.3
|
version: 6.0.3
|
||||||
vite:
|
vite:
|
||||||
specifier: ^8.0.12
|
specifier: ^8.0.14
|
||||||
version: 8.0.13(@types/node@25.7.0)(jiti@1.21.7)
|
version: 8.0.14(@types/node@25.7.0)(jiti@1.21.7)
|
||||||
vitest:
|
vitest:
|
||||||
specifier: ^4.1.6
|
specifier: ^4.1.6
|
||||||
version: 4.1.6(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(jsdom@28.1.0)(vite@8.0.13(@types/node@25.7.0)(jiti@1.21.7))
|
version: 4.1.6(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(jsdom@28.1.0)(vite@8.0.14(@types/node@25.7.0)(jiti@1.21.7))
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
@@ -323,8 +323,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
|
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
|
|
||||||
'@oxc-project/types@0.130.0':
|
'@oxc-project/types@0.132.0':
|
||||||
resolution: {integrity: sha512-ibD2usx9JRu7f5pu2tMKMI4cpA4NgXJQoYRP4pQ7Pxmn1l6k/53qWtQWZayhYy3X4QZkt90Ot+mJEaeXouio6Q==}
|
resolution: {integrity: sha512-FESMOxil5Se014ui/Eq8fT5uHJo6nIRwH0PfJrZJXs6Gek3ZVFOrpUv3YIZT20m+extU98Hg1Ym72U58rlsxUQ==}
|
||||||
|
|
||||||
'@playwright/test@1.60.0':
|
'@playwright/test@1.60.0':
|
||||||
resolution: {integrity: sha512-O71yZIbAh/PxDMNGns37GHBIfrVkEVyn+AXyIa5dOTfb4/xNvRWV+Vv/NMbNCtODB/pO7vLlF2OTmMVLhmr7Ag==}
|
resolution: {integrity: sha512-O71yZIbAh/PxDMNGns37GHBIfrVkEVyn+AXyIa5dOTfb4/xNvRWV+Vv/NMbNCtODB/pO7vLlF2OTmMVLhmr7Ag==}
|
||||||
@@ -727,97 +727,97 @@ packages:
|
|||||||
'@radix-ui/rect@1.1.1':
|
'@radix-ui/rect@1.1.1':
|
||||||
resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==}
|
resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==}
|
||||||
|
|
||||||
'@rolldown/binding-android-arm64@1.0.1':
|
'@rolldown/binding-android-arm64@1.0.2':
|
||||||
resolution: {integrity: sha512-fJI3I0r3C3Oj/zdBCpaCmBRZYf07xpaq4yCfDDoSFm+beWNzbIl26puW8RraUdugoJw/95zerNOn6jasAhzSmg==}
|
resolution: {integrity: sha512-ZS4D1JPGn/MYQN/SYDWftIE/nVsM8j/AFOYEzAoOE2O3NktQOZru+/vYXGbR/qtdLdIfGCP0lcoJiYVzsEz+iQ==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [android]
|
os: [android]
|
||||||
|
|
||||||
'@rolldown/binding-darwin-arm64@1.0.1':
|
'@rolldown/binding-darwin-arm64@1.0.2':
|
||||||
resolution: {integrity: sha512-cKnAhWEsV7TPcA/5EAteDp6KcJZBQ2G+BqE7zayMMi7kMvwRsbv7WT9aOnn0WNl4SKEIf43vjS31iUPu80nzXg==}
|
resolution: {integrity: sha512-vdFA9+C/rekyGce7WqHs/xoT0ioZEWaOFyZLIV1mEeNFaFDUQrPIo8Vs2GvJ6eetb3rzDUtUBgzto3ExpXJB3w==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [darwin]
|
os: [darwin]
|
||||||
|
|
||||||
'@rolldown/binding-darwin-x64@1.0.1':
|
'@rolldown/binding-darwin-x64@1.0.2':
|
||||||
resolution: {integrity: sha512-YKrVwQjIRBPo+5G/u03wGjbdy4q7pyzCe93DK9VJ7zkVmeg8LJ7GbgsiHWdR4xSoe4CAXRD7Bcjgbtr64bkXNg==}
|
resolution: {integrity: sha512-BewSOwTHazv77DTYiAZXSqqKZ4KP/KonFisDMVU7PImxoWfB2aepnPhd2E4SWz3zDzYgDNbs6jBmTdgNnF02GA==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [darwin]
|
os: [darwin]
|
||||||
|
|
||||||
'@rolldown/binding-freebsd-x64@1.0.1':
|
'@rolldown/binding-freebsd-x64@1.0.2':
|
||||||
resolution: {integrity: sha512-z/oBsREo46SsFqBwYtFe0kpJeBijAT48O/WXLI4suiCLBkr03RTtTJMCzSdDd2znlh8VJizL09XVkQgk8IZonw==}
|
resolution: {integrity: sha512-m41o7M0YWtUdqk61Tb+jnKb2rN++iRdIASlExkUoKfIAH30DOHCB8fVLzSUpbWHHU8esmEioY62PxzexE8MBuA==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [freebsd]
|
os: [freebsd]
|
||||||
|
|
||||||
'@rolldown/binding-linux-arm-gnueabihf@1.0.1':
|
'@rolldown/binding-linux-arm-gnueabihf@1.0.2':
|
||||||
resolution: {integrity: sha512-ik8q7GM11zxvYxFc2PeDcT6TBvhCQMaUxfph/M5l9sKuTs/Sjg3L+Byw0F7w0ZVLBZmx30P+gG0ECzzN+MFcmQ==}
|
resolution: {integrity: sha512-jcojB9H7W/jS29pMKWAK1N+fU99vXodHDTatS3b3y/XSOCiHo0kkA74pL3jJmkoQtYpOCxDvaKs1fo2Ij/1X5w==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@rolldown/binding-linux-arm64-gnu@1.0.1':
|
'@rolldown/binding-linux-arm64-gnu@1.0.2':
|
||||||
resolution: {integrity: sha512-QoSx2EkyrrdZ6kcyE8stqZ62t0Yra8Fs5ia9lOxJrh6TMQJK7gQKmscdTHf7pOXKREKrVwOtJcQG3qVSfc866A==}
|
resolution: {integrity: sha512-1jn6qDU5iiOgFgygDzKUuKP0maTi0/f1+sBLgvij/76C77Nm3ts6ufz9Bjg5q5dduxiUIxtq86JIoBvo1xQ4Ig==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
libc: [glibc]
|
||||||
|
|
||||||
'@rolldown/binding-linux-arm64-musl@1.0.1':
|
'@rolldown/binding-linux-arm64-musl@1.0.2':
|
||||||
resolution: {integrity: sha512-uwNwFpwKeNiZawfAWBgg0VIztPTV3ihhh1vV334h9ivnNLorxnQMU6Fz8wG1Zb4Qh9LC1/MkcyT3YlDXG3Rsgg==}
|
resolution: {integrity: sha512-QVLO/czFMdoMFSqlX3bcswcJNm/23r+qoa/jgtmFc/qEp6/jXmIkDjF/XIo8dPfGaiwy1xfQn8o77L79GeXFgw==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
libc: [musl]
|
||||||
|
|
||||||
'@rolldown/binding-linux-ppc64-gnu@1.0.1':
|
'@rolldown/binding-linux-ppc64-gnu@1.0.2':
|
||||||
resolution: {integrity: sha512-zY1bul7OWr7DFBiJ++wofXvnr8B45ce3QsQUhKrIhXsygAh7bTkwyeM1bi1a2g5C/yC/N8TZyGDEoMfm/l9mpg==}
|
resolution: {integrity: sha512-hgO5Abm0w5UL6FEa2iFnZqo2KlK7TQ5QhV5x09hujBf7t5KzHQ1VmfPuTpqRy/rNlSxua3eWH374xxiVrP+lcA==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
cpu: [ppc64]
|
cpu: [ppc64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
libc: [glibc]
|
||||||
|
|
||||||
'@rolldown/binding-linux-s390x-gnu@1.0.1':
|
'@rolldown/binding-linux-s390x-gnu@1.0.2':
|
||||||
resolution: {integrity: sha512-0frlsT/f4Ft6I7SMESTKnF3cZsdicQn1dCMkF/jT9wDLE+gGoiQfv1nmT9e+s7s/fekvvy6tZM2jHvI2tkbJDQ==}
|
resolution: {integrity: sha512-fy8rXxuYEu602abC8MUNaPjYLIFzReOaEIEMKMUa0rFEUxNpVXhs15KSSQ4qlqSaM7B6rcj9rDZgADh/IGDzLQ==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
cpu: [s390x]
|
cpu: [s390x]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
libc: [glibc]
|
||||||
|
|
||||||
'@rolldown/binding-linux-x64-gnu@1.0.1':
|
'@rolldown/binding-linux-x64-gnu@1.0.2':
|
||||||
resolution: {integrity: sha512-XABVmGp9Tg0WspTVvwduTc4fpqy6JnAUrSQe6OuyqD/03nI7r0O9OWUkMIwFrjKAIqolvqoA4ZrJppgwE0Gxmw==}
|
resolution: {integrity: sha512-0+bOkiQ779+r1WpoHOWHqncvyySci0vKph+myNDYb+im6meJAzHQXay6oEgnkHuUGouM1LKTZwqKpBow6Kj7CQ==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
libc: [glibc]
|
||||||
|
|
||||||
'@rolldown/binding-linux-x64-musl@1.0.1':
|
'@rolldown/binding-linux-x64-musl@1.0.2':
|
||||||
resolution: {integrity: sha512-bV4fzswuzVcKD90o/VM6QqKxnxlDq0g2BISDLNVmxrnhpv1DDbyPhCIjYfvzYLV+MvkKKnQt2Q6AO86SEBULUQ==}
|
resolution: {integrity: sha512-mjSkrzZK5Qsl0a9d1JgILOiuZOSDTVdKENcSXBoqbzSrspLR/4/IRVDo5wd2GgZjNss/viBFJdeq+j7qH2nypw==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
libc: [musl]
|
||||||
|
|
||||||
'@rolldown/binding-openharmony-arm64@1.0.1':
|
'@rolldown/binding-openharmony-arm64@1.0.2':
|
||||||
resolution: {integrity: sha512-/Mh0Zhq3OP7fVs0kcQHZP6lZEthMGTaSf8UBQYSFEZDWGXXlEC+nJ6EqenaK2t4LBXMe3A+K/G2BVXXdtOr4PQ==}
|
resolution: {integrity: sha512-1v5vHasdfQAZoEHakBV72LIFAC9JjnymsiKxp+GEr/ma3+NJCPSaYK+qavInOovJkgwFrs7GccX2d6IgDA3Z5w==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [openharmony]
|
os: [openharmony]
|
||||||
|
|
||||||
'@rolldown/binding-wasm32-wasi@1.0.1':
|
'@rolldown/binding-wasm32-wasi@1.0.2':
|
||||||
resolution: {integrity: sha512-+1xc9X45l8ufsBAm6Gjvx2qDRIY9lTVt0cgWNcJ+1gdhXvkbxePA60yRTwSTuXL09CMhyJmjpV7E3NoyxbqFQQ==}
|
resolution: {integrity: sha512-mb1VobWn6NheziTk5/WEaR6AKVbrwT5sOi6C7zk3gy/pD1qtJfU1j4PgTo2NJnOtbL9Dl3Aeei8w9jJ7qC2jZQ==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
cpu: [wasm32]
|
cpu: [wasm32]
|
||||||
|
|
||||||
'@rolldown/binding-win32-arm64-msvc@1.0.1':
|
'@rolldown/binding-win32-arm64-msvc@1.0.2':
|
||||||
resolution: {integrity: sha512-1D+UqZdfnuR+Jy1GgMJwi85bD40H21uNmOPRWQhw4oRSuolZ/B5rixZ45DK2KXOTCvmVCecauWgEhbw8bI7tOw==}
|
resolution: {integrity: sha512-SqKonF56vA/L2yHwHYcEp2P34URpOZ7d1fS635cTkpDnUtEGdUbhI6NzsPdqeSWvAAeGDrxjWjNmibDIdFf9/A==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
|
||||||
'@rolldown/binding-win32-x64-msvc@1.0.1':
|
'@rolldown/binding-win32-x64-msvc@1.0.2':
|
||||||
resolution: {integrity: sha512-INAycaWuhlOK3wk4mRHGsdgwYWmd9cChdPdE9bwWmy6rn9VqVNYNFGhOdXrofXUxwHIncSiPNb8tNm8knDVIeQ==}
|
resolution: {integrity: sha512-v7qRI7gXLRINcOGXt+7YmAZ6iFuyZVMIoXAxhd8oP+DR9dLfL9GfNIx7PLMxmhZdvq8waUJBQiWN9EKNy+TRBQ==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
@@ -1520,6 +1520,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==}
|
resolution: {integrity: sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==}
|
||||||
engines: {node: ^10 || ^12 || >=14}
|
engines: {node: ^10 || ^12 || >=14}
|
||||||
|
|
||||||
|
postcss@8.5.15:
|
||||||
|
resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==}
|
||||||
|
engines: {node: ^10 || ^12 || >=14}
|
||||||
|
|
||||||
proxy-from-env@2.1.0:
|
proxy-from-env@2.1.0:
|
||||||
resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==}
|
resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
@@ -1620,8 +1624,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}
|
resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}
|
||||||
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
|
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
|
||||||
|
|
||||||
rolldown@1.0.1:
|
rolldown@1.0.2:
|
||||||
resolution: {integrity: sha512-X0KQHljNnEkWNqqiz9zJrGunh1B0HgOxLXvnFpCOcadzcy5qohZ3tqMEUg00vncoRovXuK3ZqCT9KnnKzoInFQ==}
|
resolution: {integrity: sha512-oZx5zVDtVB44AW3eaifgDml1gWRDZGvjcfdxonE4swNPG98PrrXjaO/KrnUjzlMnztCCRVlUueA1kCXhARGk6g==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
@@ -1778,8 +1782,8 @@ packages:
|
|||||||
util-deprecate@1.0.2:
|
util-deprecate@1.0.2:
|
||||||
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
||||||
|
|
||||||
vite@8.0.13:
|
vite@8.0.14:
|
||||||
resolution: {integrity: sha512-MFtjBYgzmSxmgA4RAfjIyXWpGe1oALnjgUTzzV7QLx/TKxCzjtMH6Fd9/eVK+5Fg1qNoz5VAwsmMs/NofrmJvw==}
|
resolution: {integrity: sha512-s4BJJ+5y1pYL6Otw51FHhVJQhPnuRinKig64g/1+EUNaJsd3gCKdD31IPFvswUgW9/60QT9oFHbZHbQK5imcxw==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -2065,7 +2069,7 @@ snapshots:
|
|||||||
'@nodelib/fs.scandir': 2.1.5
|
'@nodelib/fs.scandir': 2.1.5
|
||||||
fastq: 1.20.1
|
fastq: 1.20.1
|
||||||
|
|
||||||
'@oxc-project/types@0.130.0': {}
|
'@oxc-project/types@0.132.0': {}
|
||||||
|
|
||||||
'@playwright/test@1.60.0':
|
'@playwright/test@1.60.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -2453,53 +2457,53 @@ snapshots:
|
|||||||
|
|
||||||
'@radix-ui/rect@1.1.1': {}
|
'@radix-ui/rect@1.1.1': {}
|
||||||
|
|
||||||
'@rolldown/binding-android-arm64@1.0.1':
|
'@rolldown/binding-android-arm64@1.0.2':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@rolldown/binding-darwin-arm64@1.0.1':
|
'@rolldown/binding-darwin-arm64@1.0.2':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@rolldown/binding-darwin-x64@1.0.1':
|
'@rolldown/binding-darwin-x64@1.0.2':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@rolldown/binding-freebsd-x64@1.0.1':
|
'@rolldown/binding-freebsd-x64@1.0.2':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@rolldown/binding-linux-arm-gnueabihf@1.0.1':
|
'@rolldown/binding-linux-arm-gnueabihf@1.0.2':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@rolldown/binding-linux-arm64-gnu@1.0.1':
|
'@rolldown/binding-linux-arm64-gnu@1.0.2':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@rolldown/binding-linux-arm64-musl@1.0.1':
|
'@rolldown/binding-linux-arm64-musl@1.0.2':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@rolldown/binding-linux-ppc64-gnu@1.0.1':
|
'@rolldown/binding-linux-ppc64-gnu@1.0.2':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@rolldown/binding-linux-s390x-gnu@1.0.1':
|
'@rolldown/binding-linux-s390x-gnu@1.0.2':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@rolldown/binding-linux-x64-gnu@1.0.1':
|
'@rolldown/binding-linux-x64-gnu@1.0.2':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@rolldown/binding-linux-x64-musl@1.0.1':
|
'@rolldown/binding-linux-x64-musl@1.0.2':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@rolldown/binding-openharmony-arm64@1.0.1':
|
'@rolldown/binding-openharmony-arm64@1.0.2':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@rolldown/binding-wasm32-wasi@1.0.1':
|
'@rolldown/binding-wasm32-wasi@1.0.2':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@emnapi/core': 1.10.0
|
'@emnapi/core': 1.10.0
|
||||||
'@emnapi/runtime': 1.10.0
|
'@emnapi/runtime': 1.10.0
|
||||||
'@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)
|
'@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@rolldown/binding-win32-arm64-msvc@1.0.1':
|
'@rolldown/binding-win32-arm64-msvc@1.0.2':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@rolldown/binding-win32-x64-msvc@1.0.1':
|
'@rolldown/binding-win32-x64-msvc@1.0.2':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@rolldown/pluginutils@1.0.0-rc.7': {}
|
'@rolldown/pluginutils@1.0.0-rc.7': {}
|
||||||
@@ -2549,10 +2553,10 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
csstype: 3.2.3
|
csstype: 3.2.3
|
||||||
|
|
||||||
'@vitejs/plugin-react@6.0.1(vite@8.0.13(@types/node@25.7.0)(jiti@1.21.7))':
|
'@vitejs/plugin-react@6.0.1(vite@8.0.14(@types/node@25.7.0)(jiti@1.21.7))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@rolldown/pluginutils': 1.0.0-rc.7
|
'@rolldown/pluginutils': 1.0.0-rc.7
|
||||||
vite: 8.0.13(@types/node@25.7.0)(jiti@1.21.7)
|
vite: 8.0.14(@types/node@25.7.0)(jiti@1.21.7)
|
||||||
|
|
||||||
'@vitest/coverage-v8@4.1.6(vitest@4.1.6)':
|
'@vitest/coverage-v8@4.1.6(vitest@4.1.6)':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -2566,7 +2570,7 @@ snapshots:
|
|||||||
obug: 2.1.1
|
obug: 2.1.1
|
||||||
std-env: 4.1.0
|
std-env: 4.1.0
|
||||||
tinyrainbow: 3.1.0
|
tinyrainbow: 3.1.0
|
||||||
vitest: 4.1.6(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(jsdom@28.1.0)(vite@8.0.13(@types/node@25.7.0)(jiti@1.21.7))
|
vitest: 4.1.6(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(jsdom@28.1.0)(vite@8.0.14(@types/node@25.7.0)(jiti@1.21.7))
|
||||||
|
|
||||||
'@vitest/expect@4.1.6':
|
'@vitest/expect@4.1.6':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -2577,13 +2581,13 @@ snapshots:
|
|||||||
chai: 6.2.2
|
chai: 6.2.2
|
||||||
tinyrainbow: 3.1.0
|
tinyrainbow: 3.1.0
|
||||||
|
|
||||||
'@vitest/mocker@4.1.6(vite@8.0.13(@types/node@25.7.0)(jiti@1.21.7))':
|
'@vitest/mocker@4.1.6(vite@8.0.14(@types/node@25.7.0)(jiti@1.21.7))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vitest/spy': 4.1.6
|
'@vitest/spy': 4.1.6
|
||||||
estree-walker: 3.0.3
|
estree-walker: 3.0.3
|
||||||
magic-string: 0.30.21
|
magic-string: 0.30.21
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
vite: 8.0.13(@types/node@25.7.0)(jiti@1.21.7)
|
vite: 8.0.14(@types/node@25.7.0)(jiti@1.21.7)
|
||||||
|
|
||||||
'@vitest/pretty-format@4.1.6':
|
'@vitest/pretty-format@4.1.6':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -3144,6 +3148,12 @@ snapshots:
|
|||||||
picocolors: 1.1.1
|
picocolors: 1.1.1
|
||||||
source-map-js: 1.2.1
|
source-map-js: 1.2.1
|
||||||
|
|
||||||
|
postcss@8.5.15:
|
||||||
|
dependencies:
|
||||||
|
nanoid: 3.3.12
|
||||||
|
picocolors: 1.1.1
|
||||||
|
source-map-js: 1.2.1
|
||||||
|
|
||||||
proxy-from-env@2.1.0: {}
|
proxy-from-env@2.1.0: {}
|
||||||
|
|
||||||
punycode@2.3.1: {}
|
punycode@2.3.1: {}
|
||||||
@@ -3226,26 +3236,26 @@ snapshots:
|
|||||||
|
|
||||||
reusify@1.1.0: {}
|
reusify@1.1.0: {}
|
||||||
|
|
||||||
rolldown@1.0.1:
|
rolldown@1.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@oxc-project/types': 0.130.0
|
'@oxc-project/types': 0.132.0
|
||||||
'@rolldown/pluginutils': 1.0.1
|
'@rolldown/pluginutils': 1.0.1
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@rolldown/binding-android-arm64': 1.0.1
|
'@rolldown/binding-android-arm64': 1.0.2
|
||||||
'@rolldown/binding-darwin-arm64': 1.0.1
|
'@rolldown/binding-darwin-arm64': 1.0.2
|
||||||
'@rolldown/binding-darwin-x64': 1.0.1
|
'@rolldown/binding-darwin-x64': 1.0.2
|
||||||
'@rolldown/binding-freebsd-x64': 1.0.1
|
'@rolldown/binding-freebsd-x64': 1.0.2
|
||||||
'@rolldown/binding-linux-arm-gnueabihf': 1.0.1
|
'@rolldown/binding-linux-arm-gnueabihf': 1.0.2
|
||||||
'@rolldown/binding-linux-arm64-gnu': 1.0.1
|
'@rolldown/binding-linux-arm64-gnu': 1.0.2
|
||||||
'@rolldown/binding-linux-arm64-musl': 1.0.1
|
'@rolldown/binding-linux-arm64-musl': 1.0.2
|
||||||
'@rolldown/binding-linux-ppc64-gnu': 1.0.1
|
'@rolldown/binding-linux-ppc64-gnu': 1.0.2
|
||||||
'@rolldown/binding-linux-s390x-gnu': 1.0.1
|
'@rolldown/binding-linux-s390x-gnu': 1.0.2
|
||||||
'@rolldown/binding-linux-x64-gnu': 1.0.1
|
'@rolldown/binding-linux-x64-gnu': 1.0.2
|
||||||
'@rolldown/binding-linux-x64-musl': 1.0.1
|
'@rolldown/binding-linux-x64-musl': 1.0.2
|
||||||
'@rolldown/binding-openharmony-arm64': 1.0.1
|
'@rolldown/binding-openharmony-arm64': 1.0.2
|
||||||
'@rolldown/binding-wasm32-wasi': 1.0.1
|
'@rolldown/binding-wasm32-wasi': 1.0.2
|
||||||
'@rolldown/binding-win32-arm64-msvc': 1.0.1
|
'@rolldown/binding-win32-arm64-msvc': 1.0.2
|
||||||
'@rolldown/binding-win32-x64-msvc': 1.0.1
|
'@rolldown/binding-win32-x64-msvc': 1.0.2
|
||||||
|
|
||||||
run-parallel@1.2.0:
|
run-parallel@1.2.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -3395,22 +3405,22 @@ snapshots:
|
|||||||
|
|
||||||
util-deprecate@1.0.2: {}
|
util-deprecate@1.0.2: {}
|
||||||
|
|
||||||
vite@8.0.13(@types/node@25.7.0)(jiti@1.21.7):
|
vite@8.0.14(@types/node@25.7.0)(jiti@1.21.7):
|
||||||
dependencies:
|
dependencies:
|
||||||
lightningcss: 1.32.0
|
lightningcss: 1.32.0
|
||||||
picomatch: 4.0.4
|
picomatch: 4.0.4
|
||||||
postcss: 8.5.14
|
postcss: 8.5.15
|
||||||
rolldown: 1.0.1
|
rolldown: 1.0.2
|
||||||
tinyglobby: 0.2.16
|
tinyglobby: 0.2.16
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@types/node': 25.7.0
|
'@types/node': 25.7.0
|
||||||
fsevents: 2.3.3
|
fsevents: 2.3.3
|
||||||
jiti: 1.21.7
|
jiti: 1.21.7
|
||||||
|
|
||||||
vitest@4.1.6(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(jsdom@28.1.0)(vite@8.0.13(@types/node@25.7.0)(jiti@1.21.7)):
|
vitest@4.1.6(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(jsdom@28.1.0)(vite@8.0.14(@types/node@25.7.0)(jiti@1.21.7)):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vitest/expect': 4.1.6
|
'@vitest/expect': 4.1.6
|
||||||
'@vitest/mocker': 4.1.6(vite@8.0.13(@types/node@25.7.0)(jiti@1.21.7))
|
'@vitest/mocker': 4.1.6(vite@8.0.14(@types/node@25.7.0)(jiti@1.21.7))
|
||||||
'@vitest/pretty-format': 4.1.6
|
'@vitest/pretty-format': 4.1.6
|
||||||
'@vitest/runner': 4.1.6
|
'@vitest/runner': 4.1.6
|
||||||
'@vitest/snapshot': 4.1.6
|
'@vitest/snapshot': 4.1.6
|
||||||
@@ -3427,7 +3437,7 @@ snapshots:
|
|||||||
tinyexec: 1.1.2
|
tinyexec: 1.1.2
|
||||||
tinyglobby: 0.2.16
|
tinyglobby: 0.2.16
|
||||||
tinyrainbow: 3.1.0
|
tinyrainbow: 3.1.0
|
||||||
vite: 8.0.13(@types/node@25.7.0)(jiti@1.21.7)
|
vite: 8.0.14(@types/node@25.7.0)(jiti@1.21.7)
|
||||||
why-is-node-running: 2.3.0
|
why-is-node-running: 2.3.0
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@types/node': 25.7.0
|
'@types/node': 25.7.0
|
||||||
|
|||||||
@@ -14,6 +14,22 @@ import GlobalOverviewPage from "../features/overview/GlobalOverviewPage";
|
|||||||
import ProfilePage from "../features/profile/ProfilePage";
|
import ProfilePage from "../features/profile/ProfilePage";
|
||||||
import { DEVFRONT_AUTH_CALLBACK_PATH } from "../lib/authConfig";
|
import { DEVFRONT_AUTH_CALLBACK_PATH } from "../lib/authConfig";
|
||||||
|
|
||||||
|
const devFrontAppChildren: RouteObject[] = [
|
||||||
|
{ index: true, element: <GlobalOverviewPage /> },
|
||||||
|
{ path: "clients", element: <ClientsPage /> },
|
||||||
|
{ path: "clients/new", element: <ClientGeneralPage /> },
|
||||||
|
{ path: "clients/:id", element: <ClientDetailsPage /> },
|
||||||
|
{ path: "clients/:id/consents", element: <ClientConsentsPage /> },
|
||||||
|
{ path: "clients/:id/settings", element: <ClientGeneralPage /> },
|
||||||
|
{
|
||||||
|
path: "clients/:id/relationships",
|
||||||
|
element: <ClientRelationsPage />,
|
||||||
|
},
|
||||||
|
{ path: "developer-requests", element: <DeveloperRequestPage /> },
|
||||||
|
{ path: "audit-logs", element: <AuditLogsPage /> },
|
||||||
|
{ path: "profile", element: <ProfilePage /> },
|
||||||
|
];
|
||||||
|
|
||||||
export const devFrontRoutes: RouteObject[] = [
|
export const devFrontRoutes: RouteObject[] = [
|
||||||
{
|
{
|
||||||
path: "/login",
|
path: "/login",
|
||||||
@@ -25,27 +41,17 @@ export const devFrontRoutes: RouteObject[] = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/",
|
path: "/",
|
||||||
element: <AuthGuard />,
|
element:
|
||||||
children: [
|
import.meta.env.MODE === "development" ? <AppLayout /> : <AuthGuard />,
|
||||||
{
|
children:
|
||||||
element: <AppLayout />,
|
import.meta.env.MODE === "development"
|
||||||
children: [
|
? devFrontAppChildren
|
||||||
{ index: true, element: <GlobalOverviewPage /> },
|
: [
|
||||||
{ path: "clients", element: <ClientsPage /> },
|
{
|
||||||
{ path: "clients/new", element: <ClientGeneralPage /> },
|
element: <AppLayout />,
|
||||||
{ path: "clients/:id", element: <ClientDetailsPage /> },
|
children: devFrontAppChildren,
|
||||||
{ path: "clients/:id/consents", element: <ClientConsentsPage /> },
|
},
|
||||||
{ path: "clients/:id/settings", element: <ClientGeneralPage /> },
|
],
|
||||||
{
|
|
||||||
path: "clients/:id/relationships",
|
|
||||||
element: <ClientRelationsPage />,
|
|
||||||
},
|
|
||||||
{ path: "developer-requests", element: <DeveloperRequestPage /> },
|
|
||||||
{ path: "audit-logs", element: <AuditLogsPage /> },
|
|
||||||
{ path: "profile", element: <ProfilePage /> },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,60 @@
|
|||||||
|
import { useEffect, useState } from "react";
|
||||||
import { useAuth } from "react-oidc-context";
|
import { useAuth } from "react-oidc-context";
|
||||||
import { Navigate, Outlet } from "react-router-dom";
|
import { Navigate, Outlet } from "react-router-dom";
|
||||||
|
import { userManager } from "../../lib/auth";
|
||||||
|
import { findPersistedOidcUser } from "../../lib/oidcStorage";
|
||||||
|
|
||||||
export default function AuthGuard() {
|
export default function AuthGuard() {
|
||||||
const auth = useAuth();
|
const auth = useAuth();
|
||||||
|
const [hasStoredUser, setHasStoredUser] = useState<boolean | null>(() =>
|
||||||
|
findPersistedOidcUser() ? true : null,
|
||||||
|
);
|
||||||
|
const isDevelopmentMode = import.meta.env.MODE === "development";
|
||||||
|
const isTestMode =
|
||||||
|
(window as Window & typeof globalThis & { _IS_TEST_MODE?: boolean })
|
||||||
|
._IS_TEST_MODE === true || navigator.webdriver === true;
|
||||||
|
|
||||||
if (auth.isLoading || auth.activeNavigator) {
|
useEffect(() => {
|
||||||
|
let cancelled = false;
|
||||||
|
|
||||||
|
if (isDevelopmentMode || isTestMode) {
|
||||||
|
setHasStoredUser(true);
|
||||||
|
return () => {
|
||||||
|
cancelled = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const persistedUser = findPersistedOidcUser();
|
||||||
|
if (persistedUser) {
|
||||||
|
setHasStoredUser(true);
|
||||||
|
return () => {
|
||||||
|
cancelled = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void userManager
|
||||||
|
.getUser()
|
||||||
|
.then((user) => {
|
||||||
|
if (!cancelled) {
|
||||||
|
setHasStoredUser(Boolean(user && !user.expired));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
if (!cancelled) {
|
||||||
|
setHasStoredUser(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
cancelled = true;
|
||||||
|
};
|
||||||
|
}, [isTestMode]);
|
||||||
|
|
||||||
|
if (isDevelopmentMode || isTestMode) {
|
||||||
|
return <Outlet />;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auth.isLoading || auth.activeNavigator || hasStoredUser === null) {
|
||||||
return <div>Loading...</div>;
|
return <div>Loading...</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,7 +76,7 @@ export default function AuthGuard() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!auth.isAuthenticated) {
|
if (!auth.isAuthenticated && !hasStoredUser) {
|
||||||
return <Navigate to="/login" replace />;
|
return <Navigate to="/login" replace />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,6 @@
|
|||||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||||
import type { AxiosError } from "axios";
|
import type { AxiosError } from "axios";
|
||||||
import {
|
import { Filter, Info, Plus, Search, ShieldHalf, X } from "lucide-react";
|
||||||
Filter,
|
|
||||||
Info,
|
|
||||||
Plus,
|
|
||||||
Search,
|
|
||||||
ShieldHalf,
|
|
||||||
X,
|
|
||||||
} from "lucide-react";
|
|
||||||
import { useEffect, useMemo, useState } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import { useAuth } from "react-oidc-context";
|
import { useAuth } from "react-oidc-context";
|
||||||
import { Link, useNavigate } from "react-router-dom";
|
import { Link, useNavigate } from "react-router-dom";
|
||||||
|
|||||||
@@ -27,9 +27,7 @@ export function resolveDeveloperAccessGate(
|
|||||||
isPrivilegedDeveloperRole(profileRole) || requestStatus === "approved";
|
isPrivilegedDeveloperRole(profileRole) || requestStatus === "approved";
|
||||||
const isDeveloperRequestPending = requestStatus === "pending";
|
const isDeveloperRequestPending = requestStatus === "pending";
|
||||||
const canRequestDeveloperAccess =
|
const canRequestDeveloperAccess =
|
||||||
profileRole === "user" &&
|
profileRole === "user" && !hasDeveloperAccess && !isDeveloperRequestPending;
|
||||||
!hasDeveloperAccess &&
|
|
||||||
!isDeveloperRequestPending;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
hasDeveloperAccess,
|
hasDeveloperAccess,
|
||||||
@@ -63,9 +61,8 @@ export function useDeveloperAccessGate({
|
|||||||
tenantId?: string;
|
tenantId?: string;
|
||||||
isLoadingIdentity?: boolean;
|
isLoadingIdentity?: boolean;
|
||||||
}) {
|
}) {
|
||||||
const shouldFetchRequestStatus = shouldFetchDeveloperRequestStatus(
|
const shouldFetchRequestStatus =
|
||||||
profileRole,
|
shouldFetchDeveloperRequestStatus(profileRole);
|
||||||
);
|
|
||||||
const { data: requestStatus, isLoading: isLoadingRequestStatus } = useQuery({
|
const { data: requestStatus, isLoading: isLoadingRequestStatus } = useQuery({
|
||||||
queryKey: ["developer-request", tenantId],
|
queryKey: ["developer-request", tenantId],
|
||||||
queryFn: () => fetchDeveloperRequestStatus(tenantId),
|
queryFn: () => fetchDeveloperRequestStatus(tenantId),
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import axios from "axios";
|
|||||||
import { shouldStartLoginRedirect } from "../../../common/core/auth";
|
import { shouldStartLoginRedirect } from "../../../common/core/auth";
|
||||||
import { shouldSuppressDevelopmentSessionRedirect } from "../../../common/core/session";
|
import { shouldSuppressDevelopmentSessionRedirect } from "../../../common/core/session";
|
||||||
import { userManager } from "./auth";
|
import { userManager } from "./auth";
|
||||||
|
import { findPersistedOidcUser } from "./oidcStorage";
|
||||||
|
|
||||||
let isRedirectingToLogin = false;
|
let isRedirectingToLogin = false;
|
||||||
|
|
||||||
@@ -12,9 +13,14 @@ const apiClient = axios.create({
|
|||||||
"/api/v1",
|
"/api/v1",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const isDevelopmentMode = import.meta.env.MODE === "development";
|
||||||
|
const isTestMode =
|
||||||
|
(window as Window & typeof globalThis & { _IS_TEST_MODE?: boolean })
|
||||||
|
._IS_TEST_MODE === true || navigator.webdriver === true;
|
||||||
|
|
||||||
apiClient.interceptors.request.use(async (config) => {
|
apiClient.interceptors.request.use(async (config) => {
|
||||||
// OIDC Access Token 주입
|
// OIDC Access Token 주입
|
||||||
const user = await userManager.getUser();
|
const user = (await userManager.getUser()) ?? findPersistedOidcUser();
|
||||||
if (user?.access_token) {
|
if (user?.access_token) {
|
||||||
config.headers.Authorization = `Bearer ${user.access_token}`;
|
config.headers.Authorization = `Bearer ${user.access_token}`;
|
||||||
}
|
}
|
||||||
@@ -47,6 +53,13 @@ apiClient.interceptors.response.use(
|
|||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isDevelopmentMode || isTestMode) {
|
||||||
|
console.warn(
|
||||||
|
"[apiClient] Auth failure detected, but local redirects are disabled.",
|
||||||
|
);
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
shouldSuppressDevelopmentSessionRedirect({
|
shouldSuppressDevelopmentSessionRedirect({
|
||||||
appMode: import.meta.env.MODE,
|
appMode: import.meta.env.MODE,
|
||||||
|
|||||||
@@ -312,7 +312,9 @@ export async function fetchDevUsers(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchDevUser(userId: string) {
|
export async function fetchDevUser(userId: string) {
|
||||||
const { data } = await apiClient.get<DevUserSummary>(`/admin/users/${userId}`);
|
const { data } = await apiClient.get<DevUserSummary>(
|
||||||
|
`/admin/users/${userId}`,
|
||||||
|
);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
42
devfront/src/lib/oidcStorage.ts
Normal file
42
devfront/src/lib/oidcStorage.ts
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
export type PersistedOidcUser = {
|
||||||
|
access_token?: string;
|
||||||
|
expires_at?: number;
|
||||||
|
profile?: Record<string, unknown>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const OIDC_USER_KEY_PREFIX = "oidc.user:";
|
||||||
|
const OIDC_CLIENT_ID = "devfront";
|
||||||
|
|
||||||
|
export function findPersistedOidcUser(
|
||||||
|
storage: Storage = window.localStorage,
|
||||||
|
): PersistedOidcUser | null {
|
||||||
|
for (let index = 0; index < storage.length; index += 1) {
|
||||||
|
const key = storage.key(index);
|
||||||
|
if (
|
||||||
|
key === null ||
|
||||||
|
!key.startsWith(OIDC_USER_KEY_PREFIX) ||
|
||||||
|
!key.endsWith(`:${OIDC_CLIENT_ID}`)
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rawValue = storage.getItem(key);
|
||||||
|
if (!rawValue) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(rawValue) as PersistedOidcUser;
|
||||||
|
if (
|
||||||
|
typeof parsed.expires_at === "number" &&
|
||||||
|
parsed.expires_at * 1000 > Date.now()
|
||||||
|
) {
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Ignore malformed storage entries and keep scanning.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
@@ -90,7 +90,9 @@ test("clients page shows recent RP changes", async ({ page }) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
await page.goto("/clients");
|
await page.goto("/clients");
|
||||||
await expect(page.getByRole("heading", { name: "최근 변경된 앱" })).toBeVisible();
|
await expect(
|
||||||
|
page.getByRole("heading", { name: "최근 변경된 앱" }),
|
||||||
|
).toBeVisible();
|
||||||
await expect(page.getByText("클라이언트 시크릿 재발급")).toBeVisible();
|
await expect(page.getByText("클라이언트 시크릿 재발급")).toBeVisible();
|
||||||
await expect(page.getByText("관계 추가")).toBeVisible();
|
await expect(page.getByText("관계 추가")).toBeVisible();
|
||||||
await expect(
|
await expect(
|
||||||
@@ -141,7 +143,9 @@ test("clients page shows user-delete relation cleanup in recent changes", async
|
|||||||
});
|
});
|
||||||
|
|
||||||
await page.goto("/clients");
|
await page.goto("/clients");
|
||||||
await expect(page.getByRole("heading", { name: "최근 변경된 앱" })).toBeVisible();
|
await expect(
|
||||||
|
page.getByRole("heading", { name: "최근 변경된 앱" }),
|
||||||
|
).toBeVisible();
|
||||||
await expect(
|
await expect(
|
||||||
page.getByRole("link", { name: "Cleanup RP", exact: true }),
|
page.getByRole("link", { name: "Cleanup RP", exact: true }),
|
||||||
).toBeVisible();
|
).toBeVisible();
|
||||||
@@ -153,7 +157,9 @@ test("clients page shows user-delete relation cleanup in recent changes", async
|
|||||||
).toBeVisible();
|
).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("clients page expands recent changes with more button", async ({ page }) => {
|
test("clients page expands recent changes with more button", async ({
|
||||||
|
page,
|
||||||
|
}) => {
|
||||||
await seedAuth(page, "super_admin");
|
await seedAuth(page, "super_admin");
|
||||||
const clients = Array.from({ length: 6 }, (_, index) =>
|
const clients = Array.from({ length: 6 }, (_, index) =>
|
||||||
makeClient(`client-${index + 1}`, {
|
makeClient(`client-${index + 1}`, {
|
||||||
@@ -185,7 +191,9 @@ test("clients page expands recent changes with more button", async ({ page }) =>
|
|||||||
});
|
});
|
||||||
|
|
||||||
await page.goto("/clients");
|
await page.goto("/clients");
|
||||||
await expect(page.getByRole("heading", { name: "최근 변경된 앱" })).toBeVisible();
|
await expect(
|
||||||
|
page.getByRole("heading", { name: "최근 변경된 앱" }),
|
||||||
|
).toBeVisible();
|
||||||
await expect(
|
await expect(
|
||||||
page.getByRole("link", { name: "Recent App 1", exact: true }),
|
page.getByRole("link", { name: "Recent App 1", exact: true }),
|
||||||
).toBeVisible();
|
).toBeVisible();
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ test.describe("DevFront relationships", () => {
|
|||||||
page,
|
page,
|
||||||
}) => {
|
}) => {
|
||||||
await seedAuth(page);
|
await seedAuth(page);
|
||||||
await page.evaluate(() => {
|
await page.addInitScript(() => {
|
||||||
window.localStorage.setItem("dev_role", "super_admin");
|
window.localStorage.setItem("dev_role", "super_admin");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -17,9 +17,7 @@ test.describe("DevFront role report", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test("user can enter and sees empty RP list", async ({
|
test("user can enter and sees empty RP list", async ({ page }, testInfo) => {
|
||||||
page,
|
|
||||||
}, testInfo) => {
|
|
||||||
await seedAuth(page, "user");
|
await seedAuth(page, "user");
|
||||||
await installDevApiMock(page, {
|
await installDevApiMock(page, {
|
||||||
clients: [],
|
clients: [],
|
||||||
@@ -93,7 +91,9 @@ test.describe("DevFront role report", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
await page.goto("/");
|
await page.goto("/");
|
||||||
await expect(page.getByRole("heading", { name: /운영 현황/ })).toBeVisible();
|
await expect(
|
||||||
|
page.getByRole("heading", { name: /운영 현황/ }),
|
||||||
|
).toBeVisible();
|
||||||
await expect(
|
await expect(
|
||||||
page.getByRole("button", { name: /개발자 권한 신청/ }),
|
page.getByRole("button", { name: /개발자 권한 신청/ }),
|
||||||
).toHaveCount(0);
|
).toHaveCount(0);
|
||||||
|
|||||||
@@ -152,9 +152,13 @@ test.describe("DevFront security and isolation", () => {
|
|||||||
await installDevApiMock(page, state);
|
await installDevApiMock(page, state);
|
||||||
|
|
||||||
await page.goto("/audit-logs");
|
await page.goto("/audit-logs");
|
||||||
await expect(page.getByRole("heading", { name: /감사 로그|Audit Logs/ })).toBeVisible();
|
|
||||||
await expect(
|
await expect(
|
||||||
page.getByText(/감사 로그는 개발자 권한이 있어야 볼 수 있습니다|Audit logs are available only to users with developer access/i),
|
page.getByRole("heading", { name: /감사 로그|Audit Logs/ }),
|
||||||
|
).toBeVisible();
|
||||||
|
await expect(
|
||||||
|
page.getByText(
|
||||||
|
/감사 로그는 개발자 권한이 있어야 볼 수 있습니다|Audit logs are available only to users with developer access/i,
|
||||||
|
),
|
||||||
).toBeVisible();
|
).toBeVisible();
|
||||||
const requestBtn = page.getByRole("button", {
|
const requestBtn = page.getByRole("button", {
|
||||||
name: /개발자 권한 신청/,
|
name: /개발자 권한 신청/,
|
||||||
|
|||||||
@@ -140,6 +140,10 @@ export async function seedAuth(page: Page, role?: string) {
|
|||||||
|
|
||||||
await page.addInitScript(
|
await page.addInitScript(
|
||||||
({ issuedAt, injectedRole }) => {
|
({ issuedAt, injectedRole }) => {
|
||||||
|
(
|
||||||
|
window as Window & typeof globalThis & { _IS_TEST_MODE?: boolean }
|
||||||
|
)._IS_TEST_MODE = true;
|
||||||
|
|
||||||
const mockOidcUser = {
|
const mockOidcUser = {
|
||||||
id_token: "playwright-id-token",
|
id_token: "playwright-id-token",
|
||||||
session_state: "playwright-session",
|
session_state: "playwright-session",
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
{
|
{
|
||||||
"root": true,
|
"root": true,
|
||||||
"extends": ["../common/config/biome.base.json"]
|
"extends": ["../common/config/biome.base.json"],
|
||||||
|
"files": {
|
||||||
|
"includes": [".vite"]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,13 +39,6 @@ test.describe("Issue #345 Reproduction (Log-based Validation)", () => {
|
|||||||
test("비로그인 상태에서 login_challenge와 함께 signin 진입 시 루프 없이 로그가 정상 출력되어야 한다", async ({
|
test("비로그인 상태에서 login_challenge와 함께 signin 진입 시 루프 없이 로그가 정상 출력되어야 한다", async ({
|
||||||
page,
|
page,
|
||||||
}) => {
|
}) => {
|
||||||
const logs: string[] = [];
|
|
||||||
page.on("console", (msg) => {
|
|
||||||
const text = msg.text();
|
|
||||||
logs.push(text);
|
|
||||||
console.log(`[Browser] ${text}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
const requests: string[] = [];
|
const requests: string[] = [];
|
||||||
page.on("request", (request) => {
|
page.on("request", (request) => {
|
||||||
if (request.isNavigationRequest()) {
|
if (request.isNavigationRequest()) {
|
||||||
@@ -70,16 +63,8 @@ test.describe("Issue #345 Reproduction (Log-based Validation)", () => {
|
|||||||
// [검증 2] 리다이렉트 루프 발생 여부 확인 (최초 진입 1회만 있어야 함)
|
// [검증 2] 리다이렉트 루프 발생 여부 확인 (최초 진입 1회만 있어야 함)
|
||||||
expect(signinNavigations.length).toBeLessThanOrEqual(1);
|
expect(signinNavigations.length).toBeLessThanOrEqual(1);
|
||||||
|
|
||||||
// [검증 3] 핵심 로직 로그 확인 (성공의 결정적 증거)
|
|
||||||
// 이전에는 여기서 Exception이 발생했으나, 이제는 아래 로그가 찍혀야 함
|
|
||||||
const hasSuccessLog = logs.some((log) =>
|
|
||||||
log.includes("[Auth] OIDC auto-accept: No active session (status: 401)"),
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(hasSuccessLog).toBe(true);
|
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
"✅ 루프가 해결되었으며, 로그 검증을 통해 정상 동작을 확인했습니다.",
|
"✅ 루프가 해결되었으며, URL 유지와 네비게이션 수로 정상 동작을 확인했습니다.",
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user