공개 (@Tuwasduliebst 제보) 대응. - ckeditor5: 미참조 이미지 정리 엔진 신설 — 참조 판정(hash + 파일명 2토큰, filter_reference_sources 훅으로 확장 콘텐츠 등록) + 정리 커맨드(기본 꺼짐 옵트인, 3중 게이트) + 업로드 관리 화면(권한 분리·참조 배지·개별/선택 삭제) + 기설치본 설정 백필 upgrade step - board: 임시 첨부 GC(상시) + 소프트삭제 첨부 영구 정리(옵트인) + 설정 UI, 저장 payload 누락(F4)·빈 temp 디렉토리 잔존(F5) 수정 - ecommerce: 임시 상품 이미지 GC + 카테고리 삭제 시 이미지 파일 미삭제(S4) 수정 - page: 임시 첨부 GC - 코어: 고아 첨부 정리 커맨드(옵트인, site_logo 보호) + 사이트 로고 교체 시 구 로고 재편입 차단(S6) + DB 백업 미구현 501 정직화(B3) + 플러그인 관리자 메뉴 설치·업데이트 자동 동기화(F1·F7) - 동반: 플러그인 설정 검증 오류 필드명 라벨화(F3), Toggle 노드 type 정정 수평 전개(marketing 1.0.2 bump·gdpr·ecommerce), ja 언어팩 4종, API 문서, hooks.md, 시나리오 매니페스트 8종, Playwright E2E 4종
2054 lines
176 KiB
JSON
2054 lines
176 KiB
JSON
{
|
|
"version": "1.0.0",
|
|
"meta": {
|
|
"_e2e_allow": "e2e:allow sequence 액션을 params.actions 에서 top-level actions 로 정규화한 구조 통일. 엔진이 두 형태를 모두 해석하므로(ActionDispatcher: action.actions || params.actions) 동작 변화 없음. 규약 준수는 레이아웃 회귀테스트(admin_plugin_settings.test.tsx)가 검사.",
|
|
"title": "$t:sirsoft-gdpr.settings.title",
|
|
"description": "$t:sirsoft-gdpr.settings.description"
|
|
},
|
|
"layout_name": "plugin_settings",
|
|
"permissions": [
|
|
"core.plugins.update"
|
|
],
|
|
"extends": "_admin_base",
|
|
"data_sources": [
|
|
{
|
|
"id": "gdprSettings",
|
|
"label_key": "$t:sirsoft-gdpr.editor.data_source.gdprSettings",
|
|
"type": "api",
|
|
"endpoint": "/api/plugins/sirsoft-gdpr/admin/settings",
|
|
"method": "GET",
|
|
"auto_fetch": true,
|
|
"auth_required": true,
|
|
"initLocal": {
|
|
"_merge": "deep",
|
|
"form": "settings"
|
|
},
|
|
"refetchOnMount": true
|
|
},
|
|
{
|
|
"id": "gdprPolicyVersionCurrent",
|
|
"label_key": "$t:sirsoft-gdpr.editor.data_source.gdprPolicyVersionCurrent",
|
|
"type": "api",
|
|
"endpoint": "/api/plugins/sirsoft-gdpr/admin/policy-versions/current",
|
|
"method": "GET",
|
|
"auto_fetch": true,
|
|
"auth_required": true,
|
|
"refetchOnMount": true
|
|
},
|
|
{
|
|
"id": "gdprPolicyVersionHistory",
|
|
"label_key": "$t:sirsoft-gdpr.editor.data_source.gdprPolicyVersionHistory",
|
|
"type": "api",
|
|
"endpoint": "/api/plugins/sirsoft-gdpr/admin/policy-versions?page={{_local.policyHistoryPage ?? 1}}",
|
|
"method": "GET",
|
|
"auto_fetch": false,
|
|
"auth_required": true,
|
|
"comment": "정책 버전 이력 — 페이지는 _local.policyHistoryPage 로 관리하고 페이저가 setState + refetchDataSource 로 이동시킨다."
|
|
},
|
|
{
|
|
"comment": "정책 버전 단건 snapshot — _global.viewingPolicyVersion 정수를 endpoint path 에 보간. v배지/이력 행 클릭 시 setState global.viewingPolicyVersion → openModal policy_version_snapshot_modal 시퀀스에서 자동 fetch.",
|
|
"id": "gdprPolicyVersionSnapshot",
|
|
"label_key": "$t:sirsoft-gdpr.editor.data_source.gdprPolicyVersionSnapshot",
|
|
"type": "api",
|
|
"endpoint": "/api/plugins/sirsoft-gdpr/admin/policy-versions/{{_global.viewingPolicyVersion}}",
|
|
"method": "GET",
|
|
"auto_fetch": false,
|
|
"auth_required": true,
|
|
"refetchOnMount": true
|
|
}
|
|
],
|
|
"init_actions": [
|
|
{
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "local",
|
|
"isSaving": false,
|
|
"hasChanges": false,
|
|
"errors": null,
|
|
"policyHistoryOpen": false,
|
|
"policyHistoryPage": 1
|
|
}
|
|
}
|
|
],
|
|
"transition_overlay": {
|
|
"target": "settings_main_content",
|
|
"fallback_target": "plugin_settings_content",
|
|
"wait_for": [
|
|
"gdprSettings"
|
|
]
|
|
},
|
|
"modals": [
|
|
{
|
|
"partial": "partials/plugin_settings/_policy_version_publish_modal.json"
|
|
},
|
|
{
|
|
"partial": "partials/_shared/_policy_version_snapshot_modal.json"
|
|
}
|
|
],
|
|
"slots": {
|
|
"content": [
|
|
{
|
|
"id": "plugin_settings_content",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"comment": "GDPR 플러그인 환경설정 (v1.3.0: 5 카드 + 상단 탭 스크롤 + DPO 통합 + 쿠키 통합 + 미리보기 + 인라인 토글 + 제3자 모달)",
|
|
"dataKey": "form",
|
|
"trackChanges": true,
|
|
"props": {
|
|
"className": "admin-page-content-responsive-fluid"
|
|
},
|
|
"children": [
|
|
{
|
|
"id": "sticky_header",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"comment": "헤더 + 탭을 sticky 컨테이너로 묶음 (게시판 설정과 동일한 구조 — root 가 admin-page-content-responsive-fluid 로 좌우 패딩을 이미 갖고 있으므로 header_content 는 자체 좌우 패딩을 두지 않는다. 그래야 sticky_header 의 border-b 폭이 아래 카드 폭과 정확히 일치한다).",
|
|
"props": {
|
|
"className": "sticky-section-header"
|
|
},
|
|
"children": [
|
|
{
|
|
"id": "header_content",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "pt-4 pb-0"
|
|
},
|
|
"children": [
|
|
{
|
|
"id": "header_top_row",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"comment": "제목 wrapper — 게시판 설정(page_header_wrapper)과 동일하게 별도 className 없음. panel-header-row(border-b 포함) 를 쓰면 탭 위에 불필요한 구분선이 하나 더 생긴다.",
|
|
"children": [
|
|
{
|
|
"id": "page_header",
|
|
"type": "composite",
|
|
"name": "PageHeader",
|
|
"props": {
|
|
"title": "$t:sirsoft-gdpr.settings.title",
|
|
"description": "$t:sirsoft-gdpr.settings.description",
|
|
"backPath": "/admin/plugins",
|
|
"backLabel": "$t:admin.plugins.back_to_list"
|
|
}
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "settings_tab_navigation",
|
|
"type": "composite",
|
|
"name": "TabNavigationScroll",
|
|
"comment": "상단 탭 스크롤 — settings_main_content(p-4 sm:p-6 lg:p-8) 안 카드들과 좌우 정렬을 맞추기 위해 header_content 패딩을 그대로 물려받는다(자체 좌우 패딩 없음). 클릭 시 해당 카드로 자동 스크롤 + 스크롤 시 활성 탭 자동 갱신.",
|
|
"props": {
|
|
"tabs": [
|
|
{
|
|
"id": "card_operator",
|
|
"label": "$t:sirsoft-gdpr.settings.nav.operator"
|
|
},
|
|
{
|
|
"id": "card_cookie_banner",
|
|
"label": "$t:sirsoft-gdpr.settings.nav.cookie_banner"
|
|
},
|
|
{
|
|
"id": "card_auto_blocking_policy",
|
|
"label": "$t:sirsoft-gdpr.settings.nav.auto_blocking_policy"
|
|
}
|
|
],
|
|
"className": "flex gap-1",
|
|
"sectionIdPrefix": "",
|
|
"enableScrollSpy": true,
|
|
"scrollContainerId": "right_content_area",
|
|
"scrollSpyOffset": 180,
|
|
"scrollOffset": 180
|
|
}
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "settings_main_content",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"comment": "5 카드 컨테이너 (transition_overlay 타겟). root(admin-page-content-responsive-fluid) 가 좌우 패딩을 이미 가지므로 여기서는 세로 여백만 둔다. 상단 pt-6 은 게시판 설정(.tab-content — sticky 탭과 콘텐츠 사이 표준 24px)과 동일 값.",
|
|
"props": {
|
|
"className": "pt-6 pb-6"
|
|
},
|
|
"children": [
|
|
{
|
|
"id": "validation_error",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"if": "{{_local.errors}}",
|
|
"props": {
|
|
"className": "alert-danger"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"comment": "아이콘 + 제목을 한 줄로 묶고, 그 아래에 에러 목록을 배치 (검토 — 아이콘 위치 정렬).",
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "flex-center gap-2"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Icon",
|
|
"props": {
|
|
"name": "triangle-exclamation",
|
|
"size": "lg",
|
|
"className": "text-red-600 dark:text-red-400 flex-shrink-0"
|
|
}
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "H3",
|
|
"props": {
|
|
"className": "text-error-soft"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.validation_error"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Ul",
|
|
"if": "{{typeof _local.errors === 'object' && Object.keys(_local.errors).length > 0}}",
|
|
"props": {
|
|
"className": "mt-2 list-disc list-inside space-y-1"
|
|
},
|
|
"iteration": {
|
|
"source": "Object.entries(_local.errors ?? {}).flatMap(([field, messages]) => Array.isArray(messages) ? messages : [messages])",
|
|
"item_var": "message"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Li",
|
|
"props": {
|
|
"className": "grid-3col-responsive"
|
|
},
|
|
"text": "{{message}}"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "card_operator",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"comment": "1️⃣ 운영 주체 + 개인정보처리방침 (정책 페이지 슬러그 통합)",
|
|
"props": {
|
|
"className": "bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 scroll-mt-32"
|
|
},
|
|
"children": [
|
|
{
|
|
"id": "card_operator_header",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "panel-header-row"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "H3",
|
|
"props": {
|
|
"className": "section-heading-md"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.section.operator"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "P",
|
|
"props": {
|
|
"className": "form-hint"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.section.operator_desc"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "card_operator_fields",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "p-6 space-y-6"
|
|
},
|
|
"children": [
|
|
{
|
|
"id": "field_legal_entity_name",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "grid-3col-responsive"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "lg:col-span-1"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Label",
|
|
"props": {
|
|
"className": "form-label"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.fields.legal_entity_name.label"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "P",
|
|
"props": {
|
|
"className": "form-hint"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.fields.legal_entity_name.hint"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "lg:col-span-2"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Input",
|
|
"props": {
|
|
"type": "text",
|
|
"name": "legal_entity_name",
|
|
"placeholder": "$t:sirsoft-gdpr.settings.fields.legal_entity_name.placeholder",
|
|
"className": "{{_local.errors?.['legal_entity_name'] ? 'input-error dark:focus:ring-red-400 dark:focus:border-red-400' : 'dark:focus:ring-blue-400 dark:focus:border-blue-400'}}"
|
|
}
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"comment": "필드별 422 검증 에러 메시지 (검토 #10 옵션 X — 코어 admin _tab_general 패턴 채택).",
|
|
"if": "{{_local.errors?.['legal_entity_name']}}",
|
|
"props": {
|
|
"className": "form-error"
|
|
},
|
|
"text": "{{_local.errors?.['legal_entity_name']?.[0] ?? ''}}"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "field_data_storage_location",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "grid-3col-responsive"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "lg:col-span-1"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Label",
|
|
"props": {
|
|
"className": "form-label"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.fields.data_storage_location.label"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "P",
|
|
"props": {
|
|
"className": "form-hint"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.fields.data_storage_location.hint"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "lg:col-span-2"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Input",
|
|
"props": {
|
|
"type": "text",
|
|
"name": "data_storage_location",
|
|
"placeholder": "$t:sirsoft-gdpr.settings.fields.data_storage_location.placeholder",
|
|
"className": "{{_local.errors?.['data_storage_location'] ? 'input-error dark:focus:ring-red-400 dark:focus:border-red-400' : 'dark:focus:ring-blue-400 dark:focus:border-blue-400'}}"
|
|
}
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"comment": "필드별 422 검증 에러 메시지 (검토 #10 옵션 X — 코어 admin _tab_general 패턴 채택).",
|
|
"if": "{{_local.errors?.['data_storage_location']}}",
|
|
"props": {
|
|
"className": "form-error"
|
|
},
|
|
"text": "{{_local.errors?.['data_storage_location']?.[0] ?? ''}}"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "field_privacy_policy_slug",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "grid-3col-responsive pt-6 border-t border-gray-200 dark:border-gray-700"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "lg:col-span-1"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Label",
|
|
"props": {
|
|
"className": "form-label"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.fields.privacy_policy_slug.label"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "P",
|
|
"props": {
|
|
"className": "form-hint"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.fields.privacy_policy_slug.hint"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "lg:col-span-2"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Input",
|
|
"props": {
|
|
"type": "text",
|
|
"name": "privacy_policy_slug",
|
|
"placeholder": "$t:sirsoft-gdpr.settings.fields.privacy_policy_slug.placeholder",
|
|
"className": "{{_local.errors?.['privacy_policy_slug'] ? 'input-error dark:focus:ring-red-400 dark:focus:border-red-400' : 'dark:focus:ring-blue-400 dark:focus:border-blue-400'}}"
|
|
}
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"comment": "필드별 422 검증 에러 메시지 (검토 #10 옵션 X — 코어 admin _tab_general 패턴 채택).",
|
|
"if": "{{_local.errors?.['privacy_policy_slug']}}",
|
|
"props": {
|
|
"className": "form-error"
|
|
},
|
|
"text": "{{_local.errors?.['privacy_policy_slug']?.[0] ?? ''}}"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "card_cookie_banner",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"comment": "3️⃣ 쿠키 동의 배너 통합 (배너 + 카테고리 + 정책 버전 + 미리보기)",
|
|
"props": {
|
|
"className": "mt-4 bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 scroll-mt-32"
|
|
},
|
|
"children": [
|
|
{
|
|
"id": "card_cookie_banner_header",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "panel-header-row flex-between"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "H3",
|
|
"props": {
|
|
"className": "section-heading-md"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.section.cookie_banner"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "P",
|
|
"props": {
|
|
"className": "form-hint"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.section.cookie_banner_desc"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"props": {
|
|
"className": "inline-flex items-center px-2.5 py-0.5 rounded text-xs font-medium flex-shrink-0 ml-3 {{_local.form?.banner_enabled ? 'bg-green-100 dark:bg-green-900 text-success-soft' : 'bg-gray-100 dark:bg-gray-700 text-gray-600 dark:text-gray-400'}}"
|
|
},
|
|
"text": "{{_local.form?.banner_enabled ? '$t:sirsoft-gdpr.settings.status.enabled' : '$t:sirsoft-gdpr.settings.status.disabled'}}"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "card_cookie_banner_fields",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "p-6 space-y-6"
|
|
},
|
|
"children": [
|
|
{
|
|
"id": "subsection_banner_settings",
|
|
"type": "basic",
|
|
"name": "H4",
|
|
"props": {
|
|
"className": "text-body font-semibold"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.section.cookie_banner_settings"
|
|
},
|
|
{
|
|
"id": "field_banner_enabled",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"comment": "v1.4.0: banner_display_mode Select → banner_enabled Toggle",
|
|
"props": {
|
|
"className": "grid-3col-responsive"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "lg:col-span-2"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Label",
|
|
"props": {
|
|
"className": "form-label"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.fields.banner_enabled.label"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "P",
|
|
"props": {
|
|
"className": "form-hint"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.fields.banner_enabled.hint"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "lg:col-span-1 flex justify-end"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "composite",
|
|
"name": "Toggle",
|
|
"props": {
|
|
"name": "banner_enabled"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "field_banner_position",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "grid-3col-responsive"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "lg:col-span-1"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Label",
|
|
"props": {
|
|
"className": "form-label"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.fields.banner_position.label"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "P",
|
|
"props": {
|
|
"className": "form-hint"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.fields.banner_position.hint"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "lg:col-span-2"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "composite",
|
|
"name": "Select",
|
|
"props": {
|
|
"name": "banner_position",
|
|
"className": "w-full",
|
|
"options": [
|
|
{
|
|
"value": "bottom_bar",
|
|
"label": "$t:sirsoft-gdpr.settings.fields.banner_position.option_bottom_bar"
|
|
},
|
|
{
|
|
"value": "bottom_left_popup",
|
|
"label": "$t:sirsoft-gdpr.settings.fields.banner_position.option_bottom_left_popup"
|
|
},
|
|
{
|
|
"value": "bottom_right_popup",
|
|
"label": "$t:sirsoft-gdpr.settings.fields.banner_position.option_bottom_right_popup"
|
|
},
|
|
{
|
|
"value": "centered_modal",
|
|
"label": "$t:sirsoft-gdpr.settings.fields.banner_position.option_centered_modal"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "field_cookie_policy_version",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"comment": "정책 버전 카드 — 안 A (header + body separation, full-width). 라벨/설명을 풀폭 한 줄로 배치 후 그 아래에 카드 본문(현재 버전 + 액션 + collapsible 이력)을 풀폭으로 배치. gdpr_policy_versions 테이블이 SSoT.",
|
|
"props": {
|
|
"className": "row-stack"
|
|
},
|
|
"children": [
|
|
{
|
|
"id": "policy_version_guide_box",
|
|
"comment": "라벨 + hint 2줄 (발행 가이드 통합) — 토글/박스 제거하고 카드 hint 영역에 두 줄로 통합. 1줄: 발행 시점 안내 (cookie_policy_version.hint), 2줄: 발행 대상 구분 (policy_version.guide_body).",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Label",
|
|
"props": {
|
|
"className": "form-label"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.fields.cookie_policy_version.label"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "P",
|
|
"props": {
|
|
"className": "form-hint leading-relaxed"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.fields.cookie_policy_version.hint"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "P",
|
|
"props": {
|
|
"className": "form-hint leading-relaxed"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.policy_version.guide_body"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"comment": "카드 본문 — col-span-3 (full-width) 박스. 상단: 버전 배지 + 메타 + 액션 버튼. 하단: collapsible 이력 표.",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "border border-gray-200 dark:border-gray-700 rounded-lg bg-gray-50 dark:bg-gray-900"
|
|
},
|
|
"children": [
|
|
{
|
|
"comment": "헤더 영역 — 좌측: v배지 + 발행 메타 / 우측: 새 버전 발행 + 이력 토글",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "flex-start px-4 py-3 justify-between gap-3 flex-wrap"
|
|
},
|
|
"children": [
|
|
{
|
|
"comment": "메타 4개를 한 줄로 — 현재 버전 v배지 + 발행일시 + 발행자 + 변경사유. 좁은 화면에서는 flex-wrap 으로 자연 줄바꿈.",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "flex-center flex-1 min-w-0 flex-wrap gap-x-6 gap-y-1 text-xs"
|
|
},
|
|
"children": [
|
|
{
|
|
"comment": "현재 버전 v배지 + 본문 보기 버튼. v배지는 평문 Span (인디케이션 의도 명확화). 본문 보기는 별도 Button 으로 명시 액션 — (v배지 클릭만으로는 직관성 부족).",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "flex items-baseline gap-2"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"props": {
|
|
"className": "uppercase tracking-wide text-gray-500 dark:text-gray-400"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.policy_version.current_label"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"props": {
|
|
"className": "text-lg font-semibold text-gray-900 dark:text-gray-100"
|
|
},
|
|
"text": "v{{gdprPolicyVersionCurrent?.data?.data?.version ?? '?'}}"
|
|
},
|
|
{
|
|
"id": "policy_version_current_snapshot_view_button",
|
|
"type": "basic",
|
|
"name": "Button",
|
|
"if": "{{gdprPolicyVersionCurrent?.data?.data?.version}}",
|
|
"props": {
|
|
"type": "button",
|
|
"className": "text-info-soft px-2 py-0.5 font-medium bg-blue-50 dark:bg-blue-900/30 border border-blue-200 dark:border-blue-700 rounded hover:bg-blue-100 dark:hover:bg-blue-900/50 transition-colors",
|
|
"title": "$t:sirsoft-gdpr.settings.policy_version.snapshot_modal.view_button|version={{gdprPolicyVersionCurrent?.data?.data?.version ?? '?'}}"
|
|
},
|
|
"actions": [
|
|
{
|
|
"type": "click",
|
|
"handler": "sequence",
|
|
"actions": [
|
|
{
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "global",
|
|
"viewingPolicyVersion": "{{gdprPolicyVersionCurrent?.data?.data?.version}}"
|
|
}
|
|
},
|
|
{
|
|
"handler": "refetchDataSource",
|
|
"params": {
|
|
"dataSourceId": "gdprPolicyVersionSnapshot"
|
|
}
|
|
},
|
|
{
|
|
"handler": "openModal",
|
|
"target": "policy_version_snapshot_modal"
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"text": "$t:sirsoft-gdpr.settings.policy_version.snapshot_view_short"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"if": "{{gdprPolicyVersionCurrent?.data?.data}}",
|
|
"props": {
|
|
"className": "flex items-baseline gap-2 text-gray-600 dark:text-gray-300"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"props": {
|
|
"className": "text-gray-500 dark:text-gray-400"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.policy_version.published_at_label"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"text": "{{gdprPolicyVersionCurrent?.data?.data?.created_at ?? '-'}}"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"if": "{{gdprPolicyVersionCurrent?.data?.data}}",
|
|
"props": {
|
|
"className": "flex items-baseline gap-2 text-gray-600 dark:text-gray-300"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"props": {
|
|
"className": "text-gray-500 dark:text-gray-400"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.policy_version.publisher_label"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"text": "{{gdprPolicyVersionCurrent?.data?.data?.publisher?.name ? (gdprPolicyVersionCurrent?.data?.data?.publisher?.email ? gdprPolicyVersionCurrent.data.data.publisher.name + ' (' + gdprPolicyVersionCurrent.data.data.publisher.email + ')' : gdprPolicyVersionCurrent.data.data.publisher.name) : (gdprPolicyVersionCurrent?.data?.data?.publisher?.email ?? '$t:sirsoft-gdpr.settings.policy_version.publisher_system')}}"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"if": "{{gdprPolicyVersionCurrent?.data?.data}}",
|
|
"props": {
|
|
"className": "flex items-baseline gap-2 text-gray-600 dark:text-gray-300 min-w-0"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"props": {
|
|
"className": "text-gray-500 dark:text-gray-400 flex-shrink-0"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.policy_version.memo_label"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"props": {
|
|
"className": "truncate"
|
|
},
|
|
"text": "{{gdprPolicyVersionCurrent?.data?.data?.memo ?? '-'}}"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"comment": "액션 영역 — 새 버전 발행 (publish modal 진입) + 이력 토글",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "flex-center gap-2 flex-shrink-0"
|
|
},
|
|
"children": [
|
|
{
|
|
"comment": "새 버전 발행 버튼 — publish modal 열기",
|
|
"type": "basic",
|
|
"name": "Button",
|
|
"props": {
|
|
"type": "button",
|
|
"className": "inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium text-white bg-gray-900 dark:bg-white dark:text-gray-900 border border-gray-900 dark:border-white rounded-md hover:bg-gray-800 dark:hover:bg-gray-100 transition-colors"
|
|
},
|
|
"actions": [
|
|
{
|
|
"type": "click",
|
|
"handler": "openModal",
|
|
"target": "policy_version_publish_modal"
|
|
}
|
|
],
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Icon",
|
|
"props": {
|
|
"name": "plus",
|
|
"size": "xs"
|
|
}
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"text": "$t:sirsoft-gdpr.settings.policy_version.publish_button"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"comment": "이력 collapsible 토글 — _local.policyHistoryOpen 으로 inline 표 노출/숨김 (열릴 때 데이터소스 refetch)",
|
|
"type": "basic",
|
|
"name": "Button",
|
|
"props": {
|
|
"type": "button",
|
|
"className": "inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium text-blue-600 dark:text-blue-400 border border-blue-200 dark:border-blue-800 rounded-md hover:bg-blue-50 dark:hover:bg-blue-900/20 transition-colors"
|
|
},
|
|
"actions": [
|
|
{
|
|
"type": "click",
|
|
"handler": "sequence",
|
|
"actions": [
|
|
{
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "local",
|
|
"policyHistoryOpen": "{{!_local.policyHistoryOpen}}",
|
|
"policyHistoryPage": 1
|
|
}
|
|
},
|
|
{
|
|
"handler": "refetchDataSource",
|
|
"params": {
|
|
"dataSourceId": "gdprPolicyVersionHistory"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Icon",
|
|
"props": {
|
|
"name": "{{_local.policyHistoryOpen ? 'chevron-up' : 'chevron-down'}}",
|
|
"size": "xs"
|
|
}
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"text": "{{_local.policyHistoryOpen ? '$t:sirsoft-gdpr.settings.policy_version.history_toggle_hide' : '$t:sirsoft-gdpr.settings.policy_version.history_toggle_show'}}"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "policy_version_history_table",
|
|
"comment": "이력 표 — collapsible. _local.policyHistoryOpen 일 때만 노출. gdprPolicyVersionHistory 데이터소스 페이지네이션 표시.",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"if": "{{_local.policyHistoryOpen}}",
|
|
"props": {
|
|
"className": "border-t border-gray-200 dark:border-gray-700 px-4 py-3"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"if": "{{(gdprPolicyVersionHistory?.data?.data?.length ?? 0) === 0}}",
|
|
"props": {
|
|
"className": "text-center text-label-subtle py-6"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.policy_version.history_empty"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"if": "{{(gdprPolicyVersionHistory?.data?.data?.length ?? 0) > 0}}",
|
|
"props": {
|
|
"className": "overflow-x-auto"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Table",
|
|
"props": {
|
|
"className": "w-full text-sm"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Thead",
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Tr",
|
|
"props": {
|
|
"className": "text-tertiary uppercase tracking-wide border-b border-gray-200 dark:border-gray-700"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Th",
|
|
"props": {
|
|
"className": "text-left px-3 py-2 font-medium"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.policy_version.history.col.version"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Th",
|
|
"props": {
|
|
"className": "text-left px-3 py-2 font-medium"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.policy_version.history.col.created_at"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Th",
|
|
"props": {
|
|
"className": "text-left px-3 py-2 font-medium"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.policy_version.history.col.publisher"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Th",
|
|
"props": {
|
|
"className": "text-left px-3 py-2 font-medium"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.policy_version.history.col.change_type"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Th",
|
|
"props": {
|
|
"className": "text-left px-3 py-2 font-medium"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.policy_version.history.col.memo"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Th",
|
|
"props": {
|
|
"className": "text-left px-3 py-2 font-medium w-20"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.policy_version.history.col.snapshot_action"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Tbody",
|
|
"iteration": {
|
|
"source": "gdprPolicyVersionHistory?.data?.data ?? []",
|
|
"item_var": "row"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Tr",
|
|
"props": {
|
|
"className": "border-b border-gray-100 dark:border-gray-700/60 text-gray-700 dark:text-gray-200"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Td",
|
|
"props": {
|
|
"className": "px-3 py-2 font-mono text-gray-900 dark:text-gray-100"
|
|
},
|
|
"text": "v{{row?.version ?? '?'}}"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Td",
|
|
"props": {
|
|
"className": "px-3 py-2 text-xs"
|
|
},
|
|
"text": "{{row?.created_at ?? '-'}}"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Td",
|
|
"props": {
|
|
"className": "px-3 py-2 text-xs"
|
|
},
|
|
"text": "{{row?.publisher?.name ? (row?.publisher?.email ? row.publisher.name + ' (' + row.publisher.email + ')' : row.publisher.name) : (row?.publisher?.email ?? '$t:sirsoft-gdpr.settings.policy_version.publisher_system')}}"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Td",
|
|
"props": {
|
|
"className": "px-3 py-2 text-xs"
|
|
},
|
|
"text": "{{row?.change_type === 'material' ? '$t:sirsoft-gdpr.settings.policy_version.change_type.material' : (row?.change_type === 'initial' ? '$t:sirsoft-gdpr.settings.policy_version.change_type.initial' : '$t:sirsoft-gdpr.settings.policy_version.change_type.non_material')}}"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Td",
|
|
"props": {
|
|
"className": "px-3 py-2 text-xs text-gray-600 dark:text-gray-300 break-all"
|
|
},
|
|
"text": "{{row?.memo ?? '-'}}"
|
|
},
|
|
{
|
|
"comment": "본문 액션 셀 — 클릭 시 setState global.viewingPolicyVersion → refetch → openModal 시퀀스로 snapshot 모달 노출",
|
|
"type": "basic",
|
|
"name": "Td",
|
|
"props": {
|
|
"className": "px-3 py-2 text-xs"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Button",
|
|
"props": {
|
|
"type": "button",
|
|
"className": "text-info-soft px-2 py-1 font-medium bg-blue-50 dark:bg-blue-900/30 border border-blue-200 dark:border-blue-700 rounded hover:bg-blue-100 dark:hover:bg-blue-900/50 transition-colors",
|
|
"title": "$t:sirsoft-gdpr.settings.policy_version.snapshot_modal.view_button|version={{row?.version ?? '?'}}"
|
|
},
|
|
"actions": [
|
|
{
|
|
"type": "click",
|
|
"handler": "sequence",
|
|
"actions": [
|
|
{
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "global",
|
|
"viewingPolicyVersion": "{{row?.version}}"
|
|
}
|
|
},
|
|
{
|
|
"handler": "refetchDataSource",
|
|
"params": {
|
|
"dataSourceId": "gdprPolicyVersionSnapshot"
|
|
}
|
|
},
|
|
{
|
|
"handler": "openModal",
|
|
"target": "policy_version_snapshot_modal"
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"text": "$t:sirsoft-gdpr.settings.policy_version.snapshot_view_short"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "policy_version_history_pager",
|
|
"comment": "이력 페이저 — 총건수/현재 페이지를 함께 표시한다. 없으면 최신 20건만 보이고 나머지가 조용히 잘린다.",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"if": "{{((gdprPolicyVersionHistory?.data?.pagination?.last_page ?? 0) > 1) || (gdprPolicyVersionHistory?.data?.pagination?.has_more_pages === true) || ((gdprPolicyVersionHistory?.data?.pagination?.current_page ?? 1) > 1)}}",
|
|
"props": {
|
|
"className": "flex items-center justify-between gap-3 pt-3 mt-3 border-t border-gray-200 dark:border-gray-700"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"props": {
|
|
"className": "text-label-subtle text-sm"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.policy_version.history_page_summary|current={{gdprPolicyVersionHistory?.data?.pagination?.current_page ?? 1}}|last={{gdprPolicyVersionHistory?.data?.pagination?.last_page ?? '-'}}|total={{gdprPolicyVersionHistory?.data?.pagination?.total ?? 0}}"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "flex items-center gap-2"
|
|
},
|
|
"children": [
|
|
{
|
|
"id": "policy_history_prev",
|
|
"type": "basic",
|
|
"name": "Button",
|
|
"props": {
|
|
"type": "button",
|
|
"className": "btn btn-sm btn-neutral",
|
|
"disabled": "{{(gdprPolicyVersionHistory?.data?.pagination?.current_page ?? 1) <= 1}}"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.policy_version.history_prev",
|
|
"actions": [
|
|
{
|
|
"type": "click",
|
|
"handler": "sequence",
|
|
"actions": [
|
|
{
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "local",
|
|
"policyHistoryPage": "{{gdprPolicyVersionHistory?.data?.pagination?.last_page ? Math.min(Math.max(1, (_local.policyHistoryPage ?? 1) + (-1)), gdprPolicyVersionHistory?.data?.pagination?.last_page) : Math.max(1, (_local.policyHistoryPage ?? 1) + (-1))}}"
|
|
}
|
|
},
|
|
{
|
|
"handler": "refetchDataSource",
|
|
"params": {
|
|
"dataSourceId": "gdprPolicyVersionHistory"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "policy_history_next",
|
|
"type": "basic",
|
|
"name": "Button",
|
|
"props": {
|
|
"type": "button",
|
|
"className": "btn btn-sm btn-neutral",
|
|
"disabled": "{{gdprPolicyVersionHistory?.data?.pagination?.last_page ? ((gdprPolicyVersionHistory?.data?.pagination?.current_page ?? 1) >= gdprPolicyVersionHistory?.data?.pagination?.last_page) : (gdprPolicyVersionHistory?.data?.pagination?.has_more_pages !== true)}}"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.policy_version.history_next",
|
|
"actions": [
|
|
{
|
|
"type": "click",
|
|
"handler": "sequence",
|
|
"actions": [
|
|
{
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "local",
|
|
"policyHistoryPage": "{{gdprPolicyVersionHistory?.data?.pagination?.last_page ? Math.min(Math.max(1, (_local.policyHistoryPage ?? 1) + (1)), gdprPolicyVersionHistory?.data?.pagination?.last_page) : Math.max(1, (_local.policyHistoryPage ?? 1) + (1))}}"
|
|
}
|
|
},
|
|
{
|
|
"handler": "refetchDataSource",
|
|
"params": {
|
|
"dataSourceId": "gdprPolicyVersionHistory"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "subsection_cookie_categories",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "pt-4 border-t border-gray-200 dark:border-gray-700"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "H4",
|
|
"props": {
|
|
"className": "text-body font-semibold"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.section.cookie_categories"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "P",
|
|
"props": {
|
|
"className": "form-hint"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.fields.cookie_categories.description"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "cookie_categories_rows_{{categoryIdx}}",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"comment": "카드 구조: 헤더(아이콘+이름+key+필수/선택 배지) + 운영 정보 펼침. 카드는 정보 패널이며, 카테고리·필수 여부는 CookieCategory enum 이 SSoT.",
|
|
"props": {
|
|
"className": "row-stack"
|
|
},
|
|
"iteration": {
|
|
"source": "_local.form?.cookie_categories ?? []",
|
|
"item_var": "category",
|
|
"index_var": "categoryIdx"
|
|
},
|
|
"children": [
|
|
{
|
|
"comment": "카테고리 카드 — 헤더 + (선택) 펼침 영역",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "border border-gray-200 dark:border-gray-700 rounded-lg"
|
|
},
|
|
"children": [
|
|
{
|
|
"comment": "헤더 행 — 좌측: 아이콘+한글명+(key) / 우측: 필수/선택 배지 + 펼침 버튼.",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "flex-between gap-3 px-4 py-3"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "flex-center gap-3 min-w-0"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Icon",
|
|
"if": "{{category?.key === 'necessary'}}",
|
|
"props": {
|
|
"name": "shield-halved",
|
|
"size": "sm",
|
|
"className": "text-secondary flex-shrink-0"
|
|
}
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Icon",
|
|
"if": "{{category?.key === 'functional'}}",
|
|
"props": {
|
|
"name": "sliders",
|
|
"size": "sm",
|
|
"className": "text-emerald-600 dark:text-emerald-400 flex-shrink-0"
|
|
}
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Icon",
|
|
"if": "{{category?.key === 'analytics'}}",
|
|
"props": {
|
|
"name": "chart-line",
|
|
"size": "sm",
|
|
"className": "text-blue-600 dark:text-blue-400 flex-shrink-0"
|
|
}
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Icon",
|
|
"if": "{{category?.key === 'marketing'}}",
|
|
"props": {
|
|
"name": "bullhorn",
|
|
"size": "sm",
|
|
"className": "text-purple-600 dark:text-purple-400 flex-shrink-0"
|
|
}
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "min-w-0"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "flex-center gap-2"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"props": {
|
|
"className": "text-primary text-sm font-semibold"
|
|
},
|
|
"text": "{{$localized(category?.label) || category?.key || ''}}"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"props": {
|
|
"className": "text-tertiary font-mono"
|
|
},
|
|
"text": "({{category?.key ?? ''}})"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "flex-center gap-2 flex-shrink-0"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"if": "{{category?.required === true}}",
|
|
"props": {
|
|
"className": "inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-red-100 dark:bg-red-800 text-danger-soft"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.fields.cookie_categories.category_required_badge"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"if": "{{category?.required !== true}}",
|
|
"props": {
|
|
"className": "inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-200"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.fields.cookie_categories.category_optional_badge"
|
|
},
|
|
{
|
|
"comment": "펼침 토글 버튼",
|
|
"type": "basic",
|
|
"name": "Button",
|
|
"props": {
|
|
"type": "button",
|
|
"className": "ml-1 inline-flex items-center gap-1 text-xs text-blue-600 dark:text-blue-400 hover:underline"
|
|
},
|
|
"actions": [
|
|
{
|
|
"type": "click",
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "local",
|
|
"expandedCategoryIdx": "{{_local.expandedCategoryIdx === categoryIdx ? null : categoryIdx}}"
|
|
}
|
|
}
|
|
],
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Icon",
|
|
"props": {
|
|
"name": "{{_local.expandedCategoryIdx === categoryIdx ? 'chevron-up' : 'chevron-down'}}",
|
|
"size": "xs"
|
|
}
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"text": "{{_local.expandedCategoryIdx === categoryIdx ? '$t:sirsoft-gdpr.settings.fields.cookie_categories.info.collapse' : '$t:sirsoft-gdpr.settings.fields.cookie_categories.info.expand'}}"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"comment": "펼침 영역 — description + scope + tools + legal_basis",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"if": "{{_local.expandedCategoryIdx === categoryIdx}}",
|
|
"props": {
|
|
"className": "px-4 pb-4 pt-3 border-t border-gray-100 dark:border-gray-700"
|
|
},
|
|
"children": [
|
|
{
|
|
"comment": "Definition List 스타일 — 좌측 라벨(col-span-3) + 우측 값(col-span-9) — 표준 grid-cols-12 사용 (safelist 호환)",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "grid grid-cols-12 gap-x-3 gap-y-2"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"if": "{{!!$localized(category?.description)}}",
|
|
"props": {
|
|
"className": "text-tertiary col-span-2 font-medium uppercase tracking-wide"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.fields.cookie_categories.info.description_label"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"if": "{{!!$localized(category?.description)}}",
|
|
"props": {
|
|
"className": "col-span-10 text-xs leading-relaxed text-gray-700 dark:text-gray-300"
|
|
},
|
|
"text": "{{$localized(category?.description)}}"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"props": {
|
|
"className": "text-tertiary col-span-2 font-medium uppercase tracking-wide"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.fields.cookie_categories.info.scope_label"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"if": "{{category?.key === 'necessary'}}",
|
|
"props": {
|
|
"className": "col-span-10 text-xs leading-relaxed text-gray-700 dark:text-gray-300"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.fields.cookie_categories.info.necessary.scope"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"if": "{{category?.key === 'functional'}}",
|
|
"props": {
|
|
"className": "col-span-10 text-xs leading-relaxed text-gray-700 dark:text-gray-300"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.fields.cookie_categories.info.functional.scope"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"if": "{{category?.key === 'analytics'}}",
|
|
"props": {
|
|
"className": "col-span-10 text-xs leading-relaxed text-gray-700 dark:text-gray-300"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.fields.cookie_categories.info.analytics.scope"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"if": "{{category?.key === 'marketing'}}",
|
|
"props": {
|
|
"className": "col-span-10 text-xs leading-relaxed text-gray-700 dark:text-gray-300"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.fields.cookie_categories.info.marketing.scope"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"props": {
|
|
"className": "text-tertiary col-span-2 font-medium uppercase tracking-wide"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.fields.cookie_categories.info.tools_label"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"if": "{{category?.key === 'necessary'}}",
|
|
"props": {
|
|
"className": "col-span-10 text-xs leading-relaxed text-gray-700 dark:text-gray-300"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.fields.cookie_categories.info.necessary.tools"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"if": "{{category?.key === 'functional'}}",
|
|
"props": {
|
|
"className": "col-span-10 text-xs leading-relaxed text-gray-700 dark:text-gray-300"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.fields.cookie_categories.info.functional.tools"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"if": "{{category?.key === 'analytics'}}",
|
|
"props": {
|
|
"className": "col-span-10 text-xs leading-relaxed text-gray-700 dark:text-gray-300"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.fields.cookie_categories.info.analytics.tools"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"if": "{{category?.key === 'marketing'}}",
|
|
"props": {
|
|
"className": "col-span-10 text-xs leading-relaxed text-gray-700 dark:text-gray-300"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.fields.cookie_categories.info.marketing.tools"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "card_auto_blocking_policy",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"comment": "F-02 자동 차단 정책 — 별도 카드/탭으로 분리. banner_enabled (쿠키 배너 노출) 가 ON 일 때만 본문 노출. OFF 시 안내 박스로 쿠키 배너 노출 활성화 유도",
|
|
"props": {
|
|
"className": "mt-4 bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 scroll-mt-32"
|
|
},
|
|
"children": [
|
|
{
|
|
"id": "card_auto_blocking_policy_header",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "panel-header-row flex-between"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "H3",
|
|
"props": {
|
|
"className": "section-heading-md"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.section.auto_blocking"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "P",
|
|
"props": {
|
|
"className": "form-hint"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.section.auto_blocking_desc"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"props": {
|
|
"className": "inline-flex items-center px-2.5 py-0.5 rounded text-xs font-medium flex-shrink-0 ml-3 {{_local.form?.banner_enabled ? 'bg-green-100 dark:bg-green-900 text-success-soft' : 'bg-gray-100 dark:bg-gray-700 text-gray-600 dark:text-gray-400'}}"
|
|
},
|
|
"text": "{{_local.form?.banner_enabled ? '$t:sirsoft-gdpr.settings.status.enabled' : '$t:sirsoft-gdpr.settings.status.disabled'}}"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "card_auto_blocking_policy_fields",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "p-6 space-y-6"
|
|
},
|
|
"children": [
|
|
{
|
|
"id": "blocked_domains_off_hint",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"if": "{{!_local.form?.banner_enabled}}",
|
|
"comment": "쿠키 배너 노출 (banner_enabled) OFF 시 안내 박스. ON 으로 전환하면 배너 + 자동 차단이 함께 활성됨 (마이페이지 카드는 이 토글과 무관, 항상 노출)",
|
|
"props": {
|
|
"className": "bg-blue-50 dark:bg-gray-900 border border-gray-200 dark:border-gray-700 border-l-4 border-l-blue-500 dark:border-l-blue-400 rounded-lg p-4 flex-center gap-2"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Icon",
|
|
"props": {
|
|
"name": "circle-info",
|
|
"size": "sm",
|
|
"className": "text-blue-600 dark:text-blue-400 flex-shrink-0"
|
|
}
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"props": {
|
|
"className": "text-xs text-gray-800 dark:text-gray-100"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.fields.blocked_domains.auto_blocking_off_hint"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "subsection_blocked_domains",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"if": "{{_local.form?.banner_enabled === true}}",
|
|
"comment": "F-02 도메인 기반 추적 리소스 차단 — banner_enabled ON 일 때만 본문 노출. OFF 시 위쪽 인라인 안내가 대신 표시됨",
|
|
"props": {
|
|
"className": "row-stack"
|
|
},
|
|
"children": [
|
|
{
|
|
"id": "blocked_domains_warnings_box",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"comment": "안내 — 3항목 (외부 폰트 분류 주의 / 차단 도메인 변경 후 정책 버전 bump / 도메인 형식 FQDN). FQDN 안내를 박스 안으로 흡수하여 운영자 안내 영역을 단일 박스로 통합.",
|
|
"props": {
|
|
"className": "bg-blue-50 dark:bg-gray-900 border border-gray-200 dark:border-gray-700 border-l-4 border-l-blue-500 dark:border-l-blue-400 rounded-lg p-4"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "flex-center gap-2 mb-3"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Icon",
|
|
"props": {
|
|
"name": "circle-info",
|
|
"size": "sm",
|
|
"className": "text-blue-600 dark:text-blue-400"
|
|
}
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "H4",
|
|
"props": {
|
|
"className": "text-sm font-medium text-gray-900 dark:text-white"
|
|
},
|
|
"text": "$t:sirsoft-gdpr.settings.fields.blocked_domains.warnings_title"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Ul",
|
|
"props": {
|
|
"className": "list-disc list-inside space-y-1.5 text-xs text-gray-800 dark:text-gray-100 leading-relaxed"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Li",
|
|
"text": "$t:sirsoft-gdpr.settings.fields.blocked_domains.warning_visual_break"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Li",
|
|
"text": "$t:sirsoft-gdpr.settings.fields.blocked_domains.warning_policy_bump"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Li",
|
|
"text": "$t:sirsoft-gdpr.settings.fields.blocked_domains.warning_domain_format"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Li",
|
|
"text": "$t:sirsoft-gdpr.settings.fields.blocked_domains.warning_scope_limit"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "blocked_domains_taginputs_{{categoryIdx}}",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"comment": "카테고리별 TagInput iteration — necessary 제외. options 에 카탈로그 도메인을 추천 노출 (creatable=true 로 자유 입력 가능)",
|
|
"props": {
|
|
"className": "row-stack"
|
|
},
|
|
"iteration": {
|
|
"source": "(_local.form?.cookie_categories ?? []).filter(c => c?.key !== 'necessary')",
|
|
"item_var": "category",
|
|
"index_var": "categoryIdx"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"comment": "카테고리 차단 도메인 카드. 해당 카테고리에 422 검증 에러가 있으면 외곽 테두리를 빨간색으로 강조. 도메인 인덱스가 0이 아닐 수도 있으므로 'blocked_domains.{category}.' prefix 로 시작하는 키 *어느 것이든* 존재 여부 검사 (some).",
|
|
"props": {
|
|
"className": "{{Object.keys(_local.errors ?? {}).some(k => k.startsWith('blocked_domains.' + category.key + '.')) ? 'border border-red-500 dark:border-red-500 rounded-lg p-4 space-y-2 bg-red-50/30 dark:bg-red-900/10' : 'border border-gray-200 dark:border-gray-700 rounded-lg p-4 space-y-2'}}"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "flex-center gap-2"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Icon",
|
|
"if": "{{category?.key === 'functional'}}",
|
|
"props": {
|
|
"name": "sliders",
|
|
"size": "sm",
|
|
"className": "text-emerald-600 dark:text-emerald-400"
|
|
}
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Icon",
|
|
"if": "{{category?.key === 'analytics'}}",
|
|
"props": {
|
|
"name": "chart-line",
|
|
"size": "sm",
|
|
"className": "text-blue-600 dark:text-blue-400"
|
|
}
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Icon",
|
|
"if": "{{category?.key === 'marketing'}}",
|
|
"props": {
|
|
"name": "bullhorn",
|
|
"size": "sm",
|
|
"className": "text-purple-600 dark:text-purple-400"
|
|
}
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Label",
|
|
"props": {
|
|
"className": "form-label"
|
|
},
|
|
"text": "{{$localized(category?.label) || category?.key || ''}} ({{category?.key ?? ''}})"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"type": "composite",
|
|
"name": "TagInput",
|
|
"comment": "도메인 칩 입력. TagInput onChange 는 createFakeEvent 로 { target: { value: string[] } } 형태의 가짜 이벤트를 보내므로 $event.target.value 로 실제 배열 추출. options: 카탈로그 추천 (자동완성)",
|
|
"props": {
|
|
"value": "{{_local.form?.blocked_domains?.[category.key] ?? []}}",
|
|
"options": "{{((gdprSettings?.data?.default_blocked_domains_preview?.[category.key]) ?? []).map(d => ({ value: d, label: d }))}}",
|
|
"creatable": true,
|
|
"placeholder": "$t:sirsoft-gdpr.settings.fields.blocked_domains.tag_input_placeholder",
|
|
"noOptionsMessage": "$t:sirsoft-gdpr.settings.fields.blocked_domains.tag_no_options"
|
|
},
|
|
"actions": [
|
|
{
|
|
"type": "change",
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "local",
|
|
"form.blocked_domains": "{{({...(_local.form?.blocked_domains ?? {}), [category.key]: ($event?.target?.value ?? [])})}}",
|
|
"hasChanges": true
|
|
}
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"comment": "카테고리 내 첫 잘못된 도메인의 에러 메시지 (인덱스 무관). 운영자가 첫 에러를 정정하면 다음 에러가 자연스럽게 노출됨.",
|
|
"if": "{{Object.keys(_local.errors ?? {}).some(k => k.startsWith('blocked_domains.' + category.key + '.'))}}",
|
|
"props": {
|
|
"className": "form-error"
|
|
},
|
|
"text": "{{(Object.entries(_local.errors ?? {}).find(([k]) => k.startsWith('blocked_domains.' + category.key + '.'))?.[1]?.[0]) ?? ''}}"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "footer_buttons",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"comment": "하단 sticky 저장/취소 바 — 게시판 설정(admin_board_settings.json footer_buttons)과 동일 패턴으로 통일 (상단 헤더 배치는 스크롤 시 밀리는 것으로 오인되어 재배치).",
|
|
"props": {
|
|
"className": "sticky-footer-buttons"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"if": "{{_local.hasChanges}}",
|
|
"props": {
|
|
"className": "flex-center gap-1.5 text-sm text-amber-600 dark:text-amber-400 mr-auto"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Icon",
|
|
"props": {
|
|
"name": "circle-dot",
|
|
"size": "xs"
|
|
}
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"text": "$t:sirsoft-gdpr.settings.unsaved_changes"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "footer_cancel_button",
|
|
"type": "basic",
|
|
"name": "Button",
|
|
"props": {
|
|
"type": "button",
|
|
"className": "btn btn-secondary text-sm"
|
|
},
|
|
"actions": [
|
|
{
|
|
"type": "click",
|
|
"handler": "navigate",
|
|
"params": {
|
|
"path": "/admin/plugins"
|
|
}
|
|
}
|
|
],
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"text": "$t:common.cancel"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "footer_save_button",
|
|
"type": "basic",
|
|
"name": "Button",
|
|
"props": {
|
|
"type": "button",
|
|
"disabled": "{{!_local.hasChanges || _local.isSaving}}",
|
|
"className": "btn btn-primary flex-center gap-1.5 text-sm"
|
|
},
|
|
"actions": [
|
|
{
|
|
"type": "click",
|
|
"handler": "sequence",
|
|
"actions": [
|
|
{
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "local",
|
|
"isSaving": true,
|
|
"errors": null
|
|
}
|
|
},
|
|
{
|
|
"handler": "apiCall",
|
|
"auth_required": true,
|
|
"target": "/api/plugins/sirsoft-gdpr/admin/settings",
|
|
"params": {
|
|
"method": "PUT",
|
|
"body": "{{_local.form}}"
|
|
},
|
|
"onSuccess": [
|
|
{
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "local",
|
|
"isSaving": false,
|
|
"hasChanges": false
|
|
}
|
|
},
|
|
{
|
|
"handler": "refetchDataSource",
|
|
"params": {
|
|
"dataSourceId": "gdprSettings"
|
|
}
|
|
},
|
|
{
|
|
"handler": "toast",
|
|
"params": {
|
|
"type": "success",
|
|
"message": "$t:sirsoft-gdpr.settings.save_success"
|
|
}
|
|
}
|
|
],
|
|
"onError": [
|
|
{
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "local",
|
|
"isSaving": false,
|
|
"errors": "{{error.errors}}"
|
|
}
|
|
},
|
|
{
|
|
"handler": "toast",
|
|
"params": {
|
|
"type": "error",
|
|
"message": "{{Object.values(error.errors ?? {})[0]?.[0] ?? '$t:sirsoft-gdpr.settings.save_error'}}"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Icon",
|
|
"if": "{{_local.isSaving}}",
|
|
"props": {
|
|
"name": "spinner",
|
|
"size": "sm",
|
|
"spin": true
|
|
}
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"if": "{{!_local.isSaving}}",
|
|
"text": "$t:common.save"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"if": "{{_local.isSaving}}",
|
|
"text": "$t:common.saving"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
}
|