Skip to content

Commit

Permalink
fix(ui/sidebar): show env variables in sidebar settings ui (#946)
Browse files Browse the repository at this point in the history
  • Loading branch information
qwqcode committed Aug 19, 2024
1 parent 528847d commit 006db5b
Show file tree
Hide file tree
Showing 10 changed files with 113 additions and 11 deletions.
7 changes: 7 additions & 0 deletions docs/swagger/docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -4970,9 +4970,16 @@ const docTemplate = `{
"handler.ResponseSettingGet": {
"type": "object",
"required": [
"envs",
"yaml"
],
"properties": {
"envs": {
"type": "array",
"items": {
"type": "string"
}
},
"yaml": {
"type": "string"
}
Expand Down
7 changes: 7 additions & 0 deletions docs/swagger/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -4963,9 +4963,16 @@
"handler.ResponseSettingGet": {
"type": "object",
"required": [
"envs",
"yaml"
],
"properties": {
"envs": {
"type": "array",
"items": {
"type": "string"
}
},
"yaml": {
"type": "string"
}
Expand Down
5 changes: 5 additions & 0 deletions docs/swagger/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1012,9 +1012,14 @@ definitions:
type: object
handler.ResponseSettingGet:
properties:
envs:
items:
type: string
type: array
yaml:
type: string
required:
- envs
- yaml
type: object
handler.ResponseSettingTemplate:
Expand Down
11 changes: 10 additions & 1 deletion server/handler/setting_get.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@ package handler

import (
"os"
"strings"

"github.com/ArtalkJS/Artalk/internal/core"
"github.com/ArtalkJS/Artalk/internal/i18n"
"github.com/ArtalkJS/Artalk/server/common"
"github.com/gofiber/fiber/v2"
"github.com/samber/lo"
)

type ResponseSettingGet struct {
Yaml string `json:"yaml"`
Yaml string `json:"yaml"`
Envs []string `json:"envs"`
}

// @Id GetSettings
Expand All @@ -30,8 +33,14 @@ func SettingGet(app *core.App, router fiber.Router) {
return common.RespError(c, 500, i18n.T("Config file read failed"))
}

// get all environment variables which start with ATK_
envs := lo.Filter(os.Environ(), func(v string, _ int) bool {
return strings.HasPrefix(v, "ATK_")
})

return common.RespData(c, ResponseSettingGet{
Yaml: string(dat),
Envs: envs,
})
}))
}
20 changes: 16 additions & 4 deletions ui/artalk-sidebar/src/components/PreferenceArr.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,22 @@ const props = defineProps<{
}>()
const customValue = ref<string[]>([])
const disabled = ref(false)
onMounted(() => {
sync()
})
function sync() {
const value = settings.get().getCustom(props.node.path)
customValue.value = value && typeof value.toJSON === 'function' ? value.toJSON() : []
disabled.value = !!settings.get().getEnvByPath(props.node.path)
if (typeof value === 'object' && 'toJSON' in value && typeof value.toJSON === 'function') {
customValue.value = value.toJSON()
} else if (typeof value === 'string') {
customValue.value = value.split(' ')
} else {
customValue.value = []
}
}
function save() {
Expand Down Expand Up @@ -43,21 +51,25 @@ function add() {
<input
type="text"
:value="String(item)"
:disabled="disabled"
@change="onChange(index, ($event.target as any).value)"
/>
<button class="act-btn" @click="remove(index)">-</button>
<button v-if="!disabled" class="act-btn" @click="remove(index)">-</button>
</div>
<div class="act-grp">
<div v-if="!disabled" class="act-grp">
<button class="act-btn" @click="add()">+</button>
</div>
</div>
</template>

<style scoped lang="scss">
.arr-grp {
width: 100%;
}
.arr-item {
position: relative;
margin-bottom: 20px;
margin-left: 10px;
padding-right: 50px;
.act-btn {
Expand Down
34 changes: 31 additions & 3 deletions ui/artalk-sidebar/src/components/PreferenceItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,14 @@ const props = defineProps<{
}>()
const value = ref('')
const disabled = ref(false)
const { t } = useI18n()
onBeforeMount(() => {
// initial value
value.value = settings.get().getCustom(props.node.path)
disabled.value = !!settings.get().getEnvByPath(props.node.path)
})
function onChange() {
Expand All @@ -27,14 +31,18 @@ function onChange() {
</div>

<div class="value">
<div v-if="disabled" class="disable-note">
{{ t('envVarControlHint', { key: 'ATK_' + props.node.path.toUpperCase() }) }}
</div>

<!-- Array -->
<template v-if="node.type === 'array'">
<PreferenceArr :node="node" />
</template>

<!-- 候选框 -->
<template v-else-if="node.selector">
<select v-model="value" @change="onChange">
<select v-model="value" :disabled="disabled" @change="onChange">
<option v-for="(item, i) in node.selector" :key="i" :value="item">
{{ item }}
</option>
Expand All @@ -43,12 +51,12 @@ function onChange() {

<!-- 开关 -->
<template v-else-if="node.type === 'boolean'">
<input v-model="value" type="checkbox" @change="onChange" />
<input v-model="value" type="checkbox" :disabled="disabled" @change="onChange" />
</template>

<!-- 文本框 -->
<template v-else>
<input v-model="value" type="text" @change="onChange" />
<input v-model="value" type="text" :disabled="disabled" @change="onChange" />
</template>
</div>
</div>
Expand Down Expand Up @@ -78,12 +86,32 @@ function onChange() {
}
& > .value {
position: relative;
flex: 1;
display: flex;
flex-direction: row;
justify-content: flex-end;
align-items: center;
min-height: 35px;
&:hover {
.disable-note {
opacity: 1;
}
}
.disable-note {
z-index: 999;
padding: 3px 8px;
background: rgba(105, 113, 130, 0.9);
color: #fff;
position: absolute;
top: -30px;
font-size: 13px;
left: 0;
opacity: 0;
transition: opacity 0.2s;
}
}
}
</style>
3 changes: 3 additions & 0 deletions ui/artalk-sidebar/src/i18n/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const en = {
commentAllowAll: 'Anyone Comment',
commentOnlyAdmin: 'Admin Comment Only',
config: 'Config',
envVarControlHint: 'Referenced by the environment variable {key}',
userAdminHint: 'Admin user',
userInConfHint: 'This user is defined in config file',
edit: 'Edit',
Expand Down Expand Up @@ -118,6 +119,7 @@ const zhCN: typeof en = {
commentAllowAll: '所有人可评',
commentOnlyAdmin: '仅管理员可评',
config: '配置文件',
envVarControlHint: '由环境变量 {key} 控制',
userAdminHint: '该用户具有管理员权限',
userInConfHint: '该用户存在于配置文件中',
edit: '编辑',
Expand Down Expand Up @@ -201,6 +203,7 @@ const zhTW: typeof en = {
commentAllowAll: '允許任何人評論',
commentOnlyAdmin: '僅允許管理員評論',
config: '配置文件',
envVarControlHint: '由環境變數 {key} 參照',
userAdminHint: '該用戶具有管理員權限',
userInConfHint: '該用戶存在於配置文件中',
edit: '編輯',
Expand Down
29 changes: 29 additions & 0 deletions ui/artalk-sidebar/src/lib/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export class Settings {
private tree: OptionNode
private flatten: { [path: string]: OptionNode }
private customs = shallowRef<YAML.Document.Parsed<YAML.ParsedNode>>()
private envs = shallowRef<{ [key: string]: string }>()

constructor(yamlObj: YAML.Document.Parsed) {
this.tree = getTree(yamlObj)
Expand All @@ -27,7 +28,35 @@ export class Settings {
this.customs.value = YAML.parseDocument(yamlStr)
}

setEnvs(envs: string[]) {
const envsObj: { [key: string]: string } = {}
envs.forEach((env) => {
const [key, value] = env.split('=')
envsObj[key] = value
})
this.envs.value = envsObj
}

getEnv(key: string) {
return this.envs.value?.[key] || null
}

getEnvByPath(path: string) {
// replace `.` to `_` and uppercase
// replace `ATK_TRUSTED_DOMAINS_0` to `ATK_TRUSTED_DOMAINS`
// replace `ATK_ADMIN_USERS_0_NAME` to `ATK_ADMIN_USERS`
return this.getEnv(
'ATK_' +
path
.replace(/\./g, '_')
.toUpperCase()
.replace(/(_\d+?_\w+|_\d+)$/, ''),
)
}

getCustom(path: string) {
const env = this.getEnvByPath(path)
if (env) return env
return this.customs.value?.getIn(path.split('.')) as any
}

Expand Down
1 change: 1 addition & 0 deletions ui/artalk-sidebar/src/pages/settings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ onMounted(() => {
tree.value = settings.init(yamlObj).getTree()
// console.log(tree.value)
settings.get().setCustoms(custom.data.yaml)
settings.get().setEnvs(custom.data.envs)
})
})
Expand Down
7 changes: 4 additions & 3 deletions ui/artalk/src/api/v2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,7 @@ export interface HandlerResponsePageUpdate {
}

export interface HandlerResponseSettingGet {
envs: string[]
yaml: string
}

Expand Down Expand Up @@ -697,8 +698,8 @@ export class HttpClient<SecurityDataType = unknown> {
property instanceof Blob
? property
: typeof property === 'object' && property !== null
? JSON.stringify(property)
: `${property}`,
? JSON.stringify(property)
: `${property}`,
)
return formData
}, new FormData()),
Expand Down Expand Up @@ -774,7 +775,7 @@ export class HttpClient<SecurityDataType = unknown> {
body: typeof body === 'undefined' || body === null ? null : payloadFormatter(body),
},
).then(async (response) => {
const r = response as HttpResponse<T, E>
const r = response.clone() as HttpResponse<T, E>

Check failure on line 778 in ui/artalk/src/api/v2.ts

View workflow job for this annotation

GitHub Actions / test_ui (18, ubuntu-latest)

Unhandled error

TypeError: response.clone is not a function ❯ src/api/v2.ts:778:26 ❯ processTicksAndRejections node:internal/process/task_queues:95:5 ❯ Module.load src/load.ts:31:20 This error originated in "tests/ui-api.test.ts" test file. It doesn't mean the error was thrown inside the file itself, but while it was running. The latest test that might've caused the error is "should can listen to events and the conf-remoter works (artalk.trigger, artalk.on, conf-remoter)". It might mean one of the following: - The error was thrown, while Vitest was running this test. - If the error occurred after the test had been completed, this was the last documented test before it was thrown.

Check failure on line 778 in ui/artalk/src/api/v2.ts

View workflow job for this annotation

GitHub Actions / test_ui (18, ubuntu-latest)

Unhandled error

TypeError: response.clone is not a function ❯ src/api/v2.ts:778:26 This error originated in "tests/ui-api.test.ts" test file. It doesn't mean the error was thrown inside the file itself, but while it was running. The latest test that might've caused the error is "should can reload comments (artalk.reload)". It might mean one of the following: - The error was thrown, while Vitest was running this test. - If the error occurred after the test had been completed, this was the last documented test before it was thrown.

Check failure on line 778 in ui/artalk/src/api/v2.ts

View workflow job for this annotation

GitHub Actions / test_ui (20, ubuntu-latest)

Unhandled error

TypeError: response.clone is not a function ❯ src/api/v2.ts:778:26 ❯ processTicksAndRejections node:internal/process/task_queues:95:5 ❯ Module.load src/load.ts:31:20 This error originated in "tests/ui-api.test.ts" test file. It doesn't mean the error was thrown inside the file itself, but while it was running. The latest test that might've caused the error is "should can listen to events and the conf-remoter works (artalk.trigger, artalk.on, conf-remoter)". It might mean one of the following: - The error was thrown, while Vitest was running this test. - If the error occurred after the test had been completed, this was the last documented test before it was thrown.

Check failure on line 778 in ui/artalk/src/api/v2.ts

View workflow job for this annotation

GitHub Actions / test_ui (20, ubuntu-latest)

Unhandled error

TypeError: response.clone is not a function ❯ src/api/v2.ts:778:26 This error originated in "tests/ui-api.test.ts" test file. It doesn't mean the error was thrown inside the file itself, but while it was running. The latest test that might've caused the error is "should can reload comments (artalk.reload)". It might mean one of the following: - The error was thrown, while Vitest was running this test. - If the error occurred after the test had been completed, this was the last documented test before it was thrown.
r.data = null as unknown as T
r.error = null as unknown as E

Expand Down

0 comments on commit 006db5b

Please sign in to comment.