1
0
forked from baron/baron-sso

chore: consolidate local integration changes

This commit is contained in:
2026-06-09 21:03:05 +09:00
parent aa2848c3b6
commit 1341f07ef9
158 changed files with 10995 additions and 1490 deletions

View File

@@ -18,7 +18,7 @@ COPY . .
RUN /bin/sh ./scripts/sync_userfront_locales.sh
WORKDIR /app/userfront
RUN flutter pub get
RUN flutter build web --release --wasm
RUN rm -rf build/web && flutter build web --release --wasm
FROM node:24-alpine AS optimize
WORKDIR /work

View File

@@ -1446,7 +1446,7 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
color: Colors.redAccent,
),
)
: Text(
: _singleLineText(
item.isRevoked
? tr('ui.userfront.dashboard.status.revoked')
: tr('ui.userfront.dashboard.revoke.title'),

View File

@@ -2151,7 +2151,7 @@ const Map<String, String> koStrings = {
"ui.userfront.dashboard.last_auth_label": "최근 인증",
"ui.userfront.dashboard.link_status_label": "연동 상태",
"ui.userfront.dashboard.revoke.confirm_button": "해지하기",
"ui.userfront.dashboard.revoke.title": "연동 해지",
"ui.userfront.dashboard.revoke.title": "연동해지",
"ui.userfront.dashboard.scopes.title": "동의 범위",
"ui.userfront.dashboard.sessions.active_badge": "활성화",
"ui.userfront.dashboard.sessions.current_badge": "접속중",

View File

@@ -11,6 +11,14 @@ USERFRONT_BOOT_WARMUP_ATTEMPTS="${USERFRONT_BOOT_WARMUP_ATTEMPTS:-120}"
USERFRONT_BOOT_WARMUP_INTERVAL_SECONDS="${USERFRONT_BOOT_WARMUP_INTERVAL_SECONDS:-0.5}"
USERFRONT_BOOT_WARMUP_LOCALES="${USERFRONT_BOOT_WARMUP_LOCALES:-ko en}"
USERFRONT_BOOT_WARMUP_VIEWPORTS="${USERFRONT_BOOT_WARMUP_VIEWPORTS:-mobile:390 desktop:1440}"
USERFRONT_BOOT_BUILD_MARKER="${USERFRONT_BOOT_BUILD_MARKER:-build/.userfront-boot-build-start}"
USERFRONT_BOOT_LOG="${USERFRONT_BOOT_LOG:-build/userfront-boot-flutter.log}"
USERFRONT_BOOT_LOG_PIPE="${USERFRONT_BOOT_LOG_PIPE:-build/userfront-boot-flutter.pipe}"
echo "[userfront-boot] removing stale build/web before flutter run" >&2
rm -rf build/web
mkdir -p "$(dirname "$USERFRONT_BOOT_BUILD_MARKER")"
: > "$USERFRONT_BOOT_BUILD_MARKER"
warm_get() {
path="$1"
@@ -32,7 +40,7 @@ wait_for_userfront_build() {
attempt=1
while [ "$attempt" -le "$USERFRONT_BOOT_WARMUP_ATTEMPTS" ]; do
if [ -f "build/web/index.html" ]; then
if [ -f "build/web/index.html" ] && [ "build/web/index.html" -nt "$USERFRONT_BOOT_BUILD_MARKER" ]; then
return 0
fi
if ! kill -0 "$flutter_pid" 2>/dev/null; then
@@ -47,50 +55,63 @@ wait_for_userfront_build() {
return 1
}
reset_userfront_service_worker() {
wait_for_userfront_serve_log() {
flutter_pid="$1"
attempt=1
while [ "$attempt" -le "$USERFRONT_BOOT_WARMUP_ATTEMPTS" ]; do
if [ -f "$USERFRONT_BOOT_LOG" ] && grep -Fq "lib/main.dart is being served at" "$USERFRONT_BOOT_LOG"; then
return 0
fi
if ! kill -0 "$flutter_pid" 2>/dev/null; then
echo "[userfront-boot] warmup skipped because flutter exited before serve log was ready" >&2
return 1
fi
attempt=$((attempt + 1))
sleep "$USERFRONT_BOOT_WARMUP_INTERVAL_SECONDS"
done
echo "[userfront-boot] warmup skipped after ${USERFRONT_BOOT_WARMUP_ATTEMPTS} serve readiness attempts" >&2
return 1
}
disable_userfront_dev_service_worker() {
cat > build/web/flutter_service_worker.js <<'EOF'
self.addEventListener("install", (event) => {
self.skipWaiting();
});
self.addEventListener("activate", (event) => {
event.waitUntil(
(async () => {
if (self.caches) {
const keys = await self.caches.keys();
await Promise.all(
keys
.filter(
(key) =>
key.indexOf("baron-userfront-") === 0 ||
key.indexOf("flutter-app-cache") === 0,
)
.map((key) => self.caches.delete(key)),
);
}
await self.registration.unregister();
const clients = await self.clients.matchAll({
type: "window",
includeUncontrolled: true,
});
await Promise.all(clients.map((client) => client.navigate(client.url)));
})(),
);
event.waitUntil(self.registration.unregister());
});
EOF
}
warm_flutter_bootstrap_assets() {
if [ ! -f build/web/flutter_bootstrap.js ]; then
return 0
fi
grep -Eo 'main\.dart\.[^"]+\.(js|mjs|wasm)' build/web/flutter_bootstrap.js \
| sort -u \
| while IFS= read -r asset; do
[ -n "$asset" ] || continue
wget -qO- "http://127.0.0.1:${USERFRONT_INTERNAL_PORT}/${asset}" >/dev/null 2>&1 || \
echo "[userfront-boot] warmup warning: failed to load /${asset}" >&2
done
}
warm_userfront_once() {
flutter_pid="$1"
attempt=1
started_at="$(date +%s)"
if ! wait_for_userfront_serve_log "$flutter_pid"; then
return 0
fi
if ! wait_for_userfront_build "$flutter_pid"; then
return 0
fi
reset_userfront_service_worker
disable_userfront_dev_service_worker
while [ "$attempt" -le "$USERFRONT_BOOT_WARMUP_ATTEMPTS" ]; do
if wget -qO- "http://127.0.0.1:${USERFRONT_INTERNAL_PORT}/flutter_bootstrap.js" >/dev/null 2>&1; then
@@ -109,6 +130,7 @@ warm_userfront_once() {
return 0
fi
started_at="$(date +%s)"
echo "[userfront-boot] one-shot warmup starting locales=\"${USERFRONT_BOOT_WARMUP_LOCALES}\" viewports=\"${USERFRONT_BOOT_WARMUP_VIEWPORTS}\"" >&2
for locale in $USERFRONT_BOOT_WARMUP_LOCALES; do
@@ -120,8 +142,6 @@ warm_userfront_once() {
for asset in \
/ \
/flutter_bootstrap.js \
/main.dart.mjs \
/main.dart.wasm \
/canvaskit/skwasm.js \
/canvaskit/skwasm.wasm \
/canvaskit/skwasm_heavy.js \
@@ -131,6 +151,7 @@ warm_userfront_once() {
do
wget -qO- "http://127.0.0.1:${USERFRONT_INTERNAL_PORT}${asset}" >/dev/null 2>&1 || true
done
warm_flutter_bootstrap_assets
finished_at="$(date +%s)"
elapsed_seconds=$((finished_at - started_at))
@@ -149,14 +170,28 @@ set -- flutter run \
${USERFRONT_FLUTTER_RUN_FLAGS} \
--no-web-resources-cdn
"$@" &
mkdir -p "$(dirname "$USERFRONT_BOOT_LOG")"
rm -f "$USERFRONT_BOOT_LOG" "$USERFRONT_BOOT_LOG_PIPE"
mkfifo "$USERFRONT_BOOT_LOG_PIPE"
tee "$USERFRONT_BOOT_LOG" < "$USERFRONT_BOOT_LOG_PIPE" &
tee_pid="$!"
"$@" > "$USERFRONT_BOOT_LOG_PIPE" 2>&1 &
flutter_pid="$!"
terminate() {
kill "$flutter_pid" 2>/dev/null || true
kill "$tee_pid" 2>/dev/null || true
wait "$flutter_pid" 2>/dev/null || true
wait "$tee_pid" 2>/dev/null || true
rm -f "$USERFRONT_BOOT_LOG_PIPE"
}
trap terminate INT TERM
warm_userfront_once "$flutter_pid"
set +e
wait "$flutter_pid"
flutter_status="$?"
wait "$tee_pid" 2>/dev/null || true
rm -f "$USERFRONT_BOOT_LOG_PIPE"
exit "$flutter_status"

View File

@@ -13,4 +13,23 @@ void main() {
expect(source.contains('_loadAuditLogs('), isFalse);
expect(source.contains('/api/v1/audit/auth/timeline'), isFalse);
});
test('나의 App 현황 연동해지 버튼은 단일 라인 텍스트로 렌더링한다', () async {
final screenFile = File(
'lib/features/dashboard/presentation/dashboard_screen.dart',
);
final source = await screenFile.readAsString();
final revokeLabelIndex = source.lastIndexOf(
"tr('ui.userfront.dashboard.revoke.title')",
);
expect(revokeLabelIndex, isNonNegative);
final snippetStart = revokeLabelIndex > 500 ? revokeLabelIndex - 500 : 0;
final snippetEnd = revokeLabelIndex + 300 < source.length
? revokeLabelIndex + 300
: source.length;
final revokeButtonSource = source.substring(snippetStart, snippetEnd);
expect(revokeButtonSource, contains('_singleLineText('));
});
}

View File

@@ -31,6 +31,10 @@ void main() {
}
});
test('Korean linked app revoke action label stays unbreakable', () {
expect(koStrings['ui.userfront.dashboard.revoke.title'], '연동해지');
});
test(
'TomlAssetLoader excludes non-userfront dictionaries at startup',
() async {