forked from baron/baron-sso
코드체크 업데이트
This commit is contained in:
@@ -174,7 +174,7 @@ jobs:
|
|||||||
# 코드 변경 반영을 위해 build 수행 (userfront nginx.conf 등)
|
# 코드 변경 반영을 위해 build 수행 (userfront nginx.conf 등)
|
||||||
docker compose -f staging_pull_compose.yaml build --pull
|
docker compose -f staging_pull_compose.yaml build --pull
|
||||||
|
|
||||||
docker compose -f staging_pull_compose.yaml up -d --remove-orphans
|
docker compose -f staging_pull_compose.yaml up -d --remove-orphans --renew-anon-volumes
|
||||||
docker compose -f staging_pull_compose.yaml up -d --force-recreate kratos hydra keto oathkeeper
|
docker compose -f staging_pull_compose.yaml up -d --force-recreate kratos hydra keto oathkeeper
|
||||||
docker compose -f staging_pull_compose.yaml up -d --force-recreate ory_stack_check
|
docker compose -f staging_pull_compose.yaml up -d --force-recreate ory_stack_check
|
||||||
docker compose -f staging_pull_compose.yaml up -d init-rp
|
docker compose -f staging_pull_compose.yaml up -d init-rp
|
||||||
|
|||||||
@@ -1,5 +1,12 @@
|
|||||||
|
import { createRequire } from "node:module";
|
||||||
import { defineConfig, devices } from "@playwright/test";
|
import { defineConfig, devices } from "@playwright/test";
|
||||||
|
|
||||||
|
const require = createRequire(import.meta.url);
|
||||||
|
const { shouldIncludeWebKit } =
|
||||||
|
require("../scripts/playwrightHostDeps.cjs") as {
|
||||||
|
shouldIncludeWebKit: () => boolean;
|
||||||
|
};
|
||||||
|
|
||||||
const configuredWorkers = process.env.PLAYWRIGHT_WORKERS
|
const configuredWorkers = process.env.PLAYWRIGHT_WORKERS
|
||||||
? Number.parseInt(process.env.PLAYWRIGHT_WORKERS, 10)
|
? Number.parseInt(process.env.PLAYWRIGHT_WORKERS, 10)
|
||||||
: undefined;
|
: undefined;
|
||||||
@@ -57,10 +64,14 @@ export default defineConfig({
|
|||||||
use: { ...devices["Desktop Firefox"] },
|
use: { ...devices["Desktop Firefox"] },
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
...(shouldIncludeWebKit()
|
||||||
name: "webkit",
|
? [
|
||||||
use: { ...devices["Desktop Safari"] },
|
{
|
||||||
},
|
name: "webkit",
|
||||||
|
use: { ...devices["Desktop Safari"] },
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: []),
|
||||||
],
|
],
|
||||||
|
|
||||||
/* Run your local dev server before starting the tests */
|
/* Run your local dev server before starting the tests */
|
||||||
|
|||||||
@@ -35,6 +35,29 @@ if [ "${1:-}" = "--print-mode" ]; then
|
|||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
ensure_frontend_dependencies() {
|
||||||
|
if [ ! -f package.json ] || [ ! -f package-lock.json ]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v sha256sum >/dev/null 2>&1; then
|
||||||
|
deps_hash="$(sha256sum package.json package-lock.json | sha256sum | awk '{print $1}')"
|
||||||
|
else
|
||||||
|
deps_hash="$(cksum package.json package-lock.json | cksum | awk '{print $1}')"
|
||||||
|
fi
|
||||||
|
deps_stamp="node_modules/.baron-deps-hash"
|
||||||
|
installed_hash="$(cat "$deps_stamp" 2>/dev/null || true)"
|
||||||
|
|
||||||
|
if [ "$installed_hash" != "$deps_hash" ]; then
|
||||||
|
echo "Installing frontend dependencies from package-lock.json..."
|
||||||
|
npm ci
|
||||||
|
mkdir -p node_modules
|
||||||
|
printf '%s\n' "$deps_hash" > "$deps_stamp"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_frontend_dependencies
|
||||||
|
|
||||||
if [ "$mode" = "production" ]; then
|
if [ "$mode" = "production" ]; then
|
||||||
echo "Running in production mode with Vite preview..."
|
echo "Running in production mode with Vite preview..."
|
||||||
exec sh -c "npm run build && npm run preview -- --host 0.0.0.0"
|
exec sh -c "npm run build && npm run preview -- --host 0.0.0.0"
|
||||||
|
|||||||
@@ -101,18 +101,10 @@ export function ParentTenantSelector({
|
|||||||
return (
|
return (
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<div className="flex min-h-8 flex-wrap items-center justify-between gap-2">
|
<div className="flex min-h-8 flex-wrap items-center justify-between gap-2">
|
||||||
<Label className="text-sm font-semibold">
|
<Label className="text-sm font-semibold">{label}</Label>
|
||||||
{label}
|
|
||||||
</Label>
|
|
||||||
{labelAction}
|
{labelAction}
|
||||||
</div>
|
</div>
|
||||||
<input
|
<input id={id} name={id} type="hidden" value={value} readOnly />
|
||||||
id={id}
|
|
||||||
name={id}
|
|
||||||
type="hidden"
|
|
||||||
value={value}
|
|
||||||
readOnly
|
|
||||||
/>
|
|
||||||
<div className="flex min-h-10 flex-wrap items-center gap-2 rounded-md border border-input bg-background px-3 py-2">
|
<div className="flex min-h-10 flex-wrap items-center gap-2 rounded-md border border-input bg-background px-3 py-2">
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@@ -63,7 +63,10 @@ function TenantCreatePage() {
|
|||||||
parentStepConfirmed || Boolean(selectedParentTenant);
|
parentStepConfirmed || Boolean(selectedParentTenant);
|
||||||
const parentContextLabel = selectedParentTenant
|
const parentContextLabel = selectedParentTenant
|
||||||
? canConfigureHanmacOrg
|
? canConfigureHanmacOrg
|
||||||
? t("ui.admin.tenants.create.parent_context.hanmac", "한맥가족 하위 테넌트")
|
? t(
|
||||||
|
"ui.admin.tenants.create.parent_context.hanmac",
|
||||||
|
"한맥가족 하위 테넌트",
|
||||||
|
)
|
||||||
: t("ui.admin.tenants.create.parent_context.general", "일반 하위 테넌트")
|
: t("ui.admin.tenants.create.parent_context.general", "일반 하위 테넌트")
|
||||||
: parentStepConfirmed
|
: parentStepConfirmed
|
||||||
? t("ui.admin.tenants.create.parent_context.root", "최상위 테넌트")
|
? t("ui.admin.tenants.create.parent_context.root", "최상위 테넌트")
|
||||||
@@ -232,10 +235,7 @@ function TenantCreatePage() {
|
|||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div data-testid="tenant-visibility-slot" className="space-y-2">
|
||||||
data-testid="tenant-visibility-slot"
|
|
||||||
className="space-y-2"
|
|
||||||
>
|
|
||||||
<Label
|
<Label
|
||||||
htmlFor="tenant-visibility"
|
htmlFor="tenant-visibility"
|
||||||
className="text-sm font-semibold"
|
className="text-sm font-semibold"
|
||||||
|
|||||||
@@ -980,7 +980,7 @@ function TenantListPage() {
|
|||||||
</Button>
|
</Button>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
))}{" "}
|
))}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -338,10 +338,7 @@ export function TenantProfilePage() {
|
|||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div data-testid="tenant-visibility-slot" className="space-y-2">
|
||||||
data-testid="tenant-visibility-slot"
|
|
||||||
className="space-y-2"
|
|
||||||
>
|
|
||||||
<Label className="text-sm font-semibold">
|
<Label className="text-sm font-semibold">
|
||||||
{t("ui.admin.tenants.profile.visibility", "공개 범위")}
|
{t("ui.admin.tenants.profile.visibility", "공개 범위")}
|
||||||
</Label>
|
</Label>
|
||||||
|
|||||||
@@ -202,6 +202,11 @@ subtitle = "Subtitle"
|
|||||||
[msg.admin.tenants.import_preview]
|
[msg.admin.tenants.import_preview]
|
||||||
description = "Rows without tenant_id are compared with existing tenant candidates, then imported as new tenants or updates."
|
description = "Rows without tenant_id are compared with existing tenant candidates, then imported as new tenants or updates."
|
||||||
|
|
||||||
|
[msg.admin.tenants.parent]
|
||||||
|
local_picker_description = "Select the tenant to use as the parent from the tenant list."
|
||||||
|
local_picker_empty = "No selectable tenants are available."
|
||||||
|
picker_description = "Select a tenant in org-chart to apply it as the parent tenant."
|
||||||
|
|
||||||
[msg.admin.tenants.admins]
|
[msg.admin.tenants.admins]
|
||||||
add_success = "Add Success"
|
add_success = "Add Success"
|
||||||
empty = "Empty"
|
empty = "Empty"
|
||||||
@@ -217,6 +222,7 @@ remove_success = "Owner permission revoked."
|
|||||||
subtitle = "List of owners with top-level permissions for this tenant."
|
subtitle = "List of owners with top-level permissions for this tenant."
|
||||||
|
|
||||||
[msg.admin.tenants.create]
|
[msg.admin.tenants.create]
|
||||||
|
pick_parent_first = "Select the parent tenant first."
|
||||||
subtitle = "Subtitle"
|
subtitle = "Subtitle"
|
||||||
|
|
||||||
[msg.admin.tenants.create.form]
|
[msg.admin.tenants.create.form]
|
||||||
@@ -908,9 +914,14 @@ title = "Domain conflict"
|
|||||||
candidates = "Candidates"
|
candidates = "Candidates"
|
||||||
confirm = "Run import"
|
confirm = "Run import"
|
||||||
create_new_reset = "Create new (reset ID/slug)"
|
create_new_reset = "Create new (reset ID/slug)"
|
||||||
|
csv_parents = "CSV Parents"
|
||||||
external_id = "External ID"
|
external_id = "External ID"
|
||||||
match = "Match"
|
match = "Match"
|
||||||
no_candidates = "No candidates"
|
no_candidates = "No candidates"
|
||||||
|
parent = "Parent"
|
||||||
|
parent_companies = "Parent Companies"
|
||||||
|
parent_company_groups = "Parent Company Groups"
|
||||||
|
parent_organizations = "Parent Organizations"
|
||||||
parent_unresolved = "Parent needs review"
|
parent_unresolved = "Parent needs review"
|
||||||
slug_exists = "slug conflict"
|
slug_exists = "slug conflict"
|
||||||
title = "Confirm CSV import"
|
title = "Confirm CSV import"
|
||||||
@@ -957,11 +968,20 @@ domains_label = "Allowed Domains (Comma separated)"
|
|||||||
domains_placeholder = "example.com, example.kr"
|
domains_placeholder = "example.com, example.kr"
|
||||||
name = "Tenant name"
|
name = "Tenant name"
|
||||||
parent = "Parent"
|
parent = "Parent"
|
||||||
|
pick_hanmac_parent = "Pick from Hanmac Family"
|
||||||
|
pick_other_parent = "Pick another tenant"
|
||||||
|
root_tenant = "Create as top-level tenant"
|
||||||
slug = "Slug"
|
slug = "Slug"
|
||||||
slug_placeholder = "tenant-slug"
|
slug_placeholder = "tenant-slug"
|
||||||
status = "Status"
|
status = "Status"
|
||||||
type = "Type"
|
type = "Type"
|
||||||
|
|
||||||
|
[ui.admin.tenants.create.parent_context]
|
||||||
|
general = "General child tenant"
|
||||||
|
hanmac = "Hanmac Family child tenant"
|
||||||
|
pick_required = "Parent tenant selection required"
|
||||||
|
root = "Top-level tenant"
|
||||||
|
|
||||||
[ui.admin.tenants.create.memo]
|
[ui.admin.tenants.create.memo]
|
||||||
title = "Title"
|
title = "Title"
|
||||||
|
|
||||||
@@ -1023,11 +1043,17 @@ allowed_domains_help = "Users with these email domains will be automatically ass
|
|||||||
approve_button = "Approve Tenant"
|
approve_button = "Approve Tenant"
|
||||||
description = "Description"
|
description = "Description"
|
||||||
name = "Tenant Name"
|
name = "Tenant Name"
|
||||||
|
org_unit_type = "Organization detail type"
|
||||||
slug = "Slug"
|
slug = "Slug"
|
||||||
status = "Status"
|
status = "Status"
|
||||||
subtitle = "Slug and status changes are applied immediately."
|
subtitle = "Slug and status changes are applied immediately."
|
||||||
title = "Tenant Profile"
|
title = "Tenant Profile"
|
||||||
type = "Type"
|
type = "Type"
|
||||||
|
visibility = "Visibility"
|
||||||
|
|
||||||
|
[ui.admin.tenants.parent]
|
||||||
|
local_search_placeholder = "Search tenant name or slug"
|
||||||
|
pick_tenant = "Pick tenant"
|
||||||
|
|
||||||
[ui.admin.tenants.registry]
|
[ui.admin.tenants.registry]
|
||||||
title = "Tenant registry"
|
title = "Tenant registry"
|
||||||
|
|||||||
@@ -203,6 +203,11 @@ subtitle = "현재 등록된 테넌트를 확인하고 상태를 관리합니다
|
|||||||
[msg.admin.tenants.import_preview]
|
[msg.admin.tenants.import_preview]
|
||||||
description = "tenant_id가 없는 행은 기존 테넌트 후보와 비교한 뒤 신규 생성 또는 기존 테넌트 갱신으로 처리합니다."
|
description = "tenant_id가 없는 행은 기존 테넌트 후보와 비교한 뒤 신규 생성 또는 기존 테넌트 갱신으로 처리합니다."
|
||||||
|
|
||||||
|
[msg.admin.tenants.parent]
|
||||||
|
local_picker_description = "테넌트 목록에서 상위 테넌트로 사용할 항목을 선택합니다."
|
||||||
|
local_picker_empty = "선택할 수 있는 테넌트가 없습니다."
|
||||||
|
picker_description = "org-chart에서 테넌트를 선택하면 상위 테넌트에 반영됩니다."
|
||||||
|
|
||||||
[msg.admin.tenants.admins]
|
[msg.admin.tenants.admins]
|
||||||
add_success = "관리자가 추가되었습니다."
|
add_success = "관리자가 추가되었습니다."
|
||||||
empty = "등록된 관리자가 없습니다."
|
empty = "등록된 관리자가 없습니다."
|
||||||
@@ -218,6 +223,7 @@ remove_success = "소유자 권한이 회수되었습니다."
|
|||||||
subtitle = "이 테넌트의 최상위 권한을 가진 소유자(조직장) 목록입니다."
|
subtitle = "이 테넌트의 최상위 권한을 가진 소유자(조직장) 목록입니다."
|
||||||
|
|
||||||
[msg.admin.tenants.create]
|
[msg.admin.tenants.create]
|
||||||
|
pick_parent_first = "상위 테넌트를 먼저 선택하세요."
|
||||||
subtitle = "글로벌 운영 기준의 신규 테넌트를 등록합니다."
|
subtitle = "글로벌 운영 기준의 신규 테넌트를 등록합니다."
|
||||||
|
|
||||||
[msg.admin.tenants.create.form]
|
[msg.admin.tenants.create.form]
|
||||||
@@ -910,9 +916,14 @@ title = "도메인 충돌"
|
|||||||
candidates = "후보"
|
candidates = "후보"
|
||||||
confirm = "가져오기 실행"
|
confirm = "가져오기 실행"
|
||||||
create_new_reset = "신규 생성 (ID/slug 재설정)"
|
create_new_reset = "신규 생성 (ID/slug 재설정)"
|
||||||
|
csv_parents = "CSV 상위 테넌트"
|
||||||
external_id = "외부 ID"
|
external_id = "외부 ID"
|
||||||
match = "매칭"
|
match = "매칭"
|
||||||
no_candidates = "후보 없음"
|
no_candidates = "후보 없음"
|
||||||
|
parent = "상위"
|
||||||
|
parent_companies = "상위 회사"
|
||||||
|
parent_company_groups = "상위 그룹사"
|
||||||
|
parent_organizations = "상위 조직"
|
||||||
parent_unresolved = "부모 확인 필요"
|
parent_unresolved = "부모 확인 필요"
|
||||||
slug_exists = "slug 충돌"
|
slug_exists = "slug 충돌"
|
||||||
title = "CSV 가져오기 확인"
|
title = "CSV 가져오기 확인"
|
||||||
@@ -959,11 +970,20 @@ domains_label = "Allowed Domains (Comma separated)"
|
|||||||
domains_placeholder = "example.com, example.kr"
|
domains_placeholder = "example.com, example.kr"
|
||||||
name = "테넌트 이름"
|
name = "테넌트 이름"
|
||||||
parent = "상위 테넌트"
|
parent = "상위 테넌트"
|
||||||
|
pick_hanmac_parent = "한맥가족에서 선택"
|
||||||
|
pick_other_parent = "다른 테넌트 선택"
|
||||||
|
root_tenant = "최상위 테넌트로 생성"
|
||||||
slug = "Slug"
|
slug = "Slug"
|
||||||
slug_placeholder = "tenant-slug"
|
slug_placeholder = "tenant-slug"
|
||||||
status = "상태"
|
status = "상태"
|
||||||
type = "유형"
|
type = "유형"
|
||||||
|
|
||||||
|
[ui.admin.tenants.create.parent_context]
|
||||||
|
general = "일반 하위 테넌트"
|
||||||
|
hanmac = "한맥가족 하위 테넌트"
|
||||||
|
pick_required = "상위 테넌트 선택 필요"
|
||||||
|
root = "최상위 테넌트"
|
||||||
|
|
||||||
[ui.admin.tenants.create.memo]
|
[ui.admin.tenants.create.memo]
|
||||||
title = "정책 메모"
|
title = "정책 메모"
|
||||||
|
|
||||||
@@ -1025,11 +1045,17 @@ allowed_domains_help = "이 도메인을 가진 이메일로 가입한 사용자
|
|||||||
approve_button = "테넌트 승인"
|
approve_button = "테넌트 승인"
|
||||||
description = "설명"
|
description = "설명"
|
||||||
name = "테넌트 이름"
|
name = "테넌트 이름"
|
||||||
|
org_unit_type = "조직 세부타입"
|
||||||
slug = "슬러그 (Slug)"
|
slug = "슬러그 (Slug)"
|
||||||
status = "상태"
|
status = "상태"
|
||||||
subtitle = "슬러그 및 상태 변경은 즉시 적용됩니다."
|
subtitle = "슬러그 및 상태 변경은 즉시 적용됩니다."
|
||||||
title = "테넌트 프로필"
|
title = "테넌트 프로필"
|
||||||
type = "테넌트 유형"
|
type = "테넌트 유형"
|
||||||
|
visibility = "공개 범위"
|
||||||
|
|
||||||
|
[ui.admin.tenants.parent]
|
||||||
|
local_search_placeholder = "테넌트 이름 또는 슬러그 검색"
|
||||||
|
pick_tenant = "테넌트 선택"
|
||||||
|
|
||||||
[ui.admin.tenants.registry]
|
[ui.admin.tenants.registry]
|
||||||
title = "Tenant registry"
|
title = "Tenant registry"
|
||||||
|
|||||||
@@ -208,6 +208,11 @@ subtitle = ""
|
|||||||
[msg.admin.tenants.import_preview]
|
[msg.admin.tenants.import_preview]
|
||||||
description = ""
|
description = ""
|
||||||
|
|
||||||
|
[msg.admin.tenants.parent]
|
||||||
|
local_picker_description = ""
|
||||||
|
local_picker_empty = ""
|
||||||
|
picker_description = ""
|
||||||
|
|
||||||
[msg.admin.tenants.admins]
|
[msg.admin.tenants.admins]
|
||||||
add_success = ""
|
add_success = ""
|
||||||
empty = ""
|
empty = ""
|
||||||
@@ -223,6 +228,7 @@ remove_success = ""
|
|||||||
subtitle = ""
|
subtitle = ""
|
||||||
|
|
||||||
[msg.admin.tenants.create]
|
[msg.admin.tenants.create]
|
||||||
|
pick_parent_first = ""
|
||||||
subtitle = ""
|
subtitle = ""
|
||||||
|
|
||||||
[msg.admin.tenants.create.form]
|
[msg.admin.tenants.create.form]
|
||||||
@@ -924,9 +930,14 @@ title = ""
|
|||||||
candidates = ""
|
candidates = ""
|
||||||
confirm = ""
|
confirm = ""
|
||||||
create_new_reset = ""
|
create_new_reset = ""
|
||||||
|
csv_parents = ""
|
||||||
external_id = ""
|
external_id = ""
|
||||||
match = ""
|
match = ""
|
||||||
no_candidates = ""
|
no_candidates = ""
|
||||||
|
parent = ""
|
||||||
|
parent_companies = ""
|
||||||
|
parent_company_groups = ""
|
||||||
|
parent_organizations = ""
|
||||||
parent_unresolved = ""
|
parent_unresolved = ""
|
||||||
slug_exists = ""
|
slug_exists = ""
|
||||||
title = ""
|
title = ""
|
||||||
@@ -973,11 +984,20 @@ domains_label = ""
|
|||||||
domains_placeholder = ""
|
domains_placeholder = ""
|
||||||
name = ""
|
name = ""
|
||||||
parent = ""
|
parent = ""
|
||||||
|
pick_hanmac_parent = ""
|
||||||
|
pick_other_parent = ""
|
||||||
|
root_tenant = ""
|
||||||
slug = ""
|
slug = ""
|
||||||
slug_placeholder = ""
|
slug_placeholder = ""
|
||||||
status = ""
|
status = ""
|
||||||
type = ""
|
type = ""
|
||||||
|
|
||||||
|
[ui.admin.tenants.create.parent_context]
|
||||||
|
general = ""
|
||||||
|
hanmac = ""
|
||||||
|
pick_required = ""
|
||||||
|
root = ""
|
||||||
|
|
||||||
[ui.admin.tenants.create.memo]
|
[ui.admin.tenants.create.memo]
|
||||||
title = ""
|
title = ""
|
||||||
|
|
||||||
@@ -1044,11 +1064,17 @@ allowed_domains_help = ""
|
|||||||
approve_button = ""
|
approve_button = ""
|
||||||
description = ""
|
description = ""
|
||||||
name = ""
|
name = ""
|
||||||
|
org_unit_type = ""
|
||||||
slug = ""
|
slug = ""
|
||||||
status = ""
|
status = ""
|
||||||
subtitle = ""
|
subtitle = ""
|
||||||
title = ""
|
title = ""
|
||||||
type = ""
|
type = ""
|
||||||
|
visibility = ""
|
||||||
|
|
||||||
|
[ui.admin.tenants.parent]
|
||||||
|
local_search_placeholder = ""
|
||||||
|
pick_tenant = ""
|
||||||
|
|
||||||
[ui.admin.tenants.registry]
|
[ui.admin.tenants.registry]
|
||||||
title = ""
|
title = ""
|
||||||
|
|||||||
@@ -110,9 +110,7 @@ test.describe("Tenants Management", () => {
|
|||||||
await expect(page.locator("h2").last()).toContainText(/추가|Create/i, {
|
await expect(page.locator("h2").last()).toContainText(/추가|Create/i, {
|
||||||
timeout: 20000,
|
timeout: 20000,
|
||||||
});
|
});
|
||||||
await page
|
await page.getByRole("button", { name: "최상위 테넌트로 생성" }).click();
|
||||||
.getByRole("button", { name: "최상위 테넌트로 생성" })
|
|
||||||
.click();
|
|
||||||
|
|
||||||
const nameInput = page.locator('input[name="name"]').first();
|
const nameInput = page.locator('input[name="name"]').first();
|
||||||
await nameInput.fill("New Tenant");
|
await nameInput.fill("New Tenant");
|
||||||
@@ -213,9 +211,7 @@ test.describe("Tenants Management", () => {
|
|||||||
{
|
{
|
||||||
type: "orgfront:picker:confirm",
|
type: "orgfront:picker:confirm",
|
||||||
payload: {
|
payload: {
|
||||||
selections: [
|
selections: [{ type: "tenant", id: "family-1", name: "한맥가족" }],
|
||||||
{ type: "tenant", id: "family-1", name: "한맥가족" },
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
window.location.origin,
|
window.location.origin,
|
||||||
@@ -260,7 +256,12 @@ test.describe("Tenants Management", () => {
|
|||||||
const headers = { "Access-Control-Allow-Origin": "*" };
|
const headers = { "Access-Control-Allow-Origin": "*" };
|
||||||
if (method === "GET") {
|
if (method === "GET") {
|
||||||
return route.fulfill({
|
return route.fulfill({
|
||||||
json: { items: tenants, total: tenants.length, limit: 1000, offset: 0 },
|
json: {
|
||||||
|
items: tenants,
|
||||||
|
total: tenants.length,
|
||||||
|
limit: 1000,
|
||||||
|
offset: 0,
|
||||||
|
},
|
||||||
headers,
|
headers,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -286,9 +287,7 @@ test.describe("Tenants Management", () => {
|
|||||||
{
|
{
|
||||||
type: "orgfront:picker:confirm",
|
type: "orgfront:picker:confirm",
|
||||||
payload: {
|
payload: {
|
||||||
selections: [
|
selections: [{ type: "tenant", id: "family-1", name: "한맥가족" }],
|
||||||
{ type: "tenant", id: "family-1", name: "한맥가족" },
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
window.location.origin,
|
window.location.origin,
|
||||||
@@ -309,8 +308,8 @@ test.describe("Tenants Management", () => {
|
|||||||
const visibilityWidth = await page
|
const visibilityWidth = await page
|
||||||
.getByTestId("tenant-visibility-slot")
|
.getByTestId("tenant-visibility-slot")
|
||||||
.evaluate((element) => element.getBoundingClientRect().width);
|
.evaluate((element) => element.getBoundingClientRect().width);
|
||||||
const columns = await layout.evaluate((element) =>
|
const columns = await layout.evaluate(
|
||||||
window.getComputedStyle(element).gridTemplateColumns,
|
(element) => window.getComputedStyle(element).gridTemplateColumns,
|
||||||
);
|
);
|
||||||
expect(columns.split(" ").length).toBe(4);
|
expect(columns.split(" ").length).toBe(4);
|
||||||
expect(parentWidth).toBeGreaterThan(orgUnitWidth * 1.7);
|
expect(parentWidth).toBeGreaterThan(orgUnitWidth * 1.7);
|
||||||
@@ -543,9 +542,7 @@ test.describe("Tenants Management", () => {
|
|||||||
await expect(page.locator("h2").last()).toContainText(/추가|Create/i, {
|
await expect(page.locator("h2").last()).toContainText(/추가|Create/i, {
|
||||||
timeout: 20000,
|
timeout: 20000,
|
||||||
});
|
});
|
||||||
await page
|
await page.getByRole("button", { name: "최상위 테넌트로 생성" }).click();
|
||||||
.getByRole("button", { name: "최상위 테넌트로 생성" })
|
|
||||||
.click();
|
|
||||||
|
|
||||||
const submitBtn = page.getByRole("button", { name: /^생성$/ });
|
const submitBtn = page.getByRole("button", { name: /^생성$/ });
|
||||||
await expect(submitBtn).toBeDisabled();
|
await expect(submitBtn).toBeDisabled();
|
||||||
@@ -715,8 +712,8 @@ test.describe("Tenants Management", () => {
|
|||||||
await expect(layout).toContainText("조직 세부타입");
|
await expect(layout).toContainText("조직 세부타입");
|
||||||
await expect(layout).toContainText("공개 범위");
|
await expect(layout).toContainText("공개 범위");
|
||||||
|
|
||||||
const columns = await layout.evaluate((element) =>
|
const columns = await layout.evaluate(
|
||||||
window.getComputedStyle(element).gridTemplateColumns,
|
(element) => window.getComputedStyle(element).gridTemplateColumns,
|
||||||
);
|
);
|
||||||
expect(columns.split(" ").length).toBe(4);
|
expect(columns.split(" ").length).toBe(4);
|
||||||
|
|
||||||
|
|||||||
@@ -419,6 +419,8 @@ func TestHeadlessPasswordLogin_E2E_ResponseIncludesDetailedCodeAndLogs(t *testin
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestHeadlessPasswordLogin_E2E_DebugLogsIncludeDiagnostics(t *testing.T) {
|
func TestHeadlessPasswordLogin_E2E_DebugLogsIncludeDiagnostics(t *testing.T) {
|
||||||
|
t.Setenv("BACKEND_PUBLIC_URL", "")
|
||||||
|
|
||||||
privateKey, jwks := mustE2EHeadlessRSAJWK(t)
|
privateKey, jwks := mustE2EHeadlessRSAJWK(t)
|
||||||
const receivedAudience = "https://sso.hmac.kr/api/v1/auth/headless/password/login"
|
const receivedAudience = "https://sso.hmac.kr/api/v1/auth/headless/password/login"
|
||||||
clientAssertion := mustE2EHeadlessClientAssertion(
|
clientAssertion := mustE2EHeadlessClientAssertion(
|
||||||
@@ -458,6 +460,8 @@ func TestHeadlessPasswordLogin_E2E_DebugLogsIncludeDiagnostics(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestHeadlessPasswordLogin_E2E_AcceptsForwardedHTTPSAudience(t *testing.T) {
|
func TestHeadlessPasswordLogin_E2E_AcceptsForwardedHTTPSAudience(t *testing.T) {
|
||||||
|
t.Setenv("BACKEND_PUBLIC_URL", "")
|
||||||
|
|
||||||
privateKey, jwks := mustE2EHeadlessRSAJWK(t)
|
privateKey, jwks := mustE2EHeadlessRSAJWK(t)
|
||||||
const receivedAudience = "https://sso.hmac.kr/api/v1/auth/headless/password/login"
|
const receivedAudience = "https://sso.hmac.kr/api/v1/auth/headless/password/login"
|
||||||
clientAssertion := mustE2EHeadlessClientAssertion(
|
clientAssertion := mustE2EHeadlessClientAssertion(
|
||||||
|
|||||||
@@ -894,6 +894,8 @@ func TestHeadlessPasswordLogin_HeadlessLoginClientSuccess(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestHeadlessPasswordLogin_AuditIncludesClientMetadata(t *testing.T) {
|
func TestHeadlessPasswordLogin_AuditIncludesClientMetadata(t *testing.T) {
|
||||||
|
t.Setenv("BACKEND_PUBLIC_URL", "")
|
||||||
|
|
||||||
mockIdp := new(MockIdentityProvider)
|
mockIdp := new(MockIdentityProvider)
|
||||||
mockIdp.On("SignIn", "employee001", "password").Return(&domain.AuthInfo{
|
mockIdp.On("SignIn", "employee001", "password").Return(&domain.AuthInfo{
|
||||||
SessionToken: &domain.Token{JWT: "valid-jwt", SessionID: "session-123"},
|
SessionToken: &domain.Token{JWT: "valid-jwt", SessionID: "session-123"},
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestRPManifestJSONIncludesIAMAndExternalKeyContract(t *testing.T) {
|
func TestRPManifestJSONIncludesIAMAndExternalKeyContract(t *testing.T) {
|
||||||
|
t.Setenv("BACKEND_PUBLIC_URL", "")
|
||||||
|
|
||||||
app := fiber.New()
|
app := fiber.New()
|
||||||
h := NewRPManifestHandler()
|
h := NewRPManifestHandler()
|
||||||
app.Get("/.well-known/baron-rp-manifest.json", h.GetJSON)
|
app.Get("/.well-known/baron-rp-manifest.json", h.GetJSON)
|
||||||
|
|||||||
@@ -112,6 +112,7 @@ func (m *MockUserRepoForHandler) Delete(ctx context.Context, id string) error {
|
|||||||
m.deletedIDs = append(m.deletedIDs, id)
|
m.deletedIDs = append(m.deletedIDs, id)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MockUserRepoForHandler) FindByEmail(ctx context.Context, email string) (*domain.User, error) {
|
func (m *MockUserRepoForHandler) FindByEmail(ctx context.Context, email string) (*domain.User, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ func (m *MockUserRepository) Update(ctx context.Context, user *domain.User) erro
|
|||||||
m.updatedUsers = append(m.updatedUsers, copied)
|
m.updatedUsers = append(m.updatedUsers, copied)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MockUserRepository) Delete(ctx context.Context, id string) error {
|
func (m *MockUserRepository) Delete(ctx context.Context, id string) error {
|
||||||
return m.Called(ctx, id).Error(0)
|
return m.Called(ctx, id).Error(0)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -213,6 +213,8 @@ func TestResolveWorksmobileDomainIDFromTenantIgnoresRootDomainMappings(t *testin
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestResolveWorksmobileDomainIDFromTenantRequiresFamilyDomainEnv(t *testing.T) {
|
func TestResolveWorksmobileDomainIDFromTenantRequiresFamilyDomainEnv(t *testing.T) {
|
||||||
|
t.Setenv("SAMAN_DOMAIN_ID", "")
|
||||||
|
|
||||||
rootConfig := domain.JSONMap{
|
rootConfig := domain.JSONMap{
|
||||||
"worksmobile": map[string]any{
|
"worksmobile": map[string]any{
|
||||||
"domainMappings": map[string]any{
|
"domainMappings": map[string]any{
|
||||||
|
|||||||
@@ -1,5 +1,12 @@
|
|||||||
|
import { createRequire } from "node:module";
|
||||||
import { defineConfig, devices } from "@playwright/test";
|
import { defineConfig, devices } from "@playwright/test";
|
||||||
|
|
||||||
|
const require = createRequire(import.meta.url);
|
||||||
|
const { shouldIncludeWebKit } =
|
||||||
|
require("../scripts/playwrightHostDeps.cjs") as {
|
||||||
|
shouldIncludeWebKit: () => boolean;
|
||||||
|
};
|
||||||
|
|
||||||
const configuredWorkers = process.env.PLAYWRIGHT_WORKERS
|
const configuredWorkers = process.env.PLAYWRIGHT_WORKERS
|
||||||
? Number.parseInt(process.env.PLAYWRIGHT_WORKERS, 10)
|
? Number.parseInt(process.env.PLAYWRIGHT_WORKERS, 10)
|
||||||
: undefined;
|
: undefined;
|
||||||
@@ -52,10 +59,14 @@ export default defineConfig({
|
|||||||
use: { ...devices["Desktop Firefox"] },
|
use: { ...devices["Desktop Firefox"] },
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
...(shouldIncludeWebKit()
|
||||||
name: "webkit",
|
? [
|
||||||
use: { ...devices["Desktop Safari"] },
|
{
|
||||||
},
|
name: "webkit",
|
||||||
|
use: { ...devices["Desktop Safari"] },
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: []),
|
||||||
],
|
],
|
||||||
|
|
||||||
/* Run your local dev server before starting the tests */
|
/* Run your local dev server before starting the tests */
|
||||||
|
|||||||
@@ -35,6 +35,29 @@ if [ "${1:-}" = "--print-mode" ]; then
|
|||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
ensure_frontend_dependencies() {
|
||||||
|
if [ ! -f package.json ] || [ ! -f package-lock.json ]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v sha256sum >/dev/null 2>&1; then
|
||||||
|
deps_hash="$(sha256sum package.json package-lock.json | sha256sum | awk '{print $1}')"
|
||||||
|
else
|
||||||
|
deps_hash="$(cksum package.json package-lock.json | cksum | awk '{print $1}')"
|
||||||
|
fi
|
||||||
|
deps_stamp="node_modules/.baron-deps-hash"
|
||||||
|
installed_hash="$(cat "$deps_stamp" 2>/dev/null || true)"
|
||||||
|
|
||||||
|
if [ "$installed_hash" != "$deps_hash" ]; then
|
||||||
|
echo "Installing frontend dependencies from package-lock.json..."
|
||||||
|
npm ci
|
||||||
|
mkdir -p node_modules
|
||||||
|
printf '%s\n' "$deps_hash" > "$deps_stamp"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_frontend_dependencies
|
||||||
|
|
||||||
if [ "$mode" = "production" ]; then
|
if [ "$mode" = "production" ]; then
|
||||||
echo "Running in production mode with Vite preview..."
|
echo "Running in production mode with Vite preview..."
|
||||||
exec sh -c "npm run build && npm run preview -- --host 0.0.0.0"
|
exec sh -c "npm run build && npm run preview -- --host 0.0.0.0"
|
||||||
|
|||||||
@@ -208,6 +208,11 @@ subtitle = "Review registered tenants and manage their current status."
|
|||||||
[msg.admin.tenants.import_preview]
|
[msg.admin.tenants.import_preview]
|
||||||
description = "Rows without tenant_id are compared with existing tenant candidates, then imported as new tenants or updates."
|
description = "Rows without tenant_id are compared with existing tenant candidates, then imported as new tenants or updates."
|
||||||
|
|
||||||
|
[msg.admin.tenants.parent]
|
||||||
|
local_picker_description = "Select the tenant to use as the parent from the tenant list."
|
||||||
|
local_picker_empty = "No selectable tenants are available."
|
||||||
|
picker_description = "Select a tenant in org-chart to apply it as the parent tenant."
|
||||||
|
|
||||||
[msg.admin.tenants.admins]
|
[msg.admin.tenants.admins]
|
||||||
add_success = "Tenant admin added successfully."
|
add_success = "Tenant admin added successfully."
|
||||||
empty = "No tenant admins are assigned yet."
|
empty = "No tenant admins are assigned yet."
|
||||||
@@ -218,6 +223,7 @@ remove_success = "Tenant admin removed successfully."
|
|||||||
subtitle = "Manage the administrators assigned to this tenant."
|
subtitle = "Manage the administrators assigned to this tenant."
|
||||||
|
|
||||||
[msg.admin.tenants.create]
|
[msg.admin.tenants.create]
|
||||||
|
pick_parent_first = "Select the parent tenant first."
|
||||||
subtitle = "Enter the minimum required information to create a tenant."
|
subtitle = "Enter the minimum required information to create a tenant."
|
||||||
|
|
||||||
[msg.admin.tenants.create.form]
|
[msg.admin.tenants.create.form]
|
||||||
@@ -1124,9 +1130,14 @@ title = "Domain conflict"
|
|||||||
candidates = "Candidates"
|
candidates = "Candidates"
|
||||||
confirm = "Run import"
|
confirm = "Run import"
|
||||||
create_new_reset = "Create new (reset ID/slug)"
|
create_new_reset = "Create new (reset ID/slug)"
|
||||||
|
csv_parents = "CSV Parents"
|
||||||
external_id = "External ID"
|
external_id = "External ID"
|
||||||
match = "Match"
|
match = "Match"
|
||||||
no_candidates = "No candidates"
|
no_candidates = "No candidates"
|
||||||
|
parent = "Parent"
|
||||||
|
parent_companies = "Parent Companies"
|
||||||
|
parent_company_groups = "Parent Company Groups"
|
||||||
|
parent_organizations = "Parent Organizations"
|
||||||
parent_unresolved = "Parent needs review"
|
parent_unresolved = "Parent needs review"
|
||||||
slug_exists = "slug conflict"
|
slug_exists = "slug conflict"
|
||||||
title = "Confirm CSV import"
|
title = "Confirm CSV import"
|
||||||
@@ -1163,11 +1174,20 @@ domains_placeholder = "example.com, example.kr"
|
|||||||
name = "Tenant name"
|
name = "Tenant name"
|
||||||
name_placeholder = "Enter tenant name"
|
name_placeholder = "Enter tenant name"
|
||||||
parent = "Parent"
|
parent = "Parent"
|
||||||
|
pick_hanmac_parent = "Pick from Hanmac Family"
|
||||||
|
pick_other_parent = "Pick another tenant"
|
||||||
|
root_tenant = "Create as top-level tenant"
|
||||||
slug = "Slug"
|
slug = "Slug"
|
||||||
slug_placeholder = "tenant-slug"
|
slug_placeholder = "tenant-slug"
|
||||||
status = "Status"
|
status = "Status"
|
||||||
type = "Type"
|
type = "Type"
|
||||||
|
|
||||||
|
[ui.admin.tenants.create.parent_context]
|
||||||
|
general = "General child tenant"
|
||||||
|
hanmac = "Hanmac Family child tenant"
|
||||||
|
pick_required = "Parent tenant selection required"
|
||||||
|
root = "Top-level tenant"
|
||||||
|
|
||||||
[ui.admin.tenants.create.memo]
|
[ui.admin.tenants.create.memo]
|
||||||
title = "Policy Memo"
|
title = "Policy Memo"
|
||||||
|
|
||||||
@@ -1249,9 +1269,14 @@ view_profile = "View Profile"
|
|||||||
candidates = "Candidates"
|
candidates = "Candidates"
|
||||||
confirm = "Confirm Import"
|
confirm = "Confirm Import"
|
||||||
create_new = "Create New"
|
create_new = "Create New"
|
||||||
|
csv_parents = "CSV Parents"
|
||||||
fixed_id = "Fixed ID"
|
fixed_id = "Fixed ID"
|
||||||
match = "Matched Tenant"
|
match = "Matched Tenant"
|
||||||
no_candidates = "No matching tenants found."
|
no_candidates = "No matching tenants found."
|
||||||
|
parent = "Parent"
|
||||||
|
parent_companies = "Parent Companies"
|
||||||
|
parent_company_groups = "Parent Company Groups"
|
||||||
|
parent_organizations = "Parent Organizations"
|
||||||
title = "Import Preview"
|
title = "Import Preview"
|
||||||
|
|
||||||
[ui.admin.tenants.members.table]
|
[ui.admin.tenants.members.table]
|
||||||
@@ -1278,16 +1303,22 @@ allowed_domains_help = "Users with these email domains will be automatically ass
|
|||||||
approve_button = "Approve Tenant"
|
approve_button = "Approve Tenant"
|
||||||
description = "Review and edit the tenant's basic profile information."
|
description = "Review and edit the tenant's basic profile information."
|
||||||
name = "Tenant Name"
|
name = "Tenant Name"
|
||||||
|
org_unit_type = "Organization detail type"
|
||||||
slug = "Slug"
|
slug = "Slug"
|
||||||
status = "Status"
|
status = "Status"
|
||||||
subtitle = "Slug and status changes are applied immediately."
|
subtitle = "Slug and status changes are applied immediately."
|
||||||
title = "Tenant Profile"
|
title = "Tenant Profile"
|
||||||
type = "Type"
|
type = "Type"
|
||||||
|
visibility = "Visibility"
|
||||||
|
|
||||||
[ui.admin.tenants.profile.form]
|
[ui.admin.tenants.profile.form]
|
||||||
parent = "Parent Tenant (Optional)"
|
parent = "Parent Tenant (Optional)"
|
||||||
parent_help = "Select a parent tenant if this is a subsidiary or sub-organization."
|
parent_help = "Select a parent tenant if this is a subsidiary or sub-organization."
|
||||||
|
|
||||||
|
[ui.admin.tenants.parent]
|
||||||
|
local_search_placeholder = "Search tenant name or slug"
|
||||||
|
pick_tenant = "Pick tenant"
|
||||||
|
|
||||||
[ui.admin.tenants.registry]
|
[ui.admin.tenants.registry]
|
||||||
title = "Tenant registry"
|
title = "Tenant registry"
|
||||||
|
|
||||||
|
|||||||
@@ -120,6 +120,11 @@ subtitle = "현재 등록된 테넌트를 확인하고 상태를 관리합니다
|
|||||||
[msg.admin.tenants.import_preview]
|
[msg.admin.tenants.import_preview]
|
||||||
description = "tenant_id가 없는 행은 기존 테넌트 후보와 비교한 뒤 신규 생성 또는 기존 테넌트 갱신으로 처리합니다."
|
description = "tenant_id가 없는 행은 기존 테넌트 후보와 비교한 뒤 신규 생성 또는 기존 테넌트 갱신으로 처리합니다."
|
||||||
|
|
||||||
|
[msg.admin.tenants.parent]
|
||||||
|
local_picker_description = "테넌트 목록에서 상위 테넌트로 사용할 항목을 선택합니다."
|
||||||
|
local_picker_empty = "선택할 수 있는 테넌트가 없습니다."
|
||||||
|
picker_description = "org-chart에서 테넌트를 선택하면 상위 테넌트에 반영됩니다."
|
||||||
|
|
||||||
[msg.dev.auth]
|
[msg.dev.auth]
|
||||||
access_denied_description = "DevFront는 관리자 전용 화면입니다. 권한이 필요하면 관리자에게 요청해 주세요."
|
access_denied_description = "DevFront는 관리자 전용 화면입니다. 권한이 필요하면 관리자에게 요청해 주세요."
|
||||||
access_denied_title = "접근 권한이 없습니다."
|
access_denied_title = "접근 권한이 없습니다."
|
||||||
@@ -368,9 +373,14 @@ title = "도메인 충돌"
|
|||||||
candidates = "후보"
|
candidates = "후보"
|
||||||
confirm = "가져오기 실행"
|
confirm = "가져오기 실행"
|
||||||
create_new_reset = "신규 생성 (ID/slug 재설정)"
|
create_new_reset = "신규 생성 (ID/slug 재설정)"
|
||||||
|
csv_parents = "CSV 상위 테넌트"
|
||||||
external_id = "외부 ID"
|
external_id = "외부 ID"
|
||||||
match = "매칭"
|
match = "매칭"
|
||||||
no_candidates = "후보 없음"
|
no_candidates = "후보 없음"
|
||||||
|
parent = "상위"
|
||||||
|
parent_companies = "상위 회사"
|
||||||
|
parent_company_groups = "상위 그룹사"
|
||||||
|
parent_organizations = "상위 조직"
|
||||||
parent_unresolved = "부모 확인 필요"
|
parent_unresolved = "부모 확인 필요"
|
||||||
slug_exists = "slug 충돌"
|
slug_exists = "slug 충돌"
|
||||||
title = "CSV 가져오기 확인"
|
title = "CSV 가져오기 확인"
|
||||||
@@ -699,6 +709,7 @@ remove_success = "권한이 회수되었습니다."
|
|||||||
subtitle = "이 테넌트의 자원을 관리할 수 있는 사용자 목록입니다."
|
subtitle = "이 테넌트의 자원을 관리할 수 있는 사용자 목록입니다."
|
||||||
|
|
||||||
[msg.admin.tenants.create]
|
[msg.admin.tenants.create]
|
||||||
|
pick_parent_first = "상위 테넌트를 먼저 선택하세요."
|
||||||
subtitle = "글로벌 운영 기준의 신규 테넌트를 등록합니다."
|
subtitle = "글로벌 운영 기준의 신규 테넌트를 등록합니다."
|
||||||
|
|
||||||
[msg.admin.tenants.create.form]
|
[msg.admin.tenants.create.form]
|
||||||
@@ -1623,11 +1634,20 @@ domains_placeholder = "example.com, example.kr"
|
|||||||
name = "테넌트 이름"
|
name = "테넌트 이름"
|
||||||
name_placeholder = "테넌트 이름을 입력하세요"
|
name_placeholder = "테넌트 이름을 입력하세요"
|
||||||
parent = "상위 테넌트"
|
parent = "상위 테넌트"
|
||||||
|
pick_hanmac_parent = "한맥가족에서 선택"
|
||||||
|
pick_other_parent = "다른 테넌트 선택"
|
||||||
|
root_tenant = "최상위 테넌트로 생성"
|
||||||
slug = "Slug"
|
slug = "Slug"
|
||||||
slug_placeholder = "tenant-slug"
|
slug_placeholder = "tenant-slug"
|
||||||
status = "상태"
|
status = "상태"
|
||||||
type = "유형"
|
type = "유형"
|
||||||
|
|
||||||
|
[ui.admin.tenants.create.parent_context]
|
||||||
|
general = "일반 하위 테넌트"
|
||||||
|
hanmac = "한맥가족 하위 테넌트"
|
||||||
|
pick_required = "상위 테넌트 선택 필요"
|
||||||
|
root = "최상위 테넌트"
|
||||||
|
|
||||||
[ui.admin.tenants.create.memo]
|
[ui.admin.tenants.create.memo]
|
||||||
title = "정책 메모"
|
title = "정책 메모"
|
||||||
|
|
||||||
@@ -1711,9 +1731,14 @@ view_profile = "상세 정보"
|
|||||||
candidates = "후보"
|
candidates = "후보"
|
||||||
confirm = "임포트 확정"
|
confirm = "임포트 확정"
|
||||||
create_new = "새로 생성"
|
create_new = "새로 생성"
|
||||||
|
csv_parents = "CSV 상위 테넌트"
|
||||||
fixed_id = "고정 ID"
|
fixed_id = "고정 ID"
|
||||||
match = "매칭된 테넌트"
|
match = "매칭된 테넌트"
|
||||||
no_candidates = "매칭 가능한 테넌트가 없습니다."
|
no_candidates = "매칭 가능한 테넌트가 없습니다."
|
||||||
|
parent = "상위"
|
||||||
|
parent_companies = "상위 회사"
|
||||||
|
parent_company_groups = "상위 그룹사"
|
||||||
|
parent_organizations = "상위 조직"
|
||||||
title = "임포트 미리보기"
|
title = "임포트 미리보기"
|
||||||
|
|
||||||
[ui.admin.tenants.members.table]
|
[ui.admin.tenants.members.table]
|
||||||
@@ -1740,16 +1765,22 @@ allowed_domains_help = "이 도메인을 가진 이메일로 가입한 사용자
|
|||||||
approve_button = "테넌트 승인"
|
approve_button = "테넌트 승인"
|
||||||
description = "설명"
|
description = "설명"
|
||||||
name = "테넌트 이름"
|
name = "테넌트 이름"
|
||||||
|
org_unit_type = "조직 세부타입"
|
||||||
slug = "슬러그 (Slug)"
|
slug = "슬러그 (Slug)"
|
||||||
status = "상태"
|
status = "상태"
|
||||||
subtitle = "슬러그 및 상태 변경은 즉시 적용됩니다."
|
subtitle = "슬러그 및 상태 변경은 즉시 적용됩니다."
|
||||||
title = "테넌트 프로필"
|
title = "테넌트 프로필"
|
||||||
type = "테넌트 유형"
|
type = "테넌트 유형"
|
||||||
|
visibility = "공개 범위"
|
||||||
|
|
||||||
[ui.admin.tenants.profile.form]
|
[ui.admin.tenants.profile.form]
|
||||||
parent = "상위 테넌트 (선택)"
|
parent = "상위 테넌트 (선택)"
|
||||||
parent_help = "가족사 테넌트나 하위 조직을 종속시킬 경우 상위 테넌트를 선택해주세요."
|
parent_help = "가족사 테넌트나 하위 조직을 종속시킬 경우 상위 테넌트를 선택해주세요."
|
||||||
|
|
||||||
|
[ui.admin.tenants.parent]
|
||||||
|
local_search_placeholder = "테넌트 이름 또는 슬러그 검색"
|
||||||
|
pick_tenant = "테넌트 선택"
|
||||||
|
|
||||||
[ui.admin.tenants.registry]
|
[ui.admin.tenants.registry]
|
||||||
title = "Tenant registry"
|
title = "Tenant registry"
|
||||||
|
|
||||||
|
|||||||
@@ -237,9 +237,14 @@ title = ""
|
|||||||
candidates = ""
|
candidates = ""
|
||||||
confirm = ""
|
confirm = ""
|
||||||
create_new_reset = ""
|
create_new_reset = ""
|
||||||
|
csv_parents = ""
|
||||||
external_id = ""
|
external_id = ""
|
||||||
match = ""
|
match = ""
|
||||||
no_candidates = ""
|
no_candidates = ""
|
||||||
|
parent = ""
|
||||||
|
parent_companies = ""
|
||||||
|
parent_company_groups = ""
|
||||||
|
parent_organizations = ""
|
||||||
parent_unresolved = ""
|
parent_unresolved = ""
|
||||||
slug_exists = ""
|
slug_exists = ""
|
||||||
title = ""
|
title = ""
|
||||||
@@ -568,6 +573,7 @@ remove_success = ""
|
|||||||
subtitle = ""
|
subtitle = ""
|
||||||
|
|
||||||
[msg.admin.tenants.create]
|
[msg.admin.tenants.create]
|
||||||
|
pick_parent_first = ""
|
||||||
subtitle = ""
|
subtitle = ""
|
||||||
|
|
||||||
[msg.admin.tenants.create.form]
|
[msg.admin.tenants.create.form]
|
||||||
@@ -1492,11 +1498,20 @@ domains_placeholder = ""
|
|||||||
name = ""
|
name = ""
|
||||||
name_placeholder = ""
|
name_placeholder = ""
|
||||||
parent = ""
|
parent = ""
|
||||||
|
pick_hanmac_parent = ""
|
||||||
|
pick_other_parent = ""
|
||||||
|
root_tenant = ""
|
||||||
slug = ""
|
slug = ""
|
||||||
slug_placeholder = ""
|
slug_placeholder = ""
|
||||||
status = ""
|
status = ""
|
||||||
type = ""
|
type = ""
|
||||||
|
|
||||||
|
[ui.admin.tenants.create.parent_context]
|
||||||
|
general = ""
|
||||||
|
hanmac = ""
|
||||||
|
pick_required = ""
|
||||||
|
root = ""
|
||||||
|
|
||||||
[ui.admin.tenants.create.memo]
|
[ui.admin.tenants.create.memo]
|
||||||
title = ""
|
title = ""
|
||||||
|
|
||||||
@@ -1565,6 +1580,11 @@ seed_delete_blocked = ""
|
|||||||
[msg.admin.tenants.import_preview]
|
[msg.admin.tenants.import_preview]
|
||||||
description = ""
|
description = ""
|
||||||
|
|
||||||
|
[msg.admin.tenants.parent]
|
||||||
|
local_picker_description = ""
|
||||||
|
local_picker_empty = ""
|
||||||
|
picker_description = ""
|
||||||
|
|
||||||
[msg.admin.users]
|
[msg.admin.users]
|
||||||
self_delete_blocked = ""
|
self_delete_blocked = ""
|
||||||
export_error = ""
|
export_error = ""
|
||||||
@@ -1610,16 +1630,22 @@ allowed_domains_help = ""
|
|||||||
approve_button = ""
|
approve_button = ""
|
||||||
description = ""
|
description = ""
|
||||||
name = ""
|
name = ""
|
||||||
|
org_unit_type = ""
|
||||||
slug = ""
|
slug = ""
|
||||||
status = ""
|
status = ""
|
||||||
subtitle = ""
|
subtitle = ""
|
||||||
title = ""
|
title = ""
|
||||||
type = ""
|
type = ""
|
||||||
|
visibility = ""
|
||||||
|
|
||||||
[ui.admin.tenants.profile.form]
|
[ui.admin.tenants.profile.form]
|
||||||
parent = ""
|
parent = ""
|
||||||
parent_help = ""
|
parent_help = ""
|
||||||
|
|
||||||
|
[ui.admin.tenants.parent]
|
||||||
|
local_search_placeholder = ""
|
||||||
|
pick_tenant = ""
|
||||||
|
|
||||||
[ui.admin.tenants.registry]
|
[ui.admin.tenants.registry]
|
||||||
title = ""
|
title = ""
|
||||||
|
|
||||||
@@ -1662,9 +1688,14 @@ tree_search_placeholder = ""
|
|||||||
candidates = ""
|
candidates = ""
|
||||||
confirm = ""
|
confirm = ""
|
||||||
create_new = ""
|
create_new = ""
|
||||||
|
csv_parents = ""
|
||||||
fixed_id = ""
|
fixed_id = ""
|
||||||
match = ""
|
match = ""
|
||||||
no_candidates = ""
|
no_candidates = ""
|
||||||
|
parent = ""
|
||||||
|
parent_companies = ""
|
||||||
|
parent_company_groups = ""
|
||||||
|
parent_organizations = ""
|
||||||
title = ""
|
title = ""
|
||||||
|
|
||||||
[ui.admin.tenants.sub.table]
|
[ui.admin.tenants.sub.table]
|
||||||
|
|||||||
@@ -1,5 +1,12 @@
|
|||||||
|
import { createRequire } from "node:module";
|
||||||
import { defineConfig, devices } from "@playwright/test";
|
import { defineConfig, devices } from "@playwright/test";
|
||||||
|
|
||||||
|
const require = createRequire(import.meta.url);
|
||||||
|
const { shouldIncludeWebKit } =
|
||||||
|
require("../scripts/playwrightHostDeps.cjs") as {
|
||||||
|
shouldIncludeWebKit: () => boolean;
|
||||||
|
};
|
||||||
|
|
||||||
const configuredWorkers = process.env.PLAYWRIGHT_WORKERS
|
const configuredWorkers = process.env.PLAYWRIGHT_WORKERS
|
||||||
? Number.parseInt(process.env.PLAYWRIGHT_WORKERS, 10)
|
? Number.parseInt(process.env.PLAYWRIGHT_WORKERS, 10)
|
||||||
: undefined;
|
: undefined;
|
||||||
@@ -58,10 +65,14 @@ export default defineConfig({
|
|||||||
use: { ...devices["Desktop Firefox"] },
|
use: { ...devices["Desktop Firefox"] },
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
...(shouldIncludeWebKit()
|
||||||
name: "webkit",
|
? [
|
||||||
use: { ...devices["Desktop Safari"] },
|
{
|
||||||
},
|
name: "webkit",
|
||||||
|
use: { ...devices["Desktop Safari"] },
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: []),
|
||||||
],
|
],
|
||||||
|
|
||||||
/* Run your local dev server before starting the tests */
|
/* Run your local dev server before starting the tests */
|
||||||
|
|||||||
@@ -35,6 +35,29 @@ if [ "${1:-}" = "--print-mode" ]; then
|
|||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
ensure_frontend_dependencies() {
|
||||||
|
if [ ! -f package.json ] || [ ! -f package-lock.json ]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v sha256sum >/dev/null 2>&1; then
|
||||||
|
deps_hash="$(sha256sum package.json package-lock.json | sha256sum | awk '{print $1}')"
|
||||||
|
else
|
||||||
|
deps_hash="$(cksum package.json package-lock.json | cksum | awk '{print $1}')"
|
||||||
|
fi
|
||||||
|
deps_stamp="node_modules/.baron-deps-hash"
|
||||||
|
installed_hash="$(cat "$deps_stamp" 2>/dev/null || true)"
|
||||||
|
|
||||||
|
if [ "$installed_hash" != "$deps_hash" ]; then
|
||||||
|
echo "Installing frontend dependencies from package-lock.json..."
|
||||||
|
npm ci
|
||||||
|
mkdir -p node_modules
|
||||||
|
printf '%s\n' "$deps_hash" > "$deps_stamp"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_frontend_dependencies
|
||||||
|
|
||||||
if [ "$mode" = "production" ]; then
|
if [ "$mode" = "production" ]; then
|
||||||
echo "Running in production mode with Vite preview..."
|
echo "Running in production mode with Vite preview..."
|
||||||
exec sh -c "npm run build && npm run preview -- --host 0.0.0.0 --port 5175"
|
exec sh -c "npm run build && npm run preview -- --host 0.0.0.0 --port 5175"
|
||||||
|
|||||||
@@ -46,9 +46,7 @@ describe("hanmac family organization order", () => {
|
|||||||
|
|
||||||
it("does not rank generic technical centers as GPDTDC", () => {
|
it("does not rank generic technical centers as GPDTDC", () => {
|
||||||
expect(
|
expect(
|
||||||
getHanmacFamilyTenantOrderRank(
|
getHanmacFamilyTenantOrderRank(tenant("기술개발센터", "rnd-center")),
|
||||||
tenant("기술개발센터", "rnd-center"),
|
|
||||||
),
|
|
||||||
).toBe(Number.MAX_SAFE_INTEGER);
|
).toBe(Number.MAX_SAFE_INTEGER);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -51,10 +51,9 @@ function tenantToPickerNode(
|
|||||||
tenant: TenantNode,
|
tenant: TenantNode,
|
||||||
usersBySlug: Map<string, UserSummary[]>,
|
usersBySlug: Map<string, UserSummary[]>,
|
||||||
): OrgPickerTreeNode {
|
): OrgPickerTreeNode {
|
||||||
const tenantChildren = orderHanmacFamilyChildren(
|
const tenantChildren = orderHanmacFamilyChildren(tenant, tenant.children).map(
|
||||||
tenant,
|
(child) => tenantToPickerNode(child, usersBySlug),
|
||||||
tenant.children,
|
);
|
||||||
).map((child) => tenantToPickerNode(child, usersBySlug));
|
|
||||||
const userChildren = (usersBySlug.get(tenant.slug.toLowerCase()) || []).map(
|
const userChildren = (usersBySlug.get(tenant.slug.toLowerCase()) || []).map(
|
||||||
(user) => ({
|
(user) => ({
|
||||||
type: "user" as const,
|
type: "user" as const,
|
||||||
|
|||||||
@@ -1032,12 +1032,11 @@ export function buildOrgSelectionOptions(
|
|||||||
(familyRoot?.children ?? []).filter((node) =>
|
(familyRoot?.children ?? []).filter((node) =>
|
||||||
["COMPANY_GROUP", "COMPANY", "ORGANIZATION"].includes(node.type),
|
["COMPANY_GROUP", "COMPANY", "ORGANIZATION"].includes(node.type),
|
||||||
),
|
),
|
||||||
)
|
).map((node) => ({
|
||||||
.map((node) => ({
|
descendants: collectOrgSelectionDescendants(node, 2),
|
||||||
descendants: collectOrgSelectionDescendants(node, 2),
|
id: node.id,
|
||||||
id: node.id,
|
label: node.name,
|
||||||
label: node.name,
|
}));
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getOrgSelectionLabel(
|
function getOrgSelectionLabel(
|
||||||
|
|||||||
60
scripts/playwrightHostDeps.cjs
Normal file
60
scripts/playwrightHostDeps.cjs
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
const { execFileSync } = require("node:child_process");
|
||||||
|
|
||||||
|
const webkitHostLibraries = [
|
||||||
|
"libgtk-4.so.1",
|
||||||
|
"libgraphene-1.0.so.0",
|
||||||
|
"libxslt.so.1",
|
||||||
|
"libevent-2.1.so.7",
|
||||||
|
"libopus.so.0",
|
||||||
|
"libgstallocators-1.0.so.0",
|
||||||
|
"libgstapp-1.0.so.0",
|
||||||
|
"libgstpbutils-1.0.so.0",
|
||||||
|
"libgstaudio-1.0.so.0",
|
||||||
|
"libgsttag-1.0.so.0",
|
||||||
|
"libgstvideo-1.0.so.0",
|
||||||
|
"libgstgl-1.0.so.0",
|
||||||
|
"libgstcodecparsers-1.0.so.0",
|
||||||
|
"libgstfft-1.0.so.0",
|
||||||
|
"libflite.so.1",
|
||||||
|
"libwebpdemux.so.2",
|
||||||
|
"libavif.so.16",
|
||||||
|
"libharfbuzz-icu.so.0",
|
||||||
|
"libwebpmux.so.3",
|
||||||
|
"libwayland-server.so.0",
|
||||||
|
"libmanette-0.2.so.0",
|
||||||
|
"libenchant-2.so.2",
|
||||||
|
"libhyphen.so.0",
|
||||||
|
"libsecret-1.so.0",
|
||||||
|
"libwoff2dec.so.1.0.2",
|
||||||
|
"libx264.so",
|
||||||
|
];
|
||||||
|
|
||||||
|
function hasWebKitHostDependencies() {
|
||||||
|
if (process.platform !== "linux") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let output = "";
|
||||||
|
try {
|
||||||
|
output = execFileSync("ldconfig", ["-p"], { encoding: "utf8" });
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return webkitHostLibraries.every((library) => output.includes(library));
|
||||||
|
}
|
||||||
|
|
||||||
|
function shouldIncludeWebKit() {
|
||||||
|
if (process.env.PLAYWRIGHT_FORCE_WEBKIT === "1") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (process.env.PLAYWRIGHT_SKIP_WEBKIT === "1") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return hasWebKitHostDependencies();
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
hasWebKitHostDependencies,
|
||||||
|
shouldIncludeWebKit,
|
||||||
|
};
|
||||||
@@ -18,6 +18,8 @@ rm -rf adminfront/node_modules
|
|||||||
|
|
||||||
tmp_dir="$(mktemp -d /tmp/baron-sso-adminfront-tests.XXXXXX)"
|
tmp_dir="$(mktemp -d /tmp/baron-sso-adminfront-tests.XXXXXX)"
|
||||||
playwright_browsers_path="$tmp_dir/ms-playwright"
|
playwright_browsers_path="$tmp_dir/ms-playwright"
|
||||||
|
mkdir -p "$tmp_dir/scripts"
|
||||||
|
cp "$repo_root/scripts/playwrightHostDeps.cjs" "$tmp_dir/scripts/"
|
||||||
|
|
||||||
if command -v rsync >/dev/null 2>&1; then
|
if command -v rsync >/dev/null 2>&1; then
|
||||||
rsync -rlptD --delete \
|
rsync -rlptD --delete \
|
||||||
@@ -58,6 +60,53 @@ find_available_port() {
|
|||||||
|
|
||||||
playwright_install_cmd=(npx playwright install)
|
playwright_install_cmd=(npx playwright install)
|
||||||
playwright_install_desc="npx playwright install"
|
playwright_install_desc="npx playwright install"
|
||||||
|
playwright_project_args=()
|
||||||
|
|
||||||
|
has_webkit_host_dependencies() {
|
||||||
|
if [ "$(uname -s)" != "Linux" ]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if ! command -v ldconfig >/dev/null 2>&1; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local missing=0
|
||||||
|
local lib
|
||||||
|
for lib in \
|
||||||
|
libgtk-4.so.1 \
|
||||||
|
libgraphene-1.0.so.0 \
|
||||||
|
libxslt.so.1 \
|
||||||
|
libevent-2.1.so.7 \
|
||||||
|
libopus.so.0 \
|
||||||
|
libgstallocators-1.0.so.0 \
|
||||||
|
libgstapp-1.0.so.0 \
|
||||||
|
libgstpbutils-1.0.so.0 \
|
||||||
|
libgstaudio-1.0.so.0 \
|
||||||
|
libgsttag-1.0.so.0 \
|
||||||
|
libgstvideo-1.0.so.0 \
|
||||||
|
libgstgl-1.0.so.0 \
|
||||||
|
libgstcodecparsers-1.0.so.0 \
|
||||||
|
libgstfft-1.0.so.0 \
|
||||||
|
libflite.so.1 \
|
||||||
|
libwebpdemux.so.2 \
|
||||||
|
libavif.so.16 \
|
||||||
|
libharfbuzz-icu.so.0 \
|
||||||
|
libwebpmux.so.3 \
|
||||||
|
libwayland-server.so.0 \
|
||||||
|
libmanette-0.2.so.0 \
|
||||||
|
libenchant-2.so.2 \
|
||||||
|
libhyphen.so.0 \
|
||||||
|
libsecret-1.so.0 \
|
||||||
|
libwoff2dec.so.1.0.2 \
|
||||||
|
libx264.so; do
|
||||||
|
if ! ldconfig -p 2>/dev/null | grep -Fq "$lib"; then
|
||||||
|
missing=1
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
[ "$missing" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
if [ "$(id -u)" -eq 0 ]; then
|
if [ "$(id -u)" -eq 0 ]; then
|
||||||
playwright_install_cmd=(npx playwright install --with-deps)
|
playwright_install_cmd=(npx playwright install --with-deps)
|
||||||
@@ -65,6 +114,17 @@ if [ "$(id -u)" -eq 0 ]; then
|
|||||||
elif command -v sudo >/dev/null 2>&1 && sudo -n true >/dev/null 2>&1; then
|
elif command -v sudo >/dev/null 2>&1 && sudo -n true >/dev/null 2>&1; then
|
||||||
playwright_install_cmd=(npx playwright install --with-deps)
|
playwright_install_cmd=(npx playwright install --with-deps)
|
||||||
playwright_install_desc="npx playwright install --with-deps"
|
playwright_install_desc="npx playwright install --with-deps"
|
||||||
|
elif ! has_webkit_host_dependencies; then
|
||||||
|
playwright_install_cmd=(npx playwright install chromium firefox)
|
||||||
|
playwright_install_desc="npx playwright install chromium firefox"
|
||||||
|
playwright_project_args=(--project=chromium --project=firefox)
|
||||||
|
{
|
||||||
|
echo "# Adminfront WebKit Skipped"
|
||||||
|
echo
|
||||||
|
echo "- Reason: WebKit host dependencies are not installed and this user cannot run passwordless sudo."
|
||||||
|
echo "- Action: Running Chromium and Firefox projects only."
|
||||||
|
echo "- To enable WebKit locally: run \`cd adminfront && npx playwright install-deps webkit\` with sudo privileges."
|
||||||
|
} > reports/adminfront-webkit-skipped.md
|
||||||
fi
|
fi
|
||||||
|
|
||||||
set +e
|
set +e
|
||||||
@@ -134,7 +194,7 @@ echo "==> adminfront using PORT=$port"
|
|||||||
(
|
(
|
||||||
cd "$tmp_dir/adminfront"
|
cd "$tmp_dir/adminfront"
|
||||||
PORT="$port" PLAYWRIGHT_WORKERS="${PLAYWRIGHT_WORKERS:-1}" PLAYWRIGHT_BROWSERS_PATH="$playwright_browsers_path" \
|
PORT="$port" PLAYWRIGHT_WORKERS="${PLAYWRIGHT_WORKERS:-1}" PLAYWRIGHT_BROWSERS_PATH="$playwright_browsers_path" \
|
||||||
node ./node_modules/playwright/cli.js test
|
node ./node_modules/playwright/cli.js test "${playwright_project_args[@]}"
|
||||||
) 2>&1 | tee reports/adminfront-test.log
|
) 2>&1 | tee reports/adminfront-test.log
|
||||||
test_exit_code=${PIPESTATUS[0]}
|
test_exit_code=${PIPESTATUS[0]}
|
||||||
set -e
|
set -e
|
||||||
|
|||||||
@@ -17,6 +17,14 @@ for script in \
|
|||||||
"./devfront/scripts/runtime-mode.sh" \
|
"./devfront/scripts/runtime-mode.sh" \
|
||||||
"./orgfront/scripts/runtime-mode.sh"
|
"./orgfront/scripts/runtime-mode.sh"
|
||||||
do
|
do
|
||||||
|
if ! grep -Fq "ensure_frontend_dependencies" "$script"; then
|
||||||
|
echo "script=$script must sync frontend dependencies before start" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if ! grep -Fq "package-lock.json" "$script"; then
|
||||||
|
echo "script=$script must use package-lock.json for dependency sync" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
assert_mode "$script" "production" "production"
|
assert_mode "$script" "production" "production"
|
||||||
assert_mode "$script" "prod" "production"
|
assert_mode "$script" "prod" "production"
|
||||||
assert_mode "$script" "stage" "production"
|
assert_mode "$script" "stage" "production"
|
||||||
|
|||||||
@@ -24,13 +24,19 @@ pull_compose="docker/staging_pull_compose.template.yaml"
|
|||||||
devfront_vite="devfront/vite.config.ts"
|
devfront_vite="devfront/vite.config.ts"
|
||||||
orgfront_vite="orgfront/vite.config.ts"
|
orgfront_vite="orgfront/vite.config.ts"
|
||||||
adminfront_vite="adminfront/vite.config.ts"
|
adminfront_vite="adminfront/vite.config.ts"
|
||||||
|
adminfront_runtime="adminfront/scripts/runtime-mode.sh"
|
||||||
|
devfront_runtime="devfront/scripts/runtime-mode.sh"
|
||||||
|
orgfront_runtime="orgfront/scripts/runtime-mode.sh"
|
||||||
|
|
||||||
for file in \
|
for file in \
|
||||||
"$staging_pull" \
|
"$staging_pull" \
|
||||||
"$pull_compose" \
|
"$pull_compose" \
|
||||||
"$adminfront_vite" \
|
"$adminfront_vite" \
|
||||||
"$devfront_vite" \
|
"$devfront_vite" \
|
||||||
"$orgfront_vite"
|
"$orgfront_vite" \
|
||||||
|
"$adminfront_runtime" \
|
||||||
|
"$devfront_runtime" \
|
||||||
|
"$orgfront_runtime"
|
||||||
do
|
do
|
||||||
if [ ! -f "$file" ]; then
|
if [ ! -f "$file" ]; then
|
||||||
echo "missing expected file: $file" >&2
|
echo "missing expected file: $file" >&2
|
||||||
@@ -49,6 +55,7 @@ done
|
|||||||
assert_contains "$staging_pull" 'bash scripts/render_ory_config.sh'
|
assert_contains "$staging_pull" 'bash scripts/render_ory_config.sh'
|
||||||
assert_contains "$staging_pull" 'chmod -R 777 config/.generated/ory'
|
assert_contains "$staging_pull" 'chmod -R 777 config/.generated/ory'
|
||||||
assert_contains "$staging_pull" 'docker compose -f staging_pull_compose.yaml build --pull'
|
assert_contains "$staging_pull" 'docker compose -f staging_pull_compose.yaml build --pull'
|
||||||
|
assert_contains "$staging_pull" 'docker compose -f staging_pull_compose.yaml up -d --remove-orphans --renew-anon-volumes'
|
||||||
|
|
||||||
assert_contains "$pull_compose" "baron_devfront"
|
assert_contains "$pull_compose" "baron_devfront"
|
||||||
assert_contains "$pull_compose" "baron_orgfront"
|
assert_contains "$pull_compose" "baron_orgfront"
|
||||||
@@ -71,4 +78,11 @@ assert_contains "$orgfront_vite" '"sorg.hmac.kr"'
|
|||||||
assert_contains "orgfront/biome.json" '".vite"'
|
assert_contains "orgfront/biome.json" '".vite"'
|
||||||
assert_contains "orgfront/tsconfig.app.json" '"exclude": ["src/**/*.test.ts", "src/**/*.test.tsx"]'
|
assert_contains "orgfront/tsconfig.app.json" '"exclude": ["src/**/*.test.ts", "src/**/*.test.tsx"]'
|
||||||
|
|
||||||
|
for runtime_script in "$adminfront_runtime" "$devfront_runtime" "$orgfront_runtime"; do
|
||||||
|
assert_contains "$runtime_script" "ensure_frontend_dependencies"
|
||||||
|
assert_contains "$runtime_script" "package-lock.json"
|
||||||
|
assert_contains "$runtime_script" "npm ci"
|
||||||
|
assert_contains "$runtime_script" ".baron-deps-hash"
|
||||||
|
done
|
||||||
|
|
||||||
echo "staging frontend deploy policy checks passed"
|
echo "staging frontend deploy policy checks passed"
|
||||||
|
|||||||
@@ -45,10 +45,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: characters
|
name: characters
|
||||||
sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
|
sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.4.0"
|
version: "1.4.1"
|
||||||
cli_config:
|
cli_config:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -276,14 +276,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.5"
|
version: "1.0.5"
|
||||||
js:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: js
|
|
||||||
sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.7.2"
|
|
||||||
leak_tracker:
|
leak_tracker:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -336,18 +328,18 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: matcher
|
name: matcher
|
||||||
sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
|
sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.12.17"
|
version: "0.12.19"
|
||||||
material_color_utilities:
|
material_color_utilities:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: material_color_utilities
|
name: material_color_utilities
|
||||||
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
|
sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.11.1"
|
version: "0.13.0"
|
||||||
meta:
|
meta:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -669,26 +661,26 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test
|
name: test
|
||||||
sha256: "75906bf273541b676716d1ca7627a17e4c4070a3a16272b7a3dc7da3b9f3f6b7"
|
sha256: "280d6d890011ca966ad08df7e8a4ddfab0fb3aa49f96ed6de56e3521347a9ae7"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.26.3"
|
version: "1.30.0"
|
||||||
test_api:
|
test_api:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55
|
sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.7"
|
version: "0.7.10"
|
||||||
test_core:
|
test_core:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_core
|
name: test_core
|
||||||
sha256: "0cc24b5ff94b38d2ae73e1eb43cc302b77964fbf67abad1e296025b78deb53d0"
|
sha256: "0381bd1585d1a924763c308100f2138205252fb90c9d4eeaf28489ee65ccde51"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.12"
|
version: "0.6.16"
|
||||||
toml:
|
toml:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|||||||
Reference in New Issue
Block a user