feat(core,admin_basic): .env 키 단위 우선 모드 추가

관리자 환경설정 저장값이 config 를 덮는 기존 설계는 공유호스팅을 1차 대상으로
삼은 결과다. .env 를 배포 기준값으로 관리하는 설치에서는 그 설계가 반대로
작동해, 설치기가 defaults 를 시드하는 순간부터 .env 의 28개 항목이 오류도
로그도 없이 사문화된다.

G7_ENV_PRIORITY 옵트인으로 그 소유권을 키 단위로 되돌린다. 스위치를 켜지 않은
설치는 전 경로가 조기 return 이라 동작이 100% 동일하다.

명시 여부는 config 빌드 시점에 캡처한다 — 런타임 env 는 config:cache 환경에서
null 로 고정되어 판정이 영구 미발동한다(attachment.disk_explicit 와 같은 함정).
판정은 strict 라 APP_DEBUG=false·REDIS_DB=0 같은 falsy 명시도 명시로 본다.

잠금은 그 키의 주입만 건너뛰는 것이지만, 제거된 키의 부재를 값으로 읽는 자리가
있으면 형제 설정까지 무너진다. 게이트(웹소켓 토글·메일 드라이버·디버그 모드)와
기본값 주입(mailgun.endpoint·ses.region), 형제 폴백(reverb server endpoint),
파생 판정(storage_driver→attachment.disk)을 유효값으로 보정했다.
This commit is contained in:
HeuJung
2026-09-04 10:08:30 +09:00
parent b97deee43a
commit 381fcc4e0b
37 changed files with 4026 additions and 118 deletions
@@ -121,7 +121,7 @@ admin/`)이 이 템플릿의 베이스(`_admin_base`)를 extends 하고 이 템
| 종류 | 개수 | 위치 |
|---|---|---|
| PHPUnit | 0개 | — |
| Vitest | 205개 | `vitest.config.ts` |
| Vitest | 206개 | `vitest.config.ts` |
| Playwright | 9개 | `tests/Playwright` |
| 시나리오 매니페스트 | 2개 | `tests/scenarios` |
@@ -16,6 +16,7 @@
- 개발자와 AI 에이전트를 위한 문서를 추가했습니다. 확장 폴더의 `AGENTS.md`(설계 의도·확장점·수정 시 확인할 것)와 `README.md`(도입·운영 안내), `docs/`(상세 문서)로 구성됩니다.
- 확장 문서에 「레이아웃 편집기 스펙」 항목을 추가했습니다. 이 확장이 레이아웃 편집기에 무엇을 선언했는지와, 화면 요소나 데이터를 추가할 때 편집기 쪽에서 함께 해야 할 일을 담습니다.
- 문서의 제품 표기를 「그누보드7」로 통일했습니다.
- `.env` 우선 모드를 켠 사이트에서 환경설정 화면이 그 사실을 알려 줍니다. 화면 상단에 안내가 표시되고, `.env` 로 고정된 항목은 「`.env` 고정」 표시와 함께 편집 불가로 바뀌며 실제로 적용 중인 값이 나타납니다. 비밀번호·시크릿 같은 항목은 고정 표시만 되고 값은 나타나지 않습니다. 모드를 켜지 않은 사이트는 종전과 동일합니다. (#37 @glitter-gim 님께서 건의해주셨습니다.)
### Changed
@@ -0,0 +1,364 @@
/**
* @file admin-settings-env-locked.test.tsx
* @description 환경설정 `.env` 잠금 UI 렌더링 테스트
*
* 테스트 대상:
* - `_meta.env_locked` 에 포함된 필드 → 잠금 배지 표시 + Input disabled
* - 포함되지 않은 필드 → 배지 없음 + Input 활성
* - `_meta.env_priority_enabled` → 안내 배너 표시/미표시
* - can_update:false 와의 OR 중첩 (권한 잠금 × env 잠금)
*
* 권한 중첩 축은 실브라우저(Chrome MCP 매트릭스 T9)에서 보조 계정을 만들 수 없어
* 이 레이아웃 테스트가 담당한다.
*
* @effects badge_and_disabled_rendered, switch_off_behaves_identically
*/
import React from 'react';
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import { createLayoutTest, screen } from '@core/template-engine/__tests__/utils/layoutTestUtils';
import { ComponentRegistry } from '@core/template-engine/ComponentRegistry';
const TestDiv: React.FC<{
className?: string;
children?: React.ReactNode;
'data-testid'?: string;
}> = ({ className, children, 'data-testid': testId }) => (
<div className={className} data-testid={testId}>{children}</div>
);
const TestInput: React.FC<{
className?: string;
disabled?: boolean;
type?: string;
name?: string;
'data-testid'?: string;
}> = ({ className, disabled, type, name, 'data-testid': testId }) => (
<input className={className} disabled={disabled} type={type} name={name} data-testid={testId || name} />
);
const TestSpan: React.FC<{
className?: string;
children?: React.ReactNode;
text?: string;
}> = ({ className, children, text }) => <span className={className}>{children || text}</span>;
const TestP: React.FC<{
className?: string;
children?: React.ReactNode;
text?: string;
}> = ({ className, children, text }) => <p className={className}>{children || text}</p>;
const TestIcon: React.FC<{ name?: string; className?: string }> = ({ name, className }) => (
<i className={className} data-icon={name} data-testid={`icon-${name}`} />
);
const TestLabel: React.FC<{
className?: string;
children?: React.ReactNode;
text?: string;
}> = ({ className, children, text }) => <label className={className}>{children || text}</label>;
const TestFragment: React.FC<{ children?: React.ReactNode }> = ({ children }) => <>{children}</>;
const TestBadge: React.FC<{
text?: string;
variant?: string;
size?: string;
className?: string;
'data-testid'?: string;
}> = ({ text, variant, size, className, 'data-testid': testId }) => (
<span className={className} data-variant={variant} data-size={size} data-testid={testId}>
{text}
</span>
);
function setupTestRegistry(): ComponentRegistry {
const registry = ComponentRegistry.getInstance();
(registry as any).registry = {
Div: { component: TestDiv, metadata: { name: 'Div', type: 'basic' } },
Input: { component: TestInput, metadata: { name: 'Input', type: 'basic' } },
Span: { component: TestSpan, metadata: { name: 'Span', type: 'basic' } },
P: { component: TestP, metadata: { name: 'P', type: 'basic' } },
Icon: { component: TestIcon, metadata: { name: 'Icon', type: 'basic' } },
Label: { component: TestLabel, metadata: { name: 'Label', type: 'basic' } },
Badge: { component: TestBadge, metadata: { name: 'Badge', type: 'composite' } },
Fragment: { component: TestFragment, metadata: { name: 'Fragment', type: 'layout' } },
};
return registry;
}
/**
* 설정 API 응답을 만듭니다.
*
* 프로덕션 레이아웃은 `initLocal.form` 을 거쳐 `_local.form._meta` 를 읽지만,
* 레이아웃 테스트 하네스는 initLocal 을 지원하지 않으므로 데이터소스를 직접 참조합니다.
*/
function createSettingsResponse(options: {
canUpdate: boolean;
envPriorityEnabled: boolean;
envLocked: Record<string, boolean>;
}) {
return {
success: true,
data: {
general: { site_name: 'Test Site', site_description: '설명' },
abilities: { can_update: options.canUpdate },
_meta: {
limits: {},
env_priority_enabled: options.envPriorityEnabled,
env_locked: options.envLocked,
},
},
};
}
const ENV_LOCKED = "settings?.data?._meta?.env_locked";
function lockExpr(key: string): string {
return `{{${ENV_LOCKED}?.['${key}'] === true}}`;
}
function disabledExpr(key: string): string {
return `{{(!!settings?.data && !(settings?.data?.abilities?.can_update ?? false)) || ${ENV_LOCKED}?.['${key}'] === true}}`;
}
const settingsLayout = {
version: '1.0.0',
layout_name: 'test_admin_settings_env_locked',
data_sources: [
{
id: 'settings',
type: 'api',
endpoint: '/api/admin/settings',
method: 'GET',
auto_fetch: true,
auth_required: true,
fallback: { data: [] },
},
],
components: [
{
id: 'settings_content',
type: 'basic',
name: 'Div',
children: [
{
id: 'env_priority_banner',
type: 'basic',
name: 'Div',
if: '{{settings?.data?._meta?.env_priority_enabled === true}}',
props: { className: 'alert-info', 'data-testid': 'env-priority-banner' },
children: [
{ type: 'basic', name: 'Icon', props: { name: 'lock' } },
{ type: 'basic', name: 'P', text: '.env 우선 모드' },
],
},
{
id: 'field_site_name',
type: 'basic',
name: 'Div',
children: [
{
type: 'basic',
name: 'Label',
children: [
{ type: 'basic', name: 'Span', text: '사이트 이름' },
{
type: 'composite',
name: 'Badge',
if: lockExpr('general.site_name'),
props: {
text: '.env 고정',
variant: 'secondary',
size: 'sm',
'data-testid': 'badge-site-name',
},
},
],
},
{
type: 'basic',
name: 'Input',
props: {
type: 'text',
name: 'general.site_name',
disabled: disabledExpr('general.site_name'),
'data-testid': 'input-site-name',
},
},
],
},
{
id: 'field_site_description',
type: 'basic',
name: 'Div',
children: [
{
type: 'basic',
name: 'Label',
children: [
{ type: 'basic', name: 'Span', text: '사이트 설명' },
{
type: 'composite',
name: 'Badge',
if: lockExpr('general.site_description'),
props: {
text: '.env 고정',
variant: 'secondary',
size: 'sm',
'data-testid': 'badge-site-description',
},
},
],
},
{
type: 'basic',
name: 'Input',
props: {
type: 'text',
name: 'general.site_description',
disabled: disabledExpr('general.site_description'),
'data-testid': 'input-site-description',
},
},
],
},
],
},
],
};
describe('admin-settings .env 잠금 UI', () => {
let registry: ComponentRegistry;
beforeEach(() => {
registry = setupTestRegistry();
});
afterEach(() => {
(registry as any).registry = {};
});
describe('스위치 ON + 일부 키 잠금', () => {
const response = createSettingsResponse({
canUpdate: true,
envPriorityEnabled: true,
envLocked: { 'general.site_name': true },
});
// @scenario switch=on, key_state=unlocked, surface=ui_lock
// @effects badge_and_disabled_rendered
it('안내 배너가 표시되어야 한다', async () => {
const testUtils = createLayoutTest(settingsLayout);
testUtils.mockApi('settings', { response });
await testUtils.render();
expect(screen.getByTestId('env-priority-banner')).toBeTruthy();
testUtils.cleanup();
});
// @scenario switch=on, key_state=locked_plain, surface=ui_lock
// @effects badge_and_disabled_rendered
it('잠긴 필드에만 배지가 렌더되어야 한다', async () => {
const testUtils = createLayoutTest(settingsLayout);
testUtils.mockApi('settings', { response });
await testUtils.render();
expect(screen.getByTestId('badge-site-name')).toBeTruthy();
expect(screen.queryByTestId('badge-site-description')).toBeNull();
testUtils.cleanup();
});
it('잠긴 필드만 disabled 여야 한다', async () => {
const testUtils = createLayoutTest(settingsLayout);
testUtils.mockApi('settings', { response });
await testUtils.render();
expect((screen.getByTestId('input-site-name') as HTMLInputElement).disabled).toBe(true);
expect((screen.getByTestId('input-site-description') as HTMLInputElement).disabled).toBe(false);
testUtils.cleanup();
});
});
describe('스위치 OFF (현행)', () => {
const response = createSettingsResponse({
canUpdate: true,
envPriorityEnabled: false,
envLocked: {},
});
// @scenario switch=off, key_state=unlocked, surface=ui_lock
// @effects switch_off_behaves_identically
it('배너와 배지가 모두 없어야 한다', async () => {
const testUtils = createLayoutTest(settingsLayout);
testUtils.mockApi('settings', { response });
await testUtils.render();
expect(screen.queryByTestId('env-priority-banner')).toBeNull();
expect(screen.queryByTestId('badge-site-name')).toBeNull();
expect(screen.queryByTestId('badge-site-description')).toBeNull();
testUtils.cleanup();
});
it('모든 필드가 활성이어야 한다', async () => {
const testUtils = createLayoutTest(settingsLayout);
testUtils.mockApi('settings', { response });
await testUtils.render();
expect((screen.getByTestId('input-site-name') as HTMLInputElement).disabled).toBe(false);
expect((screen.getByTestId('input-site-description') as HTMLInputElement).disabled).toBe(false);
testUtils.cleanup();
});
});
describe('권한 잠금 × env 잠금 (OR 중첩)', () => {
it('can_update:false 면 env 잠금과 무관하게 모두 disabled 여야 한다', async () => {
const testUtils = createLayoutTest(settingsLayout);
testUtils.mockApi('settings', {
response: createSettingsResponse({
canUpdate: false,
envPriorityEnabled: true,
envLocked: { 'general.site_name': true },
}),
});
await testUtils.render();
expect((screen.getByTestId('input-site-name') as HTMLInputElement).disabled).toBe(true);
expect((screen.getByTestId('input-site-description') as HTMLInputElement).disabled).toBe(true);
testUtils.cleanup();
});
it('can_update:false 여도 잠금 배지는 env 잠금 필드에만 붙어야 한다', async () => {
const testUtils = createLayoutTest(settingsLayout);
testUtils.mockApi('settings', {
response: createSettingsResponse({
canUpdate: false,
envPriorityEnabled: true,
envLocked: { 'general.site_name': true },
}),
});
await testUtils.render();
expect(screen.getByTestId('badge-site-name')).toBeTruthy();
expect(screen.queryByTestId('badge-site-description')).toBeNull();
testUtils.cleanup();
});
});
});
@@ -1307,6 +1307,8 @@
"page_title": "Settings",
"page_description": "Configure system settings.",
"readonly_notice": "These settings are read-only. Contact your administrator for edit access.",
"env_locked_badge": "Set in .env",
"env_locked_notice": "This site runs with .env priority enabled. Fields whose values are set in .env cannot be changed here, and the values shown are the ones actually in effect. To change them, edit .env on the server and rebuild the configuration cache.",
"tabs": {
"general": "General",
"mail": "Mail",
@@ -1311,6 +1311,8 @@
"page_title": "환경설정",
"page_description": "시스템 환경을 설정합니다.",
"readonly_notice": "이 설정은 읽기 전용입니다. 수정 권한이 필요한 경우 관리자에게 문의하세요.",
"env_locked_badge": ".env 고정",
"env_locked_notice": "이 사이트는 .env 우선 모드로 운영됩니다. .env 에 값이 지정된 항목은 여기서 변경할 수 없으며, 화면에는 실제로 적용 중인 값이 표시됩니다. 변경하려면 서버의 .env 를 수정한 뒤 설정 캐시를 다시 만드세요.",
"tabs": {
"general": "일반",
"mail": "메일",
@@ -10,7 +10,8 @@
"description": "$t:admin.settings.page_description"
},
"computed": {
"isReadOnly": "{{!!_global.settingsAbilities && !(_global.settingsAbilities?.can_update ?? false)}}"
"isReadOnly": "{{!!_global.settingsAbilities && !(_global.settingsAbilities?.can_update ?? false)}}",
"envLocked": "{{_local.form?._meta?.env_locked ?? null}}"
},
"transition_overlay": {
"target": "settings_tab_content",
@@ -427,6 +428,42 @@
}
]
},
{
"id": "env_priority_banner",
"type": "basic",
"name": "Div",
"if": "{{_local.form?._meta?.env_priority_enabled === true}}",
"props": {
"className": "alert-info"
},
"children": [
{
"type": "basic",
"name": "Div",
"props": {
"className": "flex-center gap-3"
},
"children": [
{
"type": "basic",
"name": "Icon",
"props": {
"name": "lock",
"className": "text-xl text-blue-600 dark:text-blue-400 flex-shrink-0"
}
},
{
"type": "basic",
"name": "P",
"props": {
"className": "text-info-soft"
},
"text": "$t:admin.settings.env_locked_notice"
}
]
}
]
},
{
"id": "sticky_header",
"type": "basic",
@@ -784,6 +784,17 @@
"className": "text-red-500 ml-1"
},
"text": "*"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['advanced.debug_mode'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
@@ -832,7 +843,7 @@
"props": {
"name": "advanced.debug_mode",
"size": "md",
"disabled": "{{_computed.isReadOnly}}"
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['advanced.debug_mode'] === true}}"
}
}
]
@@ -1314,6 +1325,17 @@
"className": "text-heading"
},
"text": "$t:admin.settings.advanced.core_update_github_url"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['advanced.core_update_github_url'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
@@ -1332,7 +1354,7 @@
"type": "url",
"name": "advanced.core_update_github_url",
"placeholder": "https://github.com/owner/repo",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['advanced.core_update_github_url'] === true}}",
"className": "input {{_local.errors?.['advanced.core_update_github_url'] ? 'input-error' : ''}}"
}
},
@@ -1366,6 +1388,17 @@
"className": "text-heading"
},
"text": "$t:admin.settings.advanced.core_update_github_token"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['advanced.core_update_github_token'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
@@ -1385,7 +1418,7 @@
"name": "advanced.core_update_github_token",
"placeholder": "ghp_xxxxxxxxxxxxxxxxxxxx",
"autoComplete": "off",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['advanced.core_update_github_token'] === true}}",
"className": "input {{_local.errors?.['advanced.core_update_github_token'] ? 'input-error' : ''}}"
}
},
@@ -1462,6 +1495,17 @@
"className": "text-label-subtle"
},
"text": "$t:admin.settings.advanced.geoip_enabled_desc"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['advanced.geoip_enabled'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
@@ -1471,7 +1515,7 @@
"props": {
"name": "advanced.geoip_enabled",
"size": "md",
"disabled": "{{_computed.isReadOnly}}"
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['advanced.geoip_enabled'] === true}}"
}
}
]
@@ -1507,6 +1551,17 @@
"className": "text-heading"
},
"text": "$t:admin.settings.advanced.geoip_license_key"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['advanced.geoip_license_key'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
@@ -1526,7 +1581,7 @@
"name": "advanced.geoip_license_key",
"placeholder": "xxxxxxxxxxxxxxxx",
"autoComplete": "off",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['advanced.geoip_license_key'] === true}}",
"className": "{{_local.errors?.['advanced.geoip_license_key'] ? 'input-error' : ''}}"
}
},
@@ -1568,6 +1623,17 @@
"className": "text-label-subtle"
},
"text": "$t:admin.settings.advanced.geoip_auto_update_enabled_desc"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['advanced.geoip_auto_update_enabled'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
@@ -1577,7 +1643,7 @@
"props": {
"name": "advanced.geoip_auto_update_enabled",
"size": "md",
"disabled": "{{_computed.isReadOnly}}"
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['advanced.geoip_auto_update_enabled'] === true}}"
}
}
]
@@ -53,7 +53,24 @@
"props": {
"className": "form-label"
},
"text": "$t:admin.settings.drivers.storage.driver"
"children": [
{
"type": "basic",
"name": "Span",
"text": "$t:admin.settings.drivers.storage.driver"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['drivers.storage_driver'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
{
"type": "basic",
@@ -67,7 +84,7 @@
"name": "Select",
"props": {
"name": "drivers.storage_driver",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['drivers.storage_driver'] === true}}",
"className": "w-full",
"error": "{{_local.errors?.['drivers.storage_driver']?.[0] ?? ''}}",
"options": "{{(_local.form?.available_drivers?.storage ?? []).map(d => ({value: d.id, label: $localized(d.label)}))}}"
@@ -139,7 +156,24 @@
"props": {
"className": "form-label"
},
"text": "$t:admin.settings.drivers.storage.s3_bucket"
"children": [
{
"type": "basic",
"name": "Span",
"text": "$t:admin.settings.drivers.storage.s3_bucket"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['drivers.s3_bucket'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
{
"type": "basic",
@@ -148,7 +182,7 @@
"type": "text",
"name": "drivers.s3_bucket",
"placeholder": "my-bucket",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['drivers.s3_bucket'] === true}}",
"className": "{{_local.errors?.['drivers.s3_bucket'] ? 'input-error md:w-64' : 'md:w-64'}}"
}
},
@@ -176,7 +210,24 @@
"props": {
"className": "form-label"
},
"text": "$t:admin.settings.drivers.storage.s3_region"
"children": [
{
"type": "basic",
"name": "Span",
"text": "$t:admin.settings.drivers.storage.s3_region"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['drivers.s3_region'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
{
"type": "basic",
@@ -185,7 +236,7 @@
"type": "text",
"name": "drivers.s3_region",
"placeholder": "ap-northeast-2",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['drivers.s3_region'] === true}}",
"className": "{{_local.errors?.['drivers.s3_region'] ? 'input-error md:w-64 font-mono' : 'md:w-64 font-mono'}}"
}
},
@@ -221,7 +272,24 @@
"props": {
"className": "form-label"
},
"text": "$t:admin.settings.drivers.storage.s3_access_key"
"children": [
{
"type": "basic",
"name": "Span",
"text": "$t:admin.settings.drivers.storage.s3_access_key"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['drivers.s3_access_key'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
{
"type": "basic",
@@ -230,7 +298,7 @@
"type": "text",
"name": "drivers.s3_access_key",
"placeholder": "AKIAIOSFODNN7EXAMPLE",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['drivers.s3_access_key'] === true}}",
"className": "{{_local.errors?.['drivers.s3_access_key'] ? 'input-error md:w-80 font-mono' : 'md:w-80 font-mono'}}"
}
},
@@ -258,7 +326,24 @@
"props": {
"className": "form-label"
},
"text": "$t:admin.settings.drivers.storage.s3_secret_key"
"children": [
{
"type": "basic",
"name": "Span",
"text": "$t:admin.settings.drivers.storage.s3_secret_key"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['drivers.s3_secret_key'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
{
"type": "basic",
@@ -267,7 +352,7 @@
"type": "password",
"name": "drivers.s3_secret_key",
"placeholder": "********",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['drivers.s3_secret_key'] === true}}",
"className": "{{_local.errors?.['drivers.s3_secret_key'] ? 'input-error md:w-80 font-mono' : 'md:w-80 font-mono'}}"
}
},
@@ -296,7 +381,24 @@
"props": {
"className": "form-label"
},
"text": "$t:admin.settings.drivers.storage.s3_endpoint"
"children": [
{
"type": "basic",
"name": "Span",
"text": "$t:admin.settings.drivers.storage.s3_endpoint"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['drivers.s3_endpoint'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
{
"type": "basic",
@@ -305,7 +407,7 @@
"type": "text",
"name": "drivers.s3_endpoint",
"placeholder": "https://<account-id>.r2.cloudflarestorage.com",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['drivers.s3_endpoint'] === true}}",
"className": "{{_local.errors?.['drivers.s3_endpoint'] ? 'input-error' : ''}}"
}
},
@@ -362,6 +464,17 @@
"className": "text-label-subtle"
},
"text": "$t:admin.settings.drivers.storage.s3_use_path_style_desc"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['drivers.s3_use_path_style'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
@@ -371,7 +484,7 @@
"props": {
"name": "drivers.s3_use_path_style",
"size": "md",
"disabled": "{{_computed.isReadOnly}}"
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['drivers.s3_use_path_style'] === true}}"
}
}
]
@@ -391,7 +504,24 @@
"props": {
"className": "form-label"
},
"text": "$t:admin.settings.drivers.storage.s3_url"
"children": [
{
"type": "basic",
"name": "Span",
"text": "$t:admin.settings.drivers.storage.s3_url"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['drivers.s3_url'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
{
"type": "basic",
@@ -400,7 +530,7 @@
"type": "text",
"name": "drivers.s3_url",
"placeholder": "https://my-bucket.s3.ap-northeast-2.amazonaws.com",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['drivers.s3_url'] === true}}",
"className": "{{_local.errors?.['drivers.s3_url'] ? 'input-error' : ''}}"
}
},
@@ -755,7 +885,24 @@
"props": {
"className": "form-label"
},
"text": "$t:admin.settings.drivers.cache.driver"
"children": [
{
"type": "basic",
"name": "Span",
"text": "$t:admin.settings.drivers.cache.driver"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['drivers.cache_driver'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
{
"type": "basic",
@@ -769,7 +916,7 @@
"name": "Select",
"props": {
"name": "drivers.cache_driver",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['drivers.cache_driver'] === true}}",
"className": "w-full",
"error": "{{_local.errors?.['drivers.cache_driver']?.[0] ?? ''}}",
"options": "{{(_local.form?.available_drivers?.cache ?? []).map(d => ({value: d.id, label: $localized(d.label)}))}}"
@@ -847,7 +994,24 @@
"props": {
"className": "form-label"
},
"text": "$t:admin.settings.drivers.cache.redis_host"
"children": [
{
"type": "basic",
"name": "Span",
"text": "$t:admin.settings.drivers.cache.redis_host"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['drivers.redis_host'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
{
"type": "basic",
@@ -856,7 +1020,7 @@
"type": "text",
"name": "drivers.redis_host",
"placeholder": "127.0.0.1",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['drivers.redis_host'] === true}}",
"className": "{{_local.errors?.['drivers.redis_host'] ? 'input-error' : ''}}"
}
},
@@ -884,7 +1048,24 @@
"props": {
"className": "form-label"
},
"text": "$t:admin.settings.drivers.cache.redis_port"
"children": [
{
"type": "basic",
"name": "Span",
"text": "$t:admin.settings.drivers.cache.redis_port"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['drivers.redis_port'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
{
"type": "basic",
@@ -895,7 +1076,7 @@
"placeholder": "6379",
"min": "{{_local?.form?._meta?.limits?.drivers_redis_port_min ?? 1}}",
"max": "{{_local?.form?._meta?.limits?.drivers_redis_port_max ?? 65535}}",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['drivers.redis_port'] === true}}",
"className": "{{_local.errors?.['drivers.redis_port'] ? 'input-error' : ''}}"
}
},
@@ -932,7 +1113,24 @@
"props": {
"className": "form-label"
},
"text": "$t:admin.settings.drivers.cache.redis_password"
"children": [
{
"type": "basic",
"name": "Span",
"text": "$t:admin.settings.drivers.cache.redis_password"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['drivers.redis_password'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
{
"type": "basic",
@@ -941,7 +1139,7 @@
"type": "password",
"name": "drivers.redis_password",
"placeholder": "$t:admin.settings.drivers.common.optional",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['drivers.redis_password'] === true}}",
"className": "{{_local.errors?.['drivers.redis_password'] ? 'input-error' : ''}}"
}
},
@@ -969,7 +1167,24 @@
"props": {
"className": "form-label"
},
"text": "$t:admin.settings.drivers.cache.redis_database"
"children": [
{
"type": "basic",
"name": "Span",
"text": "$t:admin.settings.drivers.cache.redis_database"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['drivers.redis_database'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
{
"type": "basic",
@@ -980,7 +1195,7 @@
"placeholder": "0",
"min": "{{_local?.form?._meta?.limits?.drivers_redis_database_min ?? 0}}",
"max": "{{_local?.form?._meta?.limits?.drivers_redis_database_max ?? 15}}",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['drivers.redis_database'] === true}}",
"className": "{{_local.errors?.['drivers.redis_database'] ? 'input-error' : ''}}"
}
},
@@ -1184,7 +1399,24 @@
"props": {
"className": "form-label"
},
"text": "$t:admin.settings.drivers.cache.memcached_host"
"children": [
{
"type": "basic",
"name": "Span",
"text": "$t:admin.settings.drivers.cache.memcached_host"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['drivers.memcached_host'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
{
"type": "basic",
@@ -1193,7 +1425,7 @@
"type": "text",
"name": "drivers.memcached_host",
"placeholder": "127.0.0.1",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['drivers.memcached_host'] === true}}",
"className": "{{_local.errors?.['drivers.memcached_host'] ? 'input-error' : ''}}"
}
},
@@ -1221,7 +1453,24 @@
"props": {
"className": "form-label"
},
"text": "$t:admin.settings.drivers.cache.memcached_port"
"children": [
{
"type": "basic",
"name": "Span",
"text": "$t:admin.settings.drivers.cache.memcached_port"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['drivers.memcached_port'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
{
"type": "basic",
@@ -1232,7 +1481,7 @@
"placeholder": "11211",
"min": "{{_local?.form?._meta?.limits?.drivers_memcached_port_min ?? 1}}",
"max": "{{_local?.form?._meta?.limits?.drivers_memcached_port_max ?? 65535}}",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['drivers.memcached_port'] === true}}",
"className": "{{_local.errors?.['drivers.memcached_port'] ? 'input-error' : ''}}"
}
},
@@ -1454,7 +1703,24 @@
"props": {
"className": "form-label"
},
"text": "$t:admin.settings.drivers.search_engine.driver"
"children": [
{
"type": "basic",
"name": "Span",
"text": "$t:admin.settings.drivers.search_engine.driver"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['drivers.search_engine_driver'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
{
"type": "basic",
@@ -1468,7 +1734,7 @@
"name": "Select",
"props": {
"name": "drivers.search_engine_driver",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['drivers.search_engine_driver'] === true}}",
"className": "w-full",
"error": "{{_local.errors?.['drivers.search_engine_driver']?.[0] ?? ''}}",
"options": "{{(_local.form?.available_drivers?.search ?? []).map(d => ({value: d.id, label: $localized(d.label)}))}}"
@@ -1599,7 +1865,24 @@
"props": {
"className": "form-label"
},
"text": "$t:admin.settings.drivers.session.driver"
"children": [
{
"type": "basic",
"name": "Span",
"text": "$t:admin.settings.drivers.session.driver"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['drivers.session_driver'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
{
"type": "basic",
@@ -1613,7 +1896,7 @@
"name": "Select",
"props": {
"name": "drivers.session_driver",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['drivers.session_driver'] === true}}",
"className": "w-full",
"error": "{{_local.errors?.['drivers.session_driver']?.[0] ?? ''}}",
"options": "{{(_local.form?.available_drivers?.session ?? []).map(d => ({value: d.id, label: $localized(d.label)}))}}"
@@ -1699,7 +1982,24 @@
"props": {
"className": "form-label"
},
"text": "$t:admin.settings.drivers.session.lifetime"
"children": [
{
"type": "basic",
"name": "Span",
"text": "$t:admin.settings.drivers.session.lifetime"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['drivers.session_lifetime'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
{
"type": "basic",
@@ -1717,7 +2017,7 @@
"placeholder": "120",
"min": "{{_local?.form?._meta?.limits?.drivers_session_lifetime_min ?? 1}}",
"max": "{{_local?.form?._meta?.limits?.drivers_session_lifetime_max ?? 43200}}",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['drivers.session_lifetime'] === true}}",
"className": "{{_local.errors?.['drivers.session_lifetime'] ? 'input-error w-32' : 'w-32'}}"
}
},
@@ -1788,7 +2088,24 @@
"props": {
"className": "form-label"
},
"text": "$t:admin.settings.drivers.queue.driver"
"children": [
{
"type": "basic",
"name": "Span",
"text": "$t:admin.settings.drivers.queue.driver"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['drivers.queue_driver'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
{
"type": "basic",
@@ -1802,7 +2119,7 @@
"name": "Select",
"props": {
"name": "drivers.queue_driver",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['drivers.queue_driver'] === true}}",
"className": "w-full",
"error": "{{_local.errors?.['drivers.queue_driver']?.[0] ?? ''}}",
"options": "{{(_local.form?.available_drivers?.queue ?? []).map(d => ({value: d.id, label: $localized(d.label)}))}}"
@@ -1972,7 +2289,24 @@
"props": {
"className": "form-label"
},
"text": "$t:admin.settings.drivers.log.driver"
"children": [
{
"type": "basic",
"name": "Span",
"text": "$t:admin.settings.drivers.log.driver"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['drivers.log_driver'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
{
"type": "basic",
@@ -1986,7 +2320,7 @@
"name": "Select",
"props": {
"name": "drivers.log_driver",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['drivers.log_driver'] === true}}",
"className": "w-full",
"error": "{{_local.errors?.['drivers.log_driver']?.[0] ?? ''}}",
"options": "{{(_local.form?.available_drivers?.log ?? []).map(d => ({value: d.id, label: $localized(d.label)}))}}"
@@ -2049,7 +2383,24 @@
"props": {
"className": "form-label"
},
"text": "$t:admin.settings.drivers.log.level"
"children": [
{
"type": "basic",
"name": "Span",
"text": "$t:admin.settings.drivers.log.level"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['drivers.log_level'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
{
"type": "basic",
@@ -2063,7 +2414,7 @@
"name": "Select",
"props": {
"name": "drivers.log_level",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['drivers.log_level'] === true}}",
"className": "w-full",
"error": "{{_local.errors?.['drivers.log_level']?.[0] ?? ''}}",
"options": [
@@ -2145,7 +2496,24 @@
"props": {
"className": "form-label"
},
"text": "$t:admin.settings.drivers.log.retention_days"
"children": [
{
"type": "basic",
"name": "Span",
"text": "$t:admin.settings.drivers.log.retention_days"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['drivers.log_days'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
{
"type": "basic",
@@ -2163,7 +2531,7 @@
"placeholder": "14",
"min": "{{_local?.form?._meta?.limits?.drivers_log_days_min ?? 1}}",
"max": "{{_local?.form?._meta?.limits?.drivers_log_days_max ?? 365}}",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['drivers.log_days'] === true}}",
"className": "{{_local.errors?.['drivers.log_days'] ? 'input-error w-32' : 'w-32'}}"
}
},
@@ -2290,6 +2658,17 @@
"className": "text-label-subtle"
},
"text": "$t:admin.settings.drivers.websocket.enabled_desc"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['drivers.websocket_enabled'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
@@ -2299,7 +2678,7 @@
"props": {
"name": "drivers.websocket_enabled",
"size": "md",
"disabled": "{{_computed.isReadOnly}}"
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['drivers.websocket_enabled'] === true}}"
}
}
]
@@ -2346,6 +2725,17 @@
"className": "text-red-500 ml-1"
},
"text": "*"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['drivers.websocket_app_id'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
@@ -2357,7 +2747,7 @@
"name": "drivers.websocket_app_id",
"placeholder": "my-app-id",
"required": true,
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['drivers.websocket_app_id'] === true}}",
"className": "{{_local.errors?.['drivers.websocket_app_id'] ? 'input-error font-mono' : 'font-mono'}}"
}
},
@@ -2398,6 +2788,17 @@
"className": "text-red-500 ml-1"
},
"text": "*"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['drivers.websocket_app_key'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
@@ -2409,7 +2810,7 @@
"name": "drivers.websocket_app_key",
"placeholder": "my-app-key",
"required": true,
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['drivers.websocket_app_key'] === true}}",
"className": "{{_local.errors?.['drivers.websocket_app_key'] ? 'input-error font-mono' : 'font-mono'}}"
}
},
@@ -2450,6 +2851,17 @@
"className": "text-red-500 ml-1"
},
"text": "*"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['drivers.websocket_app_secret'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
@@ -2461,7 +2873,7 @@
"name": "drivers.websocket_app_secret",
"placeholder": "my-app-secret",
"required": true,
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['drivers.websocket_app_secret'] === true}}",
"className": "{{_local.errors?.['drivers.websocket_app_secret'] ? 'input-error font-mono' : 'font-mono'}}"
}
},
@@ -2624,7 +3036,7 @@
"id": "input_websocket_verify_ssl",
"type": "checkbox",
"name": "drivers.websocket_verify_ssl",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['drivers.websocket_verify_ssl'] === true}}",
"className": "h-4 w-4 text-blue-600 rounded"
}
},
@@ -2639,7 +3051,24 @@
"htmlFor": "input_websocket_verify_ssl",
"className": "text-body font-medium cursor-pointer"
},
"text": "$t:admin.settings.drivers.websocket.verify_ssl"
"children": [
{
"type": "basic",
"name": "Span",
"text": "$t:admin.settings.drivers.websocket.verify_ssl"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['drivers.websocket_verify_ssl'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
{
"type": "basic",
@@ -2689,7 +3118,24 @@
"props": {
"className": "form-label"
},
"text": "$t:admin.settings.drivers.websocket.server_host"
"children": [
{
"type": "basic",
"name": "Span",
"text": "$t:admin.settings.drivers.websocket.server_host"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['drivers.websocket_server_host'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
{
"type": "basic",
@@ -2698,7 +3144,7 @@
"type": "text",
"name": "drivers.websocket_server_host",
"placeholder": "127.0.0.1",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['drivers.websocket_server_host'] === true}}",
"className": "{{_local.errors?.['drivers.websocket_server_host'] ? 'input-error' : ''}}"
}
},
@@ -2726,7 +3172,24 @@
"props": {
"className": "form-label"
},
"text": "$t:admin.settings.drivers.websocket.server_port"
"children": [
{
"type": "basic",
"name": "Span",
"text": "$t:admin.settings.drivers.websocket.server_port"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['drivers.websocket_server_port'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
{
"type": "basic",
@@ -2737,7 +3200,7 @@
"placeholder": "8080",
"min": "{{_local?.form?._meta?.limits?.drivers_websocket_server_port_min ?? 1}}",
"max": "{{_local?.form?._meta?.limits?.drivers_websocket_server_port_max ?? 65535}}",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['drivers.websocket_server_port'] === true}}",
"className": "{{_local.errors?.['drivers.websocket_server_port'] ? 'input-error' : ''}}"
}
},
@@ -2765,14 +3228,31 @@
"props": {
"className": "form-label"
},
"text": "$t:admin.settings.drivers.websocket.server_scheme"
"children": [
{
"type": "basic",
"name": "Span",
"text": "$t:admin.settings.drivers.websocket.server_scheme"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['drivers.websocket_server_scheme'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
{
"type": "composite",
"name": "Select",
"props": {
"name": "drivers.websocket_server_scheme",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['drivers.websocket_server_scheme'] === true}}",
"className": "w-full",
"error": "{{_local.errors?.['drivers.websocket_server_scheme']?.[0] ?? ''}}",
"options": [
@@ -70,6 +70,17 @@
"className": "text-red-500 ml-1"
},
"text": "*"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['general.site_name'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
@@ -80,7 +91,7 @@
"type": "text",
"name": "general.site_name",
"placeholder": "그누보드7",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['general.site_name'] === true}}",
"className": "input {{_local.errors?.['general.site_name'] ? 'input-error' : ''}}"
}
},
@@ -119,6 +130,17 @@
"className": "text-red-500 ml-1"
},
"text": "*"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['general.site_url'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
@@ -129,7 +151,7 @@
"type": "url",
"name": "general.site_url",
"placeholder": "https://example.com",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['general.site_url'] === true}}",
"className": "input {{_local.errors?.['general.site_url'] ? 'input-error' : ''}}"
}
},
@@ -386,6 +408,17 @@
"className": "text-red-500 ml-1"
},
"text": "*"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['general.language'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
@@ -395,7 +428,7 @@
"props": {
"name": "general.language",
"className": "w-full",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['general.language'] === true}}",
"placeholder": "$t:admin.settings.general.select_language",
"options": "{{(_global.appConfig?.supportedLocales ?? ['ko', 'en']).map(l => ({ value: l, label: _global.appConfig?.localeNames?.[l] ?? l }))}}",
"error": "{{_local.errors?.['general.language']?.[0] ?? ''}}"
@@ -436,6 +469,17 @@
"className": "text-red-500 ml-1"
},
"text": "*"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['general.timezone'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
@@ -445,7 +489,7 @@
"props": {
"name": "general.timezone",
"className": "w-full",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['general.timezone'] === true}}",
"placeholder": "$t:admin.settings.general.select_timezone",
"options": "{{_global.appConfig?.supportedTimezones ?? []}}",
"searchable": true,
@@ -71,6 +71,17 @@
"className": "text-red-500 ml-1"
},
"text": "*"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['mail.mailer'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
@@ -80,7 +91,7 @@
"props": {
"name": "mail.mailer",
"className": "w-full",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['mail.mailer'] === true}}",
"placeholder": "$t:admin.settings.mail.select_mailer",
"options": "{{(_local.form?.available_drivers?.mail ?? []).map(d => ({value: d.id, label: $localized(d.label)}))}}",
"error": "{{_local.errors?.['mail.mailer']?.[0] ?? ''}}"
@@ -200,6 +211,17 @@
"className": "text-red-500 ml-1"
},
"text": "*"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['mail.host'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
@@ -210,7 +232,7 @@
"type": "text",
"name": "mail.host",
"placeholder": "smtp.example.com",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['mail.host'] === true}}",
"className": "input {{_local.errors?.['mail.host'] ? 'input-error' : ''}}"
}
},
@@ -258,6 +280,17 @@
"className": "text-red-500 ml-1"
},
"text": "*"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['mail.port'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
@@ -268,7 +301,7 @@
"type": "number",
"name": "mail.port",
"placeholder": "587",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['mail.port'] === true}}",
"className": "input {{_local.errors?.['mail.port'] ? 'input-error' : ''}}"
}
},
@@ -294,7 +327,24 @@
"props": {
"className": "form-label"
},
"text": "$t:admin.settings.mail.username"
"children": [
{
"type": "basic",
"name": "Span",
"text": "$t:admin.settings.mail.username"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['mail.username'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
{
"type": "basic",
@@ -303,7 +353,7 @@
"type": "text",
"name": "mail.username",
"placeholder": "your@email.com",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['mail.username'] === true}}",
"className": "input"
}
}
@@ -322,7 +372,24 @@
"props": {
"className": "form-label"
},
"text": "$t:admin.settings.mail.password"
"children": [
{
"type": "basic",
"name": "Span",
"text": "$t:admin.settings.mail.password"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['mail.password'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
{
"type": "basic",
@@ -331,7 +398,7 @@
"type": "password",
"name": "mail.password",
"placeholder": "********",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['mail.password'] === true}}",
"className": "input"
}
}
@@ -379,6 +446,17 @@
"className": "text-red-500 ml-1"
},
"text": "*"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['mail.mailgun_domain'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
@@ -389,7 +467,7 @@
"type": "text",
"name": "mail.mailgun_domain",
"placeholder": "mg.example.com",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['mail.mailgun_domain'] === true}}",
"className": "input {{_local.errors?.['mail.mailgun_domain'] ? 'input-error' : ''}}"
}
},
@@ -428,6 +506,17 @@
"className": "text-red-500 ml-1"
},
"text": "*"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['mail.mailgun_secret'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
@@ -438,7 +527,7 @@
"type": "password",
"name": "mail.mailgun_secret",
"placeholder": "key-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['mail.mailgun_secret'] === true}}",
"className": "input {{_local.errors?.['mail.mailgun_secret'] ? 'input-error' : ''}}"
}
},
@@ -466,7 +555,24 @@
"props": {
"className": "form-label"
},
"text": "$t:admin.settings.mail.mailgun_endpoint"
"children": [
{
"type": "basic",
"name": "Span",
"text": "$t:admin.settings.mail.mailgun_endpoint"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['mail.mailgun_endpoint'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
{
"type": "basic",
@@ -475,7 +581,7 @@
"type": "text",
"name": "mail.mailgun_endpoint",
"placeholder": "api.mailgun.net",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['mail.mailgun_endpoint'] === true}}",
"className": "input"
}
}
@@ -523,6 +629,17 @@
"className": "text-red-500 ml-1"
},
"text": "*"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['mail.ses_key'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
@@ -533,7 +650,7 @@
"type": "text",
"name": "mail.ses_key",
"placeholder": "AKIAIOSFODNN7EXAMPLE",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['mail.ses_key'] === true}}",
"className": "input {{_local.errors?.['mail.ses_key'] ? 'input-error' : ''}}"
}
},
@@ -572,6 +689,17 @@
"className": "text-red-500 ml-1"
},
"text": "*"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['mail.ses_secret'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
@@ -582,7 +710,7 @@
"type": "password",
"name": "mail.ses_secret",
"placeholder": "********",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['mail.ses_secret'] === true}}",
"className": "input {{_local.errors?.['mail.ses_secret'] ? 'input-error' : ''}}"
}
},
@@ -623,6 +751,17 @@
"className": "text-red-500 ml-1"
},
"text": "*"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['mail.ses_region'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
@@ -632,7 +771,7 @@
"props": {
"name": "mail.ses_region",
"className": "w-full",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['mail.ses_region'] === true}}",
"placeholder": "$t:admin.settings.mail.select_ses_region",
"options": [
{
@@ -711,6 +850,17 @@
"className": "text-red-500 ml-1"
},
"text": "*"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['mail.from_address'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
@@ -721,7 +871,7 @@
"type": "email",
"name": "mail.from_address",
"placeholder": "noreply@example.com",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['mail.from_address'] === true}}",
"className": "input {{_local.errors?.['mail.from_address'] ? 'input-error' : ''}}"
}
},
@@ -760,6 +910,17 @@
"className": "text-red-500 ml-1"
},
"text": "*"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['mail.from_name'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
@@ -770,7 +931,7 @@
"type": "text",
"name": "mail.from_name",
"placeholder": "그누보드7",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['mail.from_name'] === true}}",
"className": "input {{_local.errors?.['mail.from_name'] ? 'input-error' : ''}}"
}
},
@@ -67,6 +67,17 @@
"className": "text-red-500 ml-1"
},
"text": "*"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['upload.max_file_size'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
@@ -85,7 +96,7 @@
"name": "upload.max_file_size",
"min": "{{_local?.form?._meta?.limits?.upload_max_file_size_min ?? 1}}",
"max": "{{_local?.form?._meta?.limits?.upload_max_file_size_max ?? 1024}}",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['upload.max_file_size'] === true}}",
"className": "input flex-1 {{_local.errors?.['upload.max_file_size'] ? 'input-error' : ''}}"
}
},
@@ -215,7 +226,24 @@
"props": {
"className": "form-label"
},
"text": "$t:admin.settings.upload.image_max_width"
"children": [
{
"type": "basic",
"name": "Span",
"text": "$t:admin.settings.upload.image_max_width"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['upload.image_max_width'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
{
"type": "basic",
@@ -232,7 +260,7 @@
"name": "upload.image_max_width",
"min": "{{_local?.form?._meta?.limits?.upload_image_max_width_min ?? 100}}",
"max": "{{_local?.form?._meta?.limits?.upload_image_max_width_max ?? 10000}}",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['upload.image_max_width'] === true}}",
"className": "input flex-1"
}
},
@@ -259,7 +287,24 @@
"props": {
"className": "form-label"
},
"text": "$t:admin.settings.upload.image_max_height"
"children": [
{
"type": "basic",
"name": "Span",
"text": "$t:admin.settings.upload.image_max_height"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['upload.image_max_height'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
{
"type": "basic",
@@ -276,7 +321,7 @@
"name": "upload.image_max_height",
"min": "{{_local?.form?._meta?.limits?.upload_image_max_height_min ?? 100}}",
"max": "{{_local?.form?._meta?.limits?.upload_image_max_height_max ?? 10000}}",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['upload.image_max_height'] === true}}",
"className": "input flex-1"
}
},
@@ -303,7 +348,24 @@
"props": {
"className": "form-label"
},
"text": "$t:admin.settings.upload.image_quality"
"children": [
{
"type": "basic",
"name": "Span",
"text": "$t:admin.settings.upload.image_quality"
},
{
"type": "composite",
"name": "Badge",
"if": "{{_computed.envLocked?.['upload.image_quality'] === true}}",
"props": {
"text": "$t:admin.settings.env_locked_badge",
"variant": "secondary",
"size": "sm",
"className": "ml-2"
}
}
]
},
{
"type": "basic",
@@ -320,7 +382,7 @@
"name": "upload.image_quality",
"min": "{{_local?.form?._meta?.limits?.upload_image_quality_min ?? 1}}",
"max": "{{_local?.form?._meta?.limits?.upload_image_quality_max ?? 100}}",
"disabled": "{{_computed.isReadOnly}}",
"disabled": "{{_computed.isReadOnly || _computed.envLocked?.['upload.image_quality'] === true}}",
"className": "input flex-1"
}
},