mirror of
https://github.com/0xJacky/nginx-ui.git
synced 2025-05-11 02:15:48 +02:00
313 lines
7 KiB
Vue
313 lines
7 KiB
Vue
<script setup lang="ts">
|
|
import { message } from 'ant-design-vue'
|
|
import type { Ref } from 'vue'
|
|
import FooterToolBar from '@/components/FooterToolbar/FooterToolBar.vue'
|
|
import CodeEditor from '@/components/CodeEditor/CodeEditor.vue'
|
|
|
|
import NgxConfigEditor from '@/views/domain/ngx_conf/NgxConfigEditor.vue'
|
|
import type { NgxConfig } from '@/api/ngx'
|
|
import ngx from '@/api/ngx'
|
|
import config from '@/api/config'
|
|
import RightSettings from '@/views/stream/components/RightSettings.vue'
|
|
import type { ChatComplicationMessage } from '@/api/openai'
|
|
import type { Stream } from '@/api/stream'
|
|
import stream from '@/api/stream'
|
|
import type { CheckedType } from '@/types'
|
|
|
|
const route = useRoute()
|
|
const router = useRouter()
|
|
|
|
const name = ref(route.params.name.toString())
|
|
|
|
watch(route, () => {
|
|
name.value = route.params?.name?.toString() ?? ''
|
|
})
|
|
|
|
const ngx_config: NgxConfig = reactive({
|
|
name: '',
|
|
upstreams: [],
|
|
servers: [],
|
|
})
|
|
|
|
const enabled = ref(false)
|
|
const configText = ref('')
|
|
const advance_mode_ref = ref(false)
|
|
const saving = ref(false)
|
|
const filename = ref('')
|
|
const filepath = ref('')
|
|
const parse_error_status = ref(false)
|
|
const parse_error_message = ref('')
|
|
const data = ref({})
|
|
|
|
init()
|
|
|
|
const advance_mode = computed({
|
|
get() {
|
|
return advance_mode_ref.value || parse_error_status.value
|
|
},
|
|
set(v: boolean) {
|
|
advance_mode_ref.value = v
|
|
},
|
|
})
|
|
|
|
const history_chatgpt_record = ref([]) as Ref<ChatComplicationMessage[]>
|
|
|
|
function handle_response(r: Stream) {
|
|
if (r.advanced)
|
|
advance_mode.value = true
|
|
|
|
if (r.advanced)
|
|
advance_mode.value = true
|
|
|
|
parse_error_status.value = false
|
|
parse_error_message.value = ''
|
|
filename.value = r.name
|
|
filepath.value = r.filepath
|
|
configText.value = r.config
|
|
enabled.value = r.enabled
|
|
history_chatgpt_record.value = r.chatgpt_messages
|
|
data.value = r
|
|
Object.assign(ngx_config, r.tokenized)
|
|
}
|
|
|
|
function init() {
|
|
if (name.value) {
|
|
stream.get(name.value).then(r => {
|
|
handle_response(r)
|
|
}).catch(handle_parse_error)
|
|
}
|
|
else {
|
|
history_chatgpt_record.value = []
|
|
}
|
|
}
|
|
|
|
function handle_parse_error(e: { error?: string; message: string }) {
|
|
console.error(e)
|
|
parse_error_status.value = true
|
|
parse_error_message.value = e.message
|
|
config.get(`streams-available/${name.value}`).then(r => {
|
|
configText.value = r.content
|
|
})
|
|
}
|
|
|
|
function on_mode_change(advanced: CheckedType) {
|
|
stream.advance_mode(name.value, { advanced: advanced as boolean }).then(() => {
|
|
advance_mode.value = advanced as boolean
|
|
if (advanced) {
|
|
build_config()
|
|
}
|
|
else {
|
|
return ngx.tokenize_config(configText.value).then(r => {
|
|
Object.assign(ngx_config, r)
|
|
}).catch(handle_parse_error)
|
|
}
|
|
})
|
|
}
|
|
|
|
async function build_config() {
|
|
return ngx.build_config(ngx_config).then(r => {
|
|
configText.value = r.content
|
|
})
|
|
}
|
|
|
|
const save = async () => {
|
|
saving.value = true
|
|
|
|
if (!advance_mode.value) {
|
|
try {
|
|
await build_config()
|
|
}
|
|
catch (e) {
|
|
saving.value = false
|
|
message.error($gettext('Failed to save, syntax error(s) was detected in the configuration.'))
|
|
|
|
return
|
|
}
|
|
}
|
|
|
|
return stream.save(name.value, {
|
|
name: filename.value || name.value,
|
|
content: configText.value,
|
|
overwrite: true,
|
|
}).then(r => {
|
|
handle_response(r)
|
|
router.push({
|
|
path: `/stream/${filename.value}`,
|
|
query: route.query,
|
|
})
|
|
message.success($gettext('Saved successfully'))
|
|
}).catch(handle_parse_error).finally(() => {
|
|
saving.value = false
|
|
})
|
|
}
|
|
|
|
provide('save_config', save)
|
|
provide('configText', configText)
|
|
provide('ngx_config', ngx_config)
|
|
provide('history_chatgpt_record', history_chatgpt_record)
|
|
provide('enabled', enabled)
|
|
provide('name', name)
|
|
provide('filename', filename)
|
|
provide('filepath', filepath)
|
|
provide('data', data)
|
|
</script>
|
|
|
|
<template>
|
|
<ARow :gutter="16">
|
|
<ACol
|
|
:xs="24"
|
|
:sm="24"
|
|
:md="18"
|
|
>
|
|
<ACard :bordered="false">
|
|
<template #title>
|
|
<span style="margin-right: 10px">{{ $gettext('Edit %{n}', { n: name }) }}</span>
|
|
<ATag
|
|
v-if="enabled"
|
|
color="blue"
|
|
>
|
|
{{ $gettext('Enabled') }}
|
|
</ATag>
|
|
<ATag
|
|
v-else
|
|
color="orange"
|
|
>
|
|
{{ $gettext('Disabled') }}
|
|
</ATag>
|
|
</template>
|
|
<template #extra>
|
|
<div class="mode-switch">
|
|
<div class="switch">
|
|
<ASwitch
|
|
size="small"
|
|
:disabled="parse_error_status"
|
|
:checked="advance_mode"
|
|
@change="on_mode_change"
|
|
/>
|
|
</div>
|
|
<template v-if="advance_mode">
|
|
<div>{{ $gettext('Advance Mode') }}</div>
|
|
</template>
|
|
<template v-else>
|
|
<div>{{ $gettext('Basic Mode') }}</div>
|
|
</template>
|
|
</div>
|
|
</template>
|
|
|
|
<Transition name="slide-fade">
|
|
<div
|
|
v-if="advance_mode"
|
|
key="advance"
|
|
>
|
|
<div
|
|
v-if="parse_error_status"
|
|
class="parse-error-alert-wrapper"
|
|
>
|
|
<AAlert
|
|
:message="$gettext('Nginx Configuration Parse Error')"
|
|
:description="parse_error_message"
|
|
type="error"
|
|
show-icon
|
|
/>
|
|
</div>
|
|
<div>
|
|
<CodeEditor v-model:content="configText" />
|
|
</div>
|
|
</div>
|
|
|
|
<div
|
|
v-else
|
|
key="basic"
|
|
class="domain-edit-container"
|
|
>
|
|
<NgxConfigEditor
|
|
:enabled="enabled"
|
|
context="stream"
|
|
@callback="save"
|
|
/>
|
|
</div>
|
|
</Transition>
|
|
</ACard>
|
|
</ACol>
|
|
|
|
<ACol
|
|
class="col-right"
|
|
:xs="24"
|
|
:sm="24"
|
|
:md="6"
|
|
>
|
|
<RightSettings />
|
|
</ACol>
|
|
|
|
<FooterToolBar>
|
|
<ASpace>
|
|
<AButton @click="$router.push('/streams')">
|
|
{{ $gettext('Back') }}
|
|
</AButton>
|
|
<AButton
|
|
type="primary"
|
|
:loading="saving"
|
|
@click="save"
|
|
>
|
|
{{ $gettext('Save') }}
|
|
</AButton>
|
|
</ASpace>
|
|
</FooterToolBar>
|
|
</ARow>
|
|
</template>
|
|
|
|
<style lang="less">
|
|
|
|
</style>
|
|
|
|
<style lang="less" scoped>
|
|
.col-right {
|
|
position: relative;
|
|
}
|
|
|
|
.ant-card {
|
|
margin: 10px 0;
|
|
box-shadow: unset;
|
|
}
|
|
|
|
.mode-switch {
|
|
display: flex;
|
|
|
|
.switch {
|
|
display: flex;
|
|
align-items: center;
|
|
margin-right: 5px;
|
|
}
|
|
}
|
|
|
|
.parse-error-alert-wrapper {
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.domain-edit-container {
|
|
max-width: 800px;
|
|
margin: 0 auto;
|
|
}
|
|
|
|
.slide-fade-enter-active {
|
|
transition: all .3s ease-in-out;
|
|
}
|
|
|
|
.slide-fade-leave-active {
|
|
transition: all .3s cubic-bezier(1.0, 0.5, 0.8, 1.0);
|
|
}
|
|
|
|
.slide-fade-enter-from, .slide-fade-enter-to, .slide-fade-leave-to
|
|
/* .slide-fade-leave-active for below version 2.1.8 */ {
|
|
transform: translateX(10px);
|
|
opacity: 0;
|
|
}
|
|
|
|
.directive-params-wrapper {
|
|
margin: 10px 0;
|
|
}
|
|
|
|
.tab-content {
|
|
padding: 10px;
|
|
}
|
|
</style>
|