chore: migrate to ESlint v9

This commit is contained in:
Hintay 2024-10-24 01:30:13 +09:00
parent 8c00292fa1
commit 4f25a0c670
No known key found for this signature in database
GPG key ID: 120FC7FF121F2F2D
142 changed files with 4387 additions and 2052 deletions

0
.editorconfig Executable file → Normal file
View file

View file

@ -2,5 +2,15 @@
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="HtmlUnknownAttribute" enabled="true" level="WARNING" enabled_by_default="true">
<option name="myValues">
<value>
<list size="1">
<item index="0" class="java.lang.String" itemvalue="vue-dompurify-html" />
</list>
</value>
</option>
<option name="myCustomValuesEnabled" value="true" />
</inspection_tool>
</profile>
</component>

View file

@ -1,257 +0,0 @@
module.exports = {
env: {
browser: true,
es2021: true,
},
extends: [
'@antfu/eslint-config-vue',
'plugin:vue/vue3-recommended',
'plugin:import/recommended',
'plugin:import/typescript',
'plugin:sonarjs/recommended',
'plugin:@typescript-eslint/recommended',
// 'plugin:unicorn/recommended',
],
parser: 'vue-eslint-parser',
parserOptions: {
ecmaVersion: 13,
parser: '@typescript-eslint/parser',
sourceType: 'module',
},
plugins: [
'vue',
'@typescript-eslint',
'regex',
],
ignorePatterns: ['src/@iconify/*.js', 'node_modules', 'dist', '*.d.ts'],
rules: {
'vue/no-v-html': 'off',
'vue/block-tag-newline': 'off',
// eslint-disable-next-line n/prefer-global/process
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
// eslint-disable-next-line n/prefer-global/process
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
// indentation (Already present in TypeScript)
'comma-spacing': ['error', {
before: false,
after: true,
}],
'key-spacing': ['error', {afterColon: true}],
'vue/first-attribute-linebreak': ['error', {
singleline: 'beside',
multiline: 'below',
}],
'antfu/top-level-function': 'off',
// Enforce trailing comma (Already present in TypeScript)
'comma-dangle': ['error', 'always-multiline'],
// Disable max-len
'max-len': 'off',
// we don't want it
'semi': ['error', 'never'],
// add parens ony when required in arrow function
'arrow-parens': ['error', 'as-needed'],
// add new line above comment
'newline-before-return': 'error',
// add new line above comment
'lines-around-comment': [
'error',
{
beforeBlockComment: true,
beforeLineComment: true,
allowBlockStart: true,
allowClassStart: true,
allowObjectStart: true,
allowArrayStart: true,
},
],
// Ignore _ as unused variable
'@typescript-eslint/no-unused-vars': ['error', {argsIgnorePattern: '^_+$'}],
'array-element-newline': ['error', 'consistent'],
'array-bracket-newline': ['error', 'consistent'],
'vue/multi-word-component-names': 'off',
'padding-line-between-statements': [
'error',
{
blankLine: 'always',
prev: 'expression',
next: 'const',
},
{
blankLine: 'always',
prev: 'const',
next: 'expression',
},
{
blankLine: 'always',
prev: 'multiline-const',
next: '*',
},
{
blankLine: 'always',
prev: '*',
next: 'multiline-const',
},
],
// Plugin: eslint-plugin-import
'import/prefer-default-export': 'off',
'import/newline-after-import': ['error', {count: 1}],
'no-restricted-imports': ['error', 'vuetify/components'],
// For omitting extension for ts files
'import/extensions': [
'error',
'ignorePackages',
{
mjs: 'never',
js: 'never',
jsx: 'never',
ts: 'never',
tsx: 'never',
},
],
// ignore virtual files
'import/no-unresolved': [2, {
ignore: [
'~pages$',
'virtual:generated-layouts',
// Ignore vite's ?raw imports
'.*\?raw',
],
}],
// Thanks: https://stackoverflow.com/a/63961972/10796681
'no-shadow': 'off',
'@typescript-eslint/no-shadow': ['error'],
'@typescript-eslint/consistent-type-imports': 'error',
// Plugin: eslint-plugin-promise
'promise/always-return': 'off',
'promise/catch-or-return': 'off',
// ESLint plugin vue
'vue/component-api-style': 'error',
'vue/component-name-in-template-casing': ['error', 'PascalCase', {registeredComponentsOnly: false}],
'vue/custom-event-name-casing': ['error', 'camelCase', {
ignores: [
'/^(click):[a-z]+((\d)|([A-Z0-9][a-z0-9]+))*([A-Z])?/',
],
}],
'vue/define-macros-order': 'error',
'vue/html-comment-content-newline': 'error',
'vue/html-comment-content-spacing': 'error',
'vue/html-comment-indent': 'error',
'vue/match-component-file-name': 'error',
'vue/no-child-content': 'error',
'vue/require-default-prop': 'off',
// NOTE this rule only supported in SFC, Users of the unplugin-vue-define-options should disable that rule: https://github.com/vuejs/eslint-plugin-vue/issues/1886
// 'vue/no-duplicate-attr-inheritance': 'error',
'vue/no-multiple-objects-in-class': 'error',
'vue/no-reserved-component-names': 'error',
'vue/no-template-target-blank': 'error',
'vue/no-useless-mustaches': 'error',
'vue/no-useless-v-bind': 'error',
'vue/padding-line-between-blocks': 'error',
'vue/prefer-separate-static-class': 'error',
'vue/prefer-true-attribute-shorthand': 'error',
'vue/v-on-function-call': 'error',
'vue/valid-v-slot': ['error', {
allowModifiers: true,
}],
// -- Extension Rules
'vue/no-irregular-whitespace': 'error',
// -- Sonarlint
'sonarjs/no-duplicate-string': 'off',
'sonarjs/no-nested-template-literals': 'off',
// -- Unicorn
// 'unicorn/filename-case': 'off',
// 'unicorn/prevent-abbreviations': ['error', {
// replacements: {
// props: false,
// },
// }],
// https://github.com/gmullerb/eslint-plugin-regex
'regex/invalid': [
'error',
[
{
regex: '@/assets/images',
replacement: '@images',
message: 'Use \'@images\' path alias for image imports',
},
{
regex: '@/styles',
replacement: '@styles',
message: 'Use \'@styles\' path alias for importing styles from \'src/styles\'',
},
// {
// id: 'Disallow icon of icon library',
// regex: 'tabler-\\w',
// message: 'Only \'mdi\' icons are allowed',
// },
{
regex: '@core/\\w',
message: 'You can\'t use @core when you are in @layouts module',
files: {
inspect: '@layouts/.*',
},
},
{
regex: 'useLayouts\\(',
message: '`useLayouts` composable is only allowed in @layouts & @core directory. Please use `useThemeConfig` composable instead.',
files: {
inspect: '^(?!.*(@core|@layouts)).*',
},
},
],
// Ignore files
'\.eslintrc\.js',
],
},
settings: {
'import/resolver': {
node: {
extensions: ['.ts', '.js', '.tsx', '.jsx', '.mjs', '.png', '.jpg'],
},
typescript: {},
alias: {
map: [
['@', './src'],
],
},
},
},
overrides: [
{
files: ['*.json'],
rules: {
'no-invalid-meta': 'off',
},
},
],
}

3
app/env.d.ts vendored
View file

@ -1,5 +1,6 @@
declare module '*.svg' {
import React from 'react'
import type React from 'react'
const content: React.FC<React.SVGProps<SVGElement>>
export default content
}

52
app/eslint.config.mjs Normal file
View file

@ -0,0 +1,52 @@
import createConfig from '@antfu/eslint-config'
import sonarjs from 'eslint-plugin-sonarjs'
export default createConfig(
{
stylistic: true,
ignores: ['**/version.json', 'tsconfig.json', 'tsconfig.node.json'],
},
sonarjs.configs.recommended,
{
name: '@nginx-ui/eslint-config',
rules: {
'no-console': 'warn',
'no-alert': 'warn',
'ts/no-explicit-any': 'warn',
'vue/no-unused-refs': 'warn',
'vue/prop-name-casing': 'warn',
'node/prefer-global/process': 'off',
'unused-imports/no-unused-vars': 'warn',
// https://eslint.org/docs/latest/rules/dot-notation
'style/dot-notation': 'off',
// https://eslint.org/docs/latest/rules/arrow-parens
'style/arrow-parens': ['error', 'as-needed'],
// https://eslint.org/docs/latest/rules/prefer-template
'prefer-template': 'error',
// https://eslint.style/rules/js/arrow-spacing
'style/arrow-spacing': ['error', { before: true, after: true }],
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/prefer-default-export.md
'import/prefer-default-export': 'off',
// https://eslint.vuejs.org/rules/require-typed-ref
'vue/require-typed-ref': 'warn',
// https://eslint.vuejs.org/rules/require-prop-types
'vue/require-prop-types': 'warn',
// https://eslint.vuejs.org/rules/no-ref-as-operand.html
'vue/no-ref-as-operand': 'error',
// -- Sonarlint
'sonarjs/no-duplicate-string': 'off',
'sonarjs/no-nested-template-literals': 'off',
'sonarjs/pseudo-random': 'warn',
'sonarjs/no-nested-functions': 'off',
},
},
)

View file

@ -1,4 +1,3 @@
// eslint-disable-next-line @typescript-eslint/no-var-requires
const i18n = require('./i18n.json')
module.exports = {

View file

@ -1,11 +1,13 @@
{
"name": "nginx-ui-app-next",
"version": "2.0.0-beta.36",
"type": "module",
"version": "2.0.0-beta.36",
"packageManager": "pnpm@9.10.0",
"scripts": {
"dev": "vite --host",
"typecheck": "vue-tsc --noEmit",
"lint": "eslint . -c .eslintrc.cjs --fix --ext .ts,.vue,.tsx,.d.ts",
"lint": "eslint .",
"lint:fix": "eslint --fix .",
"build": "vite build",
"preview": "vite preview",
"gettext:extract": "vue-gettext-extract"
@ -39,6 +41,7 @@
"universal-cookie": "^7.2.1",
"vite-plugin-build-id": "0.4.2",
"vue": "^3.5.12",
"vue-dompurify-html": "^5.1.0",
"vue-router": "^4.4.5",
"vue3-ace-editor": "2.2.4",
"vue3-apexcharts": "1.5.3",
@ -47,26 +50,19 @@
"vuedraggable": "^4.1.0"
},
"devDependencies": {
"@antfu/eslint-config-vue": "^0.43.1",
"@antfu/eslint-config": "^3.8.0",
"@simplewebauthn/types": "^11.0.0",
"@types/lodash": "^4.17.12",
"@types/nprogress": "^0.2.3",
"@types/sortablejs": "^1.15.8",
"@typescript-eslint/eslint-plugin": "^6.21.0",
"@typescript-eslint/parser": "^6.21.0",
"@vitejs/plugin-vue": "^5.1.4",
"@vitejs/plugin-vue-jsx": "^4.0.1",
"@vue/compiler-sfc": "^3.5.12",
"@vue/tsconfig": "^0.5.1",
"ace-builds": "^1.36.3",
"autoprefixer": "^10.4.20",
"eslint": "^8.57.1",
"eslint-import-resolver-alias": "^1.1.2",
"eslint-import-resolver-typescript": "^3.6.3",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-regex": "^1.10.0",
"eslint-plugin-sonarjs": "^0.23.0",
"eslint-plugin-vue": "^9.29.1",
"eslint": "^9.13.0",
"eslint-plugin-sonarjs": "^2.0.4",
"less": "^4.2.0",
"postcss": "^8.4.47",
"tailwindcss": "^3.4.14",
@ -74,9 +70,8 @@
"unplugin-auto-import": "^0.18.3",
"unplugin-vue-components": "^0.27.4",
"unplugin-vue-define-options": "^1.5.2",
"vite": "^5.4.9",
"vite": "^5.4.10",
"vite-svg-loader": "^5.1.0",
"vue-tsc": "^2.1.6"
},
"packageManager": "pnpm@9.10.0"
}
}

4351
app/pnpm-lock.yaml generated

File diff suppressed because it is too large Load diff

View file

@ -1,22 +1,21 @@
<script setup lang="ts">
import loadTranslations from '@/api/translations'
import gettext from '@/gettext'
import { useSettingsStore } from '@/pinia'
import { theme } from 'ant-design-vue'
import en_US from 'ant-design-vue/es/locale/en_US'
import zh_CN from 'ant-design-vue/es/locale/zh_CN'
import zh_TW from 'ant-design-vue/es/locale/zh_TW'
// This starter template is using Vue 3 <script setup> SFCs
// Check out https://vuejs.org/api/sfc-script-setup.html#script-setup
import { computed, provide } from 'vue'
import { theme } from 'ant-design-vue'
import zh_CN from 'ant-design-vue/es/locale/zh_CN'
import zh_TW from 'ant-design-vue/es/locale/zh_TW'
import en_US from 'ant-design-vue/es/locale/en_US'
import { useSettingsStore } from '@/pinia'
import gettext from '@/gettext'
import loadTranslations from '@/api/translations'
const route = useRoute()
const media = window.matchMedia('(prefers-color-scheme: dark)')
const callback = () => {
function callback() {
const settings = useSettingsStore()
if (settings.preference_theme === 'auto') {
if (media.matches)

View file

@ -23,7 +23,7 @@ const twoFA = {
begin_start_secure_session_by_passkey() {
return http.get('/2fa_secure_session/passkey')
},
finish_start_secure_session_by_passkey(data: { session_id: string; options: AuthenticationResponseJSON }): Promise<{
finish_start_secure_session_by_passkey(data: { session_id: string, options: AuthenticationResponseJSON }): Promise<{
session_id: string
}> {
return http.post('/2fa_secure_session/passkey', data.options, {

View file

@ -41,7 +41,7 @@ const auth = {
begin_passkey_login() {
return http.get('/begin_passkey_login')
},
finish_passkey_login(data: { session_id: string; options: AuthenticationResponseJSON }) {
finish_passkey_login(data: { session_id: string, options: AuthenticationResponseJSON }) {
return http.post('/finish_passkey_login', data.options, {
headers: {
'X-Passkey-Session-Id': data.session_id,

View file

@ -1,8 +1,8 @@
import type { ModelBase } from '@/api/curd'
import Curd from '@/api/curd'
import type { DnsCredential } from '@/api/dns_credential'
import type { AcmeUser } from '@/api/acme_user'
import type { ModelBase } from '@/api/curd'
import type { DnsCredential } from '@/api/dns_credential'
import type { PrivateKeyType } from '@/constants'
import Curd from '@/api/curd'
export interface Cert extends ModelBase {
name: string

View file

@ -1,5 +1,5 @@
import Curd from '@/api/curd'
import type { ChatComplicationMessage } from '@/api/openai'
import Curd from '@/api/curd'
import http from '@/lib/http'
export interface Config {

View file

@ -34,27 +34,27 @@ class Curd<T> {
this.plural = plural ?? `${this.baseUrl}s`
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
_get_list(params: any = null): Promise<GetListResponse<T>> {
return http.get(this.plural, { params })
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
_get(id: any = null, params: any = {}): Promise<T> {
return http.get(this.baseUrl + (id ? `/${id}` : ''), { params })
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
_save(id: any = null, data: any, config: any = undefined): Promise<T> {
// eslint-disable-next-line ts/no-explicit-any
_save(id: any = null, data: any = undefined, config: any = undefined): Promise<T> {
return http.post(this.baseUrl + (id ? `/${id}` : ''), data, config)
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
_destroy(id: any = null, params: any = {}) {
return http.delete(`${this.baseUrl}/${id}`, { params })
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
_recover(id: any = null) {
return http.patch(`${this.baseUrl}/${id}`)
}

View file

@ -1,6 +1,6 @@
import type { DNSProvider } from '@/api/auto_cert'
import type { ModelBase } from '@/api/curd'
import Curd from '@/api/curd'
import type { DNSProvider } from '@/api/auto_cert'
export interface DnsCredential extends ModelBase {
name: string

View file

@ -1,9 +1,9 @@
import Curd from '@/api/curd'
import http from '@/lib/http'
import type { ChatComplicationMessage } from '@/api/openai'
import type { CertificateInfo } from '@/api/cert'
import type { NgxConfig } from '@/api/ngx'
import type { ChatComplicationMessage } from '@/api/openai'
import type { PrivateKeyType } from '@/constants'
import Curd from '@/api/curd'
import http from '@/lib/http'
export interface Site {
modified_at: string
@ -26,7 +26,7 @@ export interface AutoCertRequest {
}
class Domain extends Curd<Site> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
enable(name: string, config?: any) {
return http.post(`${this.baseUrl}/${name}/enable`, undefined, config)
}

View file

@ -1,6 +1,6 @@
import http from '@/lib/http'
import type { ModelBase } from '@/api/curd'
import Curd from '@/api/curd'
import http from '@/lib/http'
export interface Environment extends ModelBase {
name: string

View file

@ -8,7 +8,7 @@ export interface INginxLogData {
}
const nginx_log = {
page(page = 0, data: INginxLogData) {
page(page = 0, data: INginxLogData | undefined = undefined) {
return http.post(`/nginx_log?page=${page}`, data)
},
}

View file

@ -46,7 +46,7 @@ const ngx = {
return http.post('/ngx/format_code', { content })
},
status(): Promise<{ running: boolean; message: string; level: number }> {
status(): Promise<{ running: boolean, message: string, level: number }> {
return http.get('/nginx/status')
},

View file

@ -7,7 +7,7 @@ export interface ChatComplicationMessage {
}
const openai = {
store_record(data: { file_name?: string; messages?: ChatComplicationMessage[] }) {
store_record(data: { file_name?: string, messages?: ChatComplicationMessage[] }) {
return http.post('/chatgpt_record', data)
},
}

View file

@ -1,6 +1,6 @@
import type { ModelBase } from '@/api/curd'
import type { RegistrationResponseJSON } from '@simplewebauthn/types'
import http from '@/lib/http'
import type { ModelBase } from '@/api/curd'
export interface Passkey extends ModelBase {
name: string

View file

@ -1,7 +1,7 @@
import type { NgxConfig } from '@/api/ngx'
import type { ChatComplicationMessage } from '@/api/openai'
import Curd from '@/api/curd'
import http from '@/lib/http'
import type { ChatComplicationMessage } from '@/api/openai'
import type { NgxConfig } from '@/api/ngx'
export interface Stream {
modified_at: string
@ -15,7 +15,7 @@ export interface Stream {
}
class StreamCurd extends Curd<Stream> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
enable(name: string, config?: any) {
return http.post(`${this.baseUrl}/${name}/enable`, undefined, config)
}

View file

@ -1,11 +1,11 @@
import type { NgxDirective, NgxLocation, NgxServer } from '@/api/ngx'
import Curd from '@/api/curd'
import http from '@/lib/http'
import type { NgxDirective, NgxLocation, NgxServer } from '@/api/ngx'
export interface Variable {
type?: string
name?: Record<string, string>
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
value?: any
mask?: Record<string, Record<string, string>>
}

View file

@ -1,4 +1,4 @@
import {LocationQueryRaw} from "vue-router";
import type { LocationQueryRaw } from 'vue-router'
export interface Bread {
name: string

View file

@ -1,9 +1,9 @@
<script setup lang="ts">
import VueApexCharts from 'vue3-apexcharts'
import { storeToRefs } from 'pinia'
import type { Series } from '@/components/Chart/types'
import type { Ref } from 'vue'
import { useSettingsStore } from '@/pinia'
import type { Series } from '@/components/Chart/types'
import { storeToRefs } from 'pinia'
import VueApexCharts from 'vue3-apexcharts'
const { series, max, yFormatter } = defineProps<{
series: Series[]
@ -14,7 +14,7 @@ const { series, max, yFormatter } = defineProps<{
const settings = useSettingsStore()
const { theme } = storeToRefs(settings)
const fontColor = () => {
function fontColor() {
return theme.value === 'dark' ? '#b4b4b4' : undefined
}
@ -85,7 +85,7 @@ let chartOptions = {
},
}
const callback = () => {
function callback() {
chartOptions = {
...chartOptions,
...{

View file

@ -1,10 +1,10 @@
<script setup lang="ts">
import VueApexCharts from 'vue3-apexcharts'
import { storeToRefs } from 'pinia'
import { useSettingsStore } from '@/pinia'
import type { Series } from '@/components/Chart/types'
import { useSettingsStore } from '@/pinia'
import { storeToRefs } from 'pinia'
import VueApexCharts from 'vue3-apexcharts'
const props = defineProps<{
series: Series[] | number[]
centerText?: string
@ -17,7 +17,7 @@ const settings = useSettingsStore()
const { theme } = storeToRefs(settings)
const fontColor = () => {
function fontColor() {
return theme.value === 'dark' ? '#fcfcfc' : undefined
}

View file

@ -1,4 +1,4 @@
import type {Usage} from '@/api/analytic'
import type { Usage } from '@/api/analytic'
export interface Series {
name: string

View file

@ -1,18 +1,18 @@
<script setup lang="ts">
import nginx from 'highlight.js/lib/languages/nginx'
import Icon, { SendOutlined } from '@ant-design/icons-vue'
import { storeToRefs } from 'pinia'
import { Marked } from 'marked'
import hljs from 'highlight.js'
import { markedHighlight } from 'marked-highlight'
import type { Ref } from 'vue'
import { urlJoin } from '@/lib/helper'
import { useSettingsStore, useUserStore } from '@/pinia'
import 'highlight.js/styles/vs2015.css'
import type { ChatComplicationMessage } from '@/api/openai'
import type { Ref } from 'vue'
import openai from '@/api/openai'
import ChatGPT_logo from '@/assets/svg/ChatGPT_logo.svg?component'
import { urlJoin } from '@/lib/helper'
import { useSettingsStore, useUserStore } from '@/pinia'
import Icon, { SendOutlined } from '@ant-design/icons-vue'
import hljs from 'highlight.js'
import nginx from 'highlight.js/lib/languages/nginx'
import { Marked } from 'marked'
import { markedHighlight } from 'marked-highlight'
import { storeToRefs } from 'pinia'
import 'highlight.js/styles/vs2015.css'
const props = defineProps<{
content: string
@ -40,7 +40,6 @@ watch(history_messages, () => {
const loading = ref(false)
const ask_buffer = ref('')
// eslint-disable-next-line sonarjs/cognitive-complexity
async function request() {
loading.value = true
@ -82,7 +81,7 @@ async function request() {
}
apply(value!)
}
catch (e) {
catch {
break
}
}
@ -172,7 +171,8 @@ const marked = new Marked(
return `<pre><code class="hljs ${language}">${highlightedCode}</code></pre>`
},
}))
}),
)
marked.setOptions({
pedantic: false,
@ -238,8 +238,8 @@ const show = computed(() => !messages.value || messages.value?.length === 0)
<template #content>
<div
v-if="item.role === 'assistant' || editing_idx !== index"
v-dompurify-html="marked.parse(item.content)"
class="content"
v-html="marked.parse(item.content)"
/>
<AInput
v-else

View file

@ -1,9 +1,9 @@
<script setup lang="ts">
import ace from 'ace-builds'
import extSearchboxUrl from 'ace-builds/src-noconflict/ext-searchbox?url'
import { VAceEditor } from 'vue3-ace-editor'
import 'ace-builds/src-noconflict/mode-nginx'
import ace from 'ace-builds'
import 'ace-builds/src-noconflict/theme-monokai'
import extSearchboxUrl from 'ace-builds/src-noconflict/ext-searchbox?url'
const props = defineProps<{
content?: string

View file

@ -1,8 +1,8 @@
<script setup lang="ts">
import { useSettingsStore } from '@/pinia'
import { CloseOutlined, DashboardOutlined, DatabaseOutlined } from '@ant-design/icons-vue'
import { storeToRefs } from 'pinia'
import { useRouter } from 'vue-router'
import { useSettingsStore } from '@/pinia'
const settingsStore = useSettingsStore()

View file

@ -1,5 +1,6 @@
<script setup lang="ts">
import logo from '@/assets/img/logo.png'</script>
import logo from '@/assets/img/logo.png'
</script>
<template>
<div class="logo">

View file

@ -1,10 +1,10 @@
<script setup lang="ts">
import { message } from 'ant-design-vue'
import { ReloadOutlined } from '@ant-design/icons-vue'
import ngx from '@/api/ngx'
import { logLevel } from '@/views/config/constants'
import { NginxStatus } from '@/constants'
import { useGlobalStore } from '@/pinia/moudule/global'
import { logLevel } from '@/views/config/constants'
import { ReloadOutlined } from '@ant-design/icons-vue'
import { message } from 'ant-design-vue'
const global = useGlobalStore()
const { nginxStatus: status } = storeToRefs(global)

View file

@ -1,6 +1,6 @@
<script setup lang="ts">
import type { Ref } from 'vue'
import type { Environment } from '@/api/environment'
import type { Ref } from 'vue'
import environment from '@/api/environment'
const props = defineProps<{

View file

@ -1,13 +1,13 @@
<script setup lang="ts">
import { BellOutlined, CheckCircleOutlined, CloseCircleOutlined, DeleteOutlined, InfoCircleOutlined, WarningOutlined } from '@ant-design/icons-vue'
import type { Ref } from 'vue'
import { message } from 'ant-design-vue'
import notification from '@/api/notification'
import type { Notification } from '@/api/notification'
import type { CustomRenderProps } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
import type { Ref } from 'vue'
import notification from '@/api/notification'
import { detailRender } from '@/components/Notification/detailRender'
import { NotificationTypeT } from '@/constants'
import { useUserStore } from '@/pinia'
import { detailRender } from '@/components/Notification/detailRender'
import type { customRender } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
import { BellOutlined, CheckCircleOutlined, CloseCircleOutlined, DeleteOutlined, InfoCircleOutlined, WarningOutlined } from '@ant-design/icons-vue'
import { message } from 'ant-design-vue'
const loading = ref(false)
@ -112,7 +112,7 @@ function viewAll() {
</template>
<AListItemMeta
:title="$gettext(item.title)"
:description="detailRender({ text: item.details, record: item } as customRender)"
:description="detailRender({ text: item.details, record: item } as CustomRenderProps)"
>
<template #avatar>
<div>

View file

@ -1,18 +1,15 @@
export function syncCertificateSuccess(text: string) {
const data = JSON.parse(text)
return $gettext('Sync Certificate %{cert_name} to %{env_name} successfully',
{ cert_name: data.cert_name, env_name: data.env_name })
return $gettext('Sync Certificate %{cert_name} to %{env_name} successfully', { cert_name: data.cert_name, env_name: data.env_name })
}
export function syncCertificateError(text: string) {
const data = JSON.parse(text)
if (data.status_code === 404) {
return $gettext('Sync Certificate %{cert_name} to %{env_name} failed, please upgrade the remote Nginx UI to the latest version',
{ cert_name: data.cert_name, env_name: data.env_name }, true)
return $gettext('Sync Certificate %{cert_name} to %{env_name} failed, please upgrade the remote Nginx UI to the latest version', { cert_name: data.cert_name, env_name: data.env_name }, true)
}
return $gettext('Sync Certificate %{cert_name} to %{env_name} failed, response: %{resp}',
{ cert_name: data.cert_name, env_name: data.env_name, resp: data.resp_body }, true)
return $gettext('Sync Certificate %{cert_name} to %{env_name} failed, response: %{resp}', { cert_name: data.cert_name, env_name: data.env_name, resp: data.resp_body }, true)
}

View file

@ -1,37 +1,31 @@
export function syncConfigSuccess(text: string) {
const data = JSON.parse(text)
return $gettext('Sync Config %{config_name} to %{env_name} successfully',
{ config_name: data.config_name, env_name: data.env_name })
return $gettext('Sync Config %{config_name} to %{env_name} successfully', { config_name: data.config_name, env_name: data.env_name })
}
export function syncConfigError(text: string) {
const data = JSON.parse(text)
if (data.status_code === 404) {
return $gettext('Sync config %{config_name} to %{env_name} failed, please upgrade the remote Nginx UI to the latest version',
{ config_name: data.config_name, env_name: data.env_name }, true)
return $gettext('Sync config %{config_name} to %{env_name} failed, please upgrade the remote Nginx UI to the latest version', { config_name: data.config_name, env_name: data.env_name }, true)
}
return $gettext('Sync config %{config_name} to %{env_name} failed, response: %{resp}',
{ config_name: data.cert_name, env_name: data.env_name, resp: data.resp_body }, true)
return $gettext('Sync config %{config_name} to %{env_name} failed, response: %{resp}', { config_name: data.cert_name, env_name: data.env_name, resp: data.resp_body }, true)
}
export function syncRenameConfigSuccess(text: string) {
const data = JSON.parse(text)
return $gettext('Rename %{orig_path} to %{new_path} on %{env_name} successfully',
{ orig_path: data.orig_path, new_path: data.orig_path, env_name: data.env_name })
return $gettext('Rename %{orig_path} to %{new_path} on %{env_name} successfully', { orig_path: data.orig_path, new_path: data.orig_path, env_name: data.env_name })
}
export function syncRenameConfigError(text: string) {
const data = JSON.parse(text)
if (data.status_code === 404) {
return $gettext('Rename %{orig_path} to %{new_path} on %{env_name} failed, please upgrade the remote Nginx UI to the latest version',
{ orig_path: data.orig_path, new_path: data.orig_path, env_name: data.env_name }, true)
return $gettext('Rename %{orig_path} to %{new_path} on %{env_name} failed, please upgrade the remote Nginx UI to the latest version', { orig_path: data.orig_path, new_path: data.orig_path, env_name: data.env_name }, true)
}
return $gettext('Rename %{orig_path} to %{new_path} on %{env_name} failed, response: %{resp}',
{ orig_path: data.orig_path, new_path: data.orig_path, resp: data.resp_body, env_name: data.env_name }, true)
return $gettext('Rename %{orig_path} to %{new_path} on %{env_name} failed, response: %{resp}', { orig_path: data.orig_path, new_path: data.orig_path, resp: data.resp_body, env_name: data.env_name }, true)
}

View file

@ -1,4 +1,4 @@
import type { customRender } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
import type { CustomRenderProps } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
import { syncCertificateError, syncCertificateSuccess } from '@/components/Notification/cert'
import {
syncConfigError,
@ -7,7 +7,7 @@ import {
syncRenameConfigSuccess,
} from '@/components/Notification/config'
export const detailRender = (args: customRender) => {
export function detailRender(args: CustomRenderProps) {
switch (args.record.title) {
case 'Sync Certificate Success':
return syncCertificateSuccess(args.text)

View file

@ -1,8 +1,8 @@
<script setup lang="ts">
import dayjs from 'dayjs'
import { useSettingsStore } from '@/pinia'
import gettext from '@/gettext'
import loadTranslations from '@/api/translations'
import gettext from '@/gettext'
import { useSettingsStore } from '@/pinia'
import dayjs from 'dayjs'
import 'dayjs/locale/fr'
import 'dayjs/locale/ja'
@ -29,7 +29,7 @@ const current = computed({
const languageAvailable = gettext.available
const updateTitle = () => {
function updateTitle() {
const name = route.meta.name as never as () => string
document.title = `${name()} | Nginx UI`

View file

@ -1,9 +1,9 @@
<script setup lang="ts">
import { message } from 'ant-design-vue'
import StdDataEntry from '@/components/StdDesign/StdDataEntry'
import { message } from 'ant-design-vue'
const props = defineProps<{
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
api: (ids: number[], data: any) => Promise<void>
beforeSave?: () => Promise<void>
}>()
@ -15,7 +15,7 @@ const batchColumns = ref([])
const visible = ref(false)
const selectedRowKeys = ref([])
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
function showModal(c: any, rowKeys: any) {
visible.value = true
selectedRowKeys.value = rowKeys

View file

@ -1,12 +1,12 @@
<script setup lang="ts" generic="T=any">
import { message } from 'ant-design-vue'
import type { StdTableSlots } from '@/components/StdDesign/StdDataDisplay/types'
import type { Column } from '@/components/StdDesign/types'
import type { ComputedRef } from 'vue'
import type { StdTableProps } from './StdTable.vue'
import StdTable from './StdTable.vue'
import StdDataEntry from '@/components/StdDesign/StdDataEntry'
import type { Column } from '@/components/StdDesign/types'
import StdCurdDetail from '@/components/StdDesign/StdDataDisplay/StdCurdDetail.vue'
import type { StdTableSlots } from '@/components/StdDesign/StdDataDisplay/types'
import StdDataEntry from '@/components/StdDesign/StdDataEntry'
import { message } from 'ant-design-vue'
import StdTable from './StdTable.vue'
export interface StdCurdProps<T> extends StdTableProps<T> {
cardTitleKey?: string
@ -19,13 +19,13 @@ export interface StdCurdProps<T> extends StdTableProps<T> {
onClickAdd?: () => void
onClickEdit?: (id: number | string, record: T, index: number) => void
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
beforeSave?: (data: any) => Promise<void>
}
const props = defineProps<StdTableProps<T> & StdCurdProps<T>>()
const visible = ref(false)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
const data: any = reactive({ id: null })
const modifyMode = ref(true)
const editMode = ref<string>()
@ -35,11 +35,11 @@ provide('data', data)
provide('editMode', editMode)
provide('shouldRefetchList', shouldRefetchList)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
const error: any = reactive({})
const selected = ref([])
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
function onSelect(keys: any) {
selected.value = keys
}
@ -50,7 +50,7 @@ const editableColumns = computed(() => {
})
}) as ComputedRef<Column[]>
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
function add(preset: any = undefined) {
if (props.onClickAdd)
return
@ -69,12 +69,12 @@ function add(preset: any = undefined) {
const table = ref()
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
const selectedRowKeys = defineModel<any[]>('selectedRowKeys', {
default: () => [],
})
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
const selectedRows = defineModel<any[]>('selectedRows', {
type: Array,
default: () => [],
@ -84,8 +84,8 @@ const getParams = reactive({
trash: false,
})
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const setParams = (k: string, v: any) => {
// eslint-disable-next-line ts/no-explicit-any
function setParams(k: string, v: any) {
getParams[k] = v
}
@ -117,17 +117,15 @@ async function ok() {
await formRef.validateFields()
props?.beforeSave?.(data)
props
.api!.save(data.id, { ...data, ...props.overwriteParams }, { params: { ...props.overwriteParams } })
.then(r => {
message.success($gettext('Save successfully'))
Object.assign(data, r)
get_list()
visible.value = false
})
.catch(e => {
message.error($gettext(e?.message ?? 'Server error'), 5)
Object.assign(error, e.errors)
})
.api!.save(data.id, { ...data, ...props.overwriteParams }, { params: { ...props.overwriteParams } }).then(r => {
message.success($gettext('Save successfully'))
Object.assign(data, r)
get_list()
visible.value = false
}).catch(e => {
message.error($gettext(e?.message ?? 'Server error'), 5)
Object.assign(error, e.errors)
})
}
catch {
message.error($gettext('Please fill in the required fields'))
@ -169,18 +167,19 @@ function view(id: number | string) {
async function get(id: number | string) {
return props
.api!.get(id, { ...props.overwriteParams })
.then(async r => {
Object.keys(data).forEach(k => {
delete data[k]
})
data.id = null
Object.assign(data, r)
.api!.get(id, { ...props.overwriteParams }).then(async r => {
Object.keys(data).forEach(k => {
delete data[k]
})
data.id = null
Object.assign(data, r)
})
}
const modalTitle = computed(() => {
return data.id ? modifyMode.value ? $gettext('Modify') : $gettext('View Details') : $gettext('Add')
if (data.id)
return modifyMode.value ? $gettext('Modify') : $gettext('View Details')
return $gettext('Add')
})
const localOverwriteParams = reactive(props.overwriteParams ?? {})

View file

@ -1,13 +1,13 @@
<script setup lang="ts">
import type { ComputedRef } from 'vue'
import _ from 'lodash'
import type { Column } from '@/components/StdDesign/types'
import { labelRender } from '@/components/StdDesign/StdDataEntry'
import type { ComputedRef } from 'vue'
import { CustomRender } from '@/components/StdDesign/StdDataDisplay/components/CustomRender'
import { labelRender } from '@/components/StdDesign/StdDataEntry'
import _ from 'lodash'
const props = defineProps<{
columns: Column[]
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
data: any
}>()

View file

@ -1,28 +1,28 @@
<script setup lang="ts" generic="T=any">
import type { Pagination } from '@/api/curd'
import type Curd from '@/api/curd'
import type { Column } from '@/components/StdDesign/types'
import type { TableProps } from 'ant-design-vue'
import { message } from 'ant-design-vue'
import { HolderOutlined } from '@ant-design/icons-vue'
import type { ComputedRef, Ref } from 'vue'
import type { SorterResult, TablePaginationConfig } from 'ant-design-vue/lib/table/interface'
import type { FilterValue } from 'ant-design-vue/es/table/interface'
import type { Key } from 'ant-design-vue/es/_util/type'
import type { FilterValue } from 'ant-design-vue/es/table/interface'
import type { SorterResult, TablePaginationConfig } from 'ant-design-vue/lib/table/interface'
import type { ComputedRef, Ref } from 'vue'
import type { RouteParams } from 'vue-router'
import useSortable from '@/components/StdDesign/StdDataDisplay/methods/sortable'
import StdDataEntry from '@/components/StdDesign/StdDataEntry'
import { HolderOutlined } from '@ant-design/icons-vue'
import { message } from 'ant-design-vue'
import _ from 'lodash'
import StdPagination from './StdPagination.vue'
import StdDataEntry from '@/components/StdDesign/StdDataEntry'
import type { Pagination } from '@/api/curd'
import type { Column } from '@/components/StdDesign/types'
import useSortable from '@/components/StdDesign/StdDataDisplay/methods/sortable'
import type Curd from '@/api/curd'
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
export interface StdTableProps<T = any> {
title?: string
mode?: string
rowKey?: string
api: Curd<T>
columns: Column[]
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
getParams?: Record<string, any>
size?: string
disableQueryParams?: boolean
@ -30,7 +30,7 @@ export interface StdTableProps<T = any> {
pithy?: boolean
exportExcel?: boolean
exportMaterial?: boolean
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
overwriteParams?: Record<string, any>
disableView?: boolean
disableModify?: boolean
@ -40,7 +40,7 @@ export interface StdTableProps<T = any> {
disablePagination?: boolean
sortableMoveHook?: (oldRow: number[], newRow: number[]) => boolean
scrollX?: string | number
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
getCheckboxProps?: (record: any) => any
}
@ -71,10 +71,10 @@ watch(dataSource, () => {
expandKeysList.value = res
})
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
const rowsKeyIndexMap: Ref<Record<number, any>> = ref({})
const loading = ref(true)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
const selectedRecords: Ref<Record<any, any>> = ref({})
// This can be useful if there are more than one StdTable in the same page.
@ -93,12 +93,12 @@ const params = reactive({
...props.getParams,
})
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
const selectedRowKeys = defineModel<any[]>('selectedRowKeys', {
default: () => [],
})
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
const selectedRows = defineModel<any[]>('selectedRows', {
type: Array,
default: () => [],
@ -213,10 +213,10 @@ function recover(id: number | string) {
})
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
function buildIndexMap(data: any, level: number = 0, index: number = 0, total: number[] = []) {
if (data && data.length > 0) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
data.forEach((v: any) => {
v.level = level
@ -253,7 +253,7 @@ async function _get_list(page_num = null, page_size = 20) {
})
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
function onTableChange(_pagination: TablePaginationConfig, filters: Record<string, FilterValue>, sorter: SorterResult | SorterResult<any>[]) {
if (sorter) {
sorter = sorter as SorterResult
@ -286,7 +286,7 @@ function expandedTable(keys: Key[]) {
expandKeysList.value = keys
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any,sonarjs/cognitive-complexity
// eslint-disable-next-line ts/no-explicit-any
async function onSelect(record: any, selected: boolean, _selectedRows: any[]) {
if (props.selectionType === 'checkbox' || props.exportExcel) {
if (selected) {
@ -300,13 +300,13 @@ async function onSelect(record: any, selected: boolean, _selectedRows: any[]) {
})
}
else {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
selectedRowKeys.value = selectedRowKeys.value.filter((v: any) => v !== record[props.rowKey])
delete selectedRecords.value[record[props.rowKey]]
}
await nextTick(async () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
const filteredRows: any[] = []
selectedRowKeys.value.forEach(v => {
@ -325,10 +325,10 @@ async function onSelect(record: any, selected: boolean, _selectedRows: any[]) {
}
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
async function onSelectAll(selected: boolean, _selectedRows: any[], changeRows: any[]) {
// console.log(selected, selectedRows, changeRows)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
changeRows.forEach((v: any) => {
if (v) {
if (selected) {
@ -350,7 +350,7 @@ async function onSelectAll(selected: boolean, _selectedRows: any[], changeRows:
// console.log(selectedRowKeysBuffer.value, selectedRecords.value)
await nextTick(async () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
const filteredRows: any[] = []
selectedRowKeys.value.forEach(v => {
@ -362,7 +362,7 @@ async function onSelectAll(selected: boolean, _selectedRows: any[], changeRows:
const router = useRouter()
const resetSearch = async () => {
async function resetSearch() {
Object.keys(params).forEach(v => {
delete params[v]
})
@ -460,7 +460,6 @@ const paginationSize = computed(() => {
else
return 'default'
})
</script>
<template>

View file

@ -1,27 +1,27 @@
// text, record, index, column
import dayjs from 'dayjs'
import type { JSX } from 'vue/jsx-runtime'
import { Tag } from 'ant-design-vue'
// text, record, index, column
import dayjs from 'dayjs'
import { get } from 'lodash'
export interface customRender {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export interface CustomRenderProps {
// eslint-disable-next-line ts/no-explicit-any
text: any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
record: any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
index: any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
column: any
isExport?: boolean
isDetail?: boolean
}
export const datetime = (args: customRender) => {
export function datetime(args: CustomRenderProps) {
return dayjs(args.text).format('YYYY-MM-DD HH:mm:ss')
}
export const date = (args: customRender) => {
export function date(args: CustomRenderProps) {
return args.text ? dayjs(args.text).format('YYYY-MM-DD') : '-'
}
@ -29,10 +29,10 @@ export const date = (args: customRender) => {
date.isDate = true
datetime.isDatetime = true
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const mask = (maskObj: any): (args: customRender) => JSX.Element => {
return (args: customRender) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
export function mask(maskObj: any): (args: CustomRenderProps) => JSX.Element {
return (args: CustomRenderProps) => {
// eslint-disable-next-line ts/no-explicit-any
let v: any
if (typeof maskObj?.[args.text] === 'function')
@ -45,15 +45,15 @@ export const mask = (maskObj: any): (args: customRender) => JSX.Element => {
}
}
export const arrayToTextRender = (args: customRender) => {
export function arrayToTextRender(args: CustomRenderProps) {
return args.text?.join(', ')
}
export const actualValueRender = (args: customRender, actualDataIndex: string | string[]) => {
export function actualValueRender(args: CustomRenderProps, actualDataIndex: string | string[]) {
return get(args.record, actualDataIndex)
}
export const longTextWithEllipsis = (len: number): (args: customRender) => JSX.Element => {
return (args: customRender) => {
export function longTextWithEllipsis(len: number): (args: CustomRenderProps) => JSX.Element {
return (args: CustomRenderProps) => {
if (args.isExport || args.isDetail)
return args.text
@ -61,29 +61,31 @@ export const longTextWithEllipsis = (len: number): (args: customRender) => JSX.E
}
}
export const year = (args: customRender) => {
export function year(args: CustomRenderProps) {
return dayjs(args.text).format('YYYY')
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const maskRenderWithColor = (maskObj: any) => (args: customRender) => {
let label: string
if (typeof maskObj[args.text] === 'function')
label = maskObj[args.text]()
else if (typeof maskObj[args.text] === 'string')
label = maskObj[args.text]
else label = args.text
// eslint-disable-next-line ts/no-explicit-any
export function maskRenderWithColor(maskObj: any) {
return (args: CustomRenderProps) => {
let label: string
if (typeof maskObj[args.text] === 'function')
label = maskObj[args.text]()
else if (typeof maskObj[args.text] === 'string')
label = maskObj[args.text]
else label = args.text
if (args.isExport)
return label
if (args.isExport)
return label
const colorMap = {
0: '',
1: 'blue',
2: 'green',
3: 'red',
4: 'cyan',
const colorMap = {
0: '',
1: 'blue',
2: 'green',
3: 'red',
4: 'cyan',
}
return args.text ? h(Tag, { color: colorMap[args.text] }, maskObj[args.text]) : '-'
}
return args.text ? h(Tag, { color: colorMap[args.text] }, maskObj[args.text]) : '-'
}

View file

@ -1,7 +1,7 @@
import type { CustomRenderProps } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
import _ from 'lodash'
import type { customRender } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
export function CustomRender(props: customRender) {
export function CustomRender(props: CustomRenderProps) {
return props.column.customRender
? props.column.customRender(props)
: _.get(props.record, props.column.dataIndex!)

View file

@ -1,9 +1,9 @@
import StdTable from './StdTable.vue'
import StdCurd from './StdCurd.vue'
import StdBatchEdit from './StdBatchEdit.vue'
import StdCurd from './StdCurd.vue'
import StdTable from './StdTable.vue'
export {
StdTable,
StdCurd,
StdBatchEdit,
StdCurd,
StdTable,
}

View file

@ -1,14 +1,14 @@
import type { StdTableProps } from '@/components/StdDesign/StdDataDisplay/StdTable.vue'
import type { Column, StdTableResponse } from '@/components/StdDesign/types'
import type { ComputedRef } from 'vue'
import { downloadCsv } from '@/lib/helper'
import { message } from 'ant-design-vue'
import dayjs from 'dayjs'
import type { ComputedRef } from 'vue'
import _ from 'lodash'
import { downloadCsv } from '@/lib/helper'
import type { Column, StdTableResponse } from '@/components/StdDesign/types'
import type { StdTableProps } from '@/components/StdDesign/StdDataDisplay/StdTable.vue'
async function exportCsv(props: StdTableProps, pithyColumns: ComputedRef<Column[]>) {
const header: { title?: string; key: Column['dataIndex'] }[] = []
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const header: { title?: string, key: Column['dataIndex'] }[] = []
// eslint-disable-next-line ts/no-explicit-any
const headerKeys: any[] = []
const showColumnsMap: Record<string, Column> = {}
@ -26,33 +26,31 @@ async function exportCsv(props: StdTableProps, pithyColumns: ComputedRef<Column[
showColumnsMap[column?.dataIndex?.toString() as string] = column
})
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
const dataSource: any[] = []
let hasMore = true
let page = 1
while (hasMore) {
// 准备 DataSource
await props
.api!.get_list({ page })
.then((r: StdTableResponse) => {
if (r.data.length === 0) {
hasMore = false
return
}
dataSource.push(...r.data)
})
.catch((e: { message?: string }) => {
message.error(e.message ?? $gettext('Server error'))
.api!.get_list({ page }).then((r: StdTableResponse) => {
if (r.data.length === 0) {
hasMore = false
})
return
}
dataSource.push(...r.data)
}).catch((e: { message?: string }) => {
message.error(e.message ?? $gettext('Server error'))
hasMore = false
})
page += 1
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
const data: any[] = []
dataSource.forEach(row => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
const obj: Record<string, any> = {}
headerKeys.forEach(key => {

View file

@ -1,17 +1,17 @@
import { message } from 'ant-design-vue'
import type { Ref } from 'vue'
import sortable from 'sortablejs'
import type { Key } from 'ant-design-vue/es/_util/type'
import type { StdTableProps } from '@/components/StdDesign/StdDataDisplay/StdTable.vue'
import type { Key } from 'ant-design-vue/es/_util/type'
import type { Ref } from 'vue'
import { message } from 'ant-design-vue'
import sortable from 'sortablejs'
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
function getRowKey(item: any) {
return item.dataset.rowKey
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
function getTargetData(data: any, indexList: number[]): any {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
let target: any = { children: data }
indexList.forEach((index: number) => {
target.children[index].parent = target
@ -21,112 +21,116 @@ function getTargetData(data: any, indexList: number[]): any {
return target
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function useSortable(props: StdTableProps, randomId: Ref<string>, dataSource: Ref<any[]>,
rowsKeyIndexMap: Ref<Record<number, number[]>>, expandKeysList: Ref<Key[]>) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
function useSortable(props: StdTableProps, randomId: Ref<string>, dataSource: Ref<any[]>, rowsKeyIndexMap: Ref<Record<number, number[]>>, expandKeysList: Ref<Key[]>) {
// eslint-disable-next-line ts/no-explicit-any
const table: any = document.querySelector(`#std-table-${randomId.value} tbody`)
// eslint-disable-next-line no-new,new-cap
new sortable(table, {
handle: '.ant-table-drag-icon',
animation: 150,
sort: true,
forceFallback: true,
setData(dataTransfer) {
dataTransfer.setData('Text', '')
},
onStart({ item }) {
const targetRowKey = Number(getRowKey(item))
if (targetRowKey)
expandKeysList.value = expandKeysList.value.filter((_item: Key) => _item !== targetRowKey)
},
onMove({
dragged,
related,
}) {
const oldRow: number[] = rowsKeyIndexMap.value?.[Number(getRowKey(dragged))]
const newRow: number[] = rowsKeyIndexMap.value?.[Number(getRowKey(related))]
try {
// eslint-disable-next-line no-new,new-cap
new sortable(table, {
handle: '.ant-table-drag-icon',
animation: 150,
sort: true,
forceFallback: true,
setData(dataTransfer) {
dataTransfer.setData('Text', '')
},
onStart({ item }) {
const targetRowKey = Number(getRowKey(item))
if (targetRowKey)
expandKeysList.value = expandKeysList.value.filter((_item: Key) => _item !== targetRowKey)
},
onMove({
dragged,
related,
}) {
const oldRow: number[] = rowsKeyIndexMap.value?.[Number(getRowKey(dragged))]
const newRow: number[] = rowsKeyIndexMap.value?.[Number(getRowKey(related))]
if (oldRow.length !== newRow.length || oldRow[oldRow.length - 2] !== newRow[newRow.length - 2])
return false
if (oldRow.length !== newRow.length || oldRow[oldRow.length - 2] !== newRow[newRow.length - 2])
return false
if (props.sortableMoveHook)
return props.sortableMoveHook(oldRow, newRow)
},
async onEnd({
item,
newIndex,
oldIndex,
}) {
if (newIndex === oldIndex)
return
if (props.sortableMoveHook)
return props.sortableMoveHook(oldRow, newRow)
},
async onEnd({
item,
newIndex,
oldIndex,
}) {
if (newIndex === oldIndex || newIndex === undefined)
return
const indexDelta: number = Number(oldIndex) - Number(newIndex)
const direction: number = indexDelta > 0 ? +1 : -1
const indexDelta: number = Number(oldIndex) - Number(newIndex)
const direction: number = indexDelta > 0 ? +1 : -1
const rowIndex: number[] = rowsKeyIndexMap.value?.[Number(getRowKey(item))]
const newRow = getTargetData(dataSource.value, rowIndex)
const newRowParent = newRow.parent
const level: number = newRow.level
const rowIndex: number[] = rowsKeyIndexMap.value?.[Number(getRowKey(item))]
const newRow = getTargetData(dataSource.value, rowIndex)
const newRowParent = newRow.parent
const level: number = newRow.level
const currentRowIndex: number[] = [...rowsKeyIndexMap.value?.
[Number(getRowKey(table.children[Number(newIndex) + direction]))]]
const currentRowIndex: number[] = [...rowsKeyIndexMap.value?.
[Number(getRowKey(table.children[Number(newIndex) + direction]))]]
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const currentRow: any = getTargetData(dataSource.value, currentRowIndex)
// eslint-disable-next-line ts/no-explicit-any
const currentRow: any = getTargetData(dataSource.value, currentRowIndex)
// Reset parent
currentRow.parent = newRow.parent = null
newRowParent.children.splice(rowIndex[level], 1)
newRowParent.children.splice(currentRowIndex[level], 0, toRaw(newRow))
// Reset parent
currentRow.parent = newRow.parent = null
newRowParent.children.splice(rowIndex[level], 1)
newRowParent.children.splice(currentRowIndex[level], 0, toRaw(newRow))
const changeIds: number[] = []
const changeIds: number[] = []
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function processChanges(row: any, children = false, _newIndex: number | undefined = undefined) {
// Build changes ID list expect new row
if (children || _newIndex === undefined)
changeIds.push(row.id)
// eslint-disable-next-line ts/no-explicit-any
function processChanges(row: any, children = false, _newIndex: number | undefined = undefined) {
// Build changes ID list expect new row
if (children || _newIndex === undefined)
changeIds.push(row.id)
if (_newIndex !== undefined)
rowsKeyIndexMap.value[row.id][level] = _newIndex
else if (children)
rowsKeyIndexMap.value[row.id][level] += direction
if (_newIndex !== undefined)
rowsKeyIndexMap.value[row.id][level] = _newIndex
else if (children)
rowsKeyIndexMap.value[row.id][level] += direction
row.parent = null
if (row.children) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
row.children.forEach((v: any) => processChanges(v, true, _newIndex))
row.parent = null
if (row.children) {
// eslint-disable-next-line ts/no-explicit-any
row.children.forEach((v: any) => processChanges(v, true, _newIndex))
}
}
}
// Replace row index for new row
processChanges(newRow, false, currentRowIndex[level])
// Replace row index for new row
processChanges(newRow, false, currentRowIndex[level])
// Rebuild row index maps for changes row
for (let i = Number(oldIndex); i !== newIndex; i -= direction) {
const _rowIndex: number[] = rowsKeyIndexMap.value?.[getRowKey(table.children[i])]
// Rebuild row index maps for changes row
for (let i = Number(oldIndex); i >= newIndex; i -= direction) {
const _rowIndex: number[] = rowsKeyIndexMap.value?.[getRowKey(table.children[i])]
_rowIndex[level] += direction
processChanges(getTargetData(dataSource.value, _rowIndex))
}
_rowIndex[level] += direction
processChanges(getTargetData(dataSource.value, _rowIndex))
}
// console.log('Change row id', newRow.id, 'order', newRow.id, '=>', currentRow.id, ', direction: ', direction,
// ', changes IDs:', changeIds
// console.log('Change row id', newRow.id, 'order', newRow.id, '=>', currentRow.id, ', direction: ', direction,
// ', changes IDs:', changeIds
props.api.update_order({
target_id: newRow.id,
direction,
affected_ids: changeIds,
}).then(() => {
message.success($gettext('Updated successfully'))
// eslint-disable-next-line @typescript-eslint/no-explicit-any
}).catch((e: any) => {
message.error(e?.message ?? $gettext('Server error'))
})
},
})
props.api.update_order({
target_id: newRow.id,
direction,
affected_ids: changeIds,
}).then(() => {
message.success($gettext('Updated successfully'))
// eslint-disable-next-line ts/no-explicit-any
}).catch((e: any) => {
message.error(e?.message ?? $gettext('Server error'))
})
},
})
}
catch (e) {
console.error(e)
}
}
export default useSortable

View file

@ -1,4 +1,6 @@
/* eslint-disable ts/no-explicit-any */
export interface StdTableSlots {
'append-search': ({}) => any
actions: ({}: Record<string, any>) => any
'append-search': (action) => any
'actions': (actions: Record<string, any>) => any
}

View file

@ -1,13 +1,13 @@
<script setup lang="tsx">
import { Form } from 'ant-design-vue'
import type { Ref } from 'vue'
import type { Column, JSXElements, StdDesignEdit } from '@/components/StdDesign/types'
import StdFormItem from '@/components/StdDesign/StdDataEntry/StdFormItem.vue'
import type { Ref } from 'vue'
import { labelRender } from '@/components/StdDesign/StdDataEntry'
import StdFormItem from '@/components/StdDesign/StdDataEntry/StdFormItem.vue'
import { Form } from 'ant-design-vue'
const props = defineProps<{
dataList: Column[]
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
dataSource: Record<string, any>
errors?: Record<string, string>
type?: 'search' | 'edit'
@ -15,7 +15,7 @@ const props = defineProps<{
}>()
const emit = defineEmits<{
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
'update:dataSource': [data: Record<string, any>]
}>()
@ -95,7 +95,7 @@ function Render() {
})
if (slots.action)
template.push(<div class={'std-data-entry-action'}>{slots.action()}</div>)
template.push(<div class="std-data-entry-action">{slots.action()}</div>)
return <Form ref={formRef} model={dataSource.value} layout={props.layout || 'vertical'}>{template}</Form>
}

View file

@ -1,6 +1,6 @@
<script setup lang="ts">
import { computed } from 'vue'
import type { Column } from '@/components/StdDesign/types'
import { computed } from 'vue'
const props = defineProps<Props>()

View file

@ -1,19 +1,19 @@
<script setup lang="ts">
import { ref } from 'vue'
import type { SelectProps } from 'ant-design-vue'
import { ref } from 'vue'
const props = defineProps<{
mask?: Record<string | number, string | (() => string)> | (() => Promise<Record<string | number, string>>)
placeholder?: string
multiple?: boolean
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
defaultValue?: any
}>()
const selectedValue = defineModel<string | number | string[] | number[]>('value')
const options = ref<SelectProps['options']>([])
const loadOptions = async () => {
async function loadOptions() {
options.value = []
let actualValue: number | string
if (typeof props.mask === 'function') {
@ -45,7 +45,7 @@ const loadOptions = async () => {
}
}
const init = () => {
function init() {
loadOptions()
}

View file

@ -1,28 +1,28 @@
<script setup lang="ts">
import _ from 'lodash'
import type { Ref } from 'vue'
import StdTable from '@/components/StdDesign/StdDataDisplay/StdTable.vue'
import type Curd from '@/api/curd'
import type { Column } from '@/components/StdDesign/types'
import type { Ref } from 'vue'
import StdTable from '@/components/StdDesign/StdDataDisplay/StdTable.vue'
import _ from 'lodash'
const props = defineProps<{
label?: string
selectedKey: number | number[] | undefined | null
selectionType: 'radio' | 'checkbox'
recordValueIndex: string // to index the value of the record
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
api: Curd<any>
columns: Column[]
disableSearch?: boolean
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
getParams?: any
description?: string
errorMessages?: string
itemKey?: string // default: id
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
value?: any | any[]
disabled?: boolean
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
valueApi?: Curd<any>
}>()
@ -33,7 +33,7 @@ const getParams = computed(() => {
})
const visible = ref(false)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
const M_values = ref([]) as any
const init = _.debounce(_init, 500, {
@ -45,7 +45,7 @@ onMounted(() => {
init()
})
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
const records = ref([]) as Ref<any[]>
async function _init() {

View file

@ -1,4 +1,6 @@
import { h } from 'vue'
import type { StdDesignEdit } from '@/components/StdDesign/types'
import type { Dayjs } from 'dayjs'
import { DATE_FORMAT } from '@/constants'
import {
DatePicker,
Input,
@ -7,16 +9,14 @@ import {
Switch,
Textarea,
} from 'ant-design-vue'
import type { Dayjs } from 'dayjs'
import dayjs from 'dayjs'
import StdDataEntry from './StdDataEntry.vue'
import StdSelector from './components/StdSelector.vue'
import StdSelect from './components/StdSelect.vue'
import { h } from 'vue'
import StdPassword from './components/StdPassword.vue'
import type { StdDesignEdit } from '@/components/StdDesign/types'
import { DATE_FORMAT } from '@/constants'
import StdSelect from './components/StdSelect.vue'
import StdSelector from './components/StdSelector.vue'
import StdDataEntry from './StdDataEntry.vue'
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
export function readonly(edit: StdDesignEdit, dataSource: any, dataIndex: any) {
return h('p', dataSource?.[dataIndex] ?? edit?.config?.defaultValue)
}
@ -32,7 +32,7 @@ export function placeholderHelper(edit: StdDesignEdit) {
return typeof edit.config?.placeholder === 'function' ? edit.config?.placeholder() : edit.config?.placeholder
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
export function input(edit: StdDesignEdit, dataSource: any, dataIndex: any) {
return h(Input, {
'autocomplete': 'off',
@ -44,7 +44,7 @@ export function input(edit: StdDesignEdit, dataSource: any, dataIndex: any) {
})
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
export function inputNumber(edit: StdDesignEdit, dataSource: any, dataIndex: any) {
if (edit.config?.defaultValue !== undefined)
dataSource[dataIndex] = edit.config.defaultValue
@ -64,7 +64,7 @@ export function inputNumber(edit: StdDesignEdit, dataSource: any, dataIndex: any
})
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
export function textarea(edit: StdDesignEdit, dataSource: any, dataIndex: any) {
return h(Textarea, {
'placeholder': placeholderHelper(edit),
@ -75,7 +75,7 @@ export function textarea(edit: StdDesignEdit, dataSource: any, dataIndex: any) {
})
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
export function password(edit: StdDesignEdit, dataSource: any, dataIndex: any) {
return (
<StdPassword
@ -87,7 +87,7 @@ export function password(edit: StdDesignEdit, dataSource: any, dataIndex: any) {
)
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
export function select(edit: StdDesignEdit, dataSource: any, dataIndex: any) {
const actualDataIndex = edit?.actualDataIndex ?? dataIndex
@ -102,7 +102,7 @@ export function select(edit: StdDesignEdit, dataSource: any, dataIndex: any) {
)
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
export function selector(edit: StdDesignEdit, dataSource: any, dataIndex: any) {
return (
<StdSelector
@ -119,18 +119,18 @@ export function selector(edit: StdDesignEdit, dataSource: any, dataIndex: any) {
)
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
export function switcher(edit: StdDesignEdit, dataSource: any, dataIndex: any) {
return h(Switch, {
'checked': dataSource?.[dataIndex] ?? edit?.config?.defaultValue,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
'onUpdate:checked': (value: any) => {
dataSource[dataIndex] = value
},
})
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
export function datePicker(edit: StdDesignEdit, dataSource: any, dataIndex: any) {
const date: Dayjs | undefined = dataSource?.[dataIndex] ? dayjs(dataSource?.[dataIndex]) : undefined
@ -143,7 +143,7 @@ export function datePicker(edit: StdDesignEdit, dataSource: any, dataIndex: any)
)
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
export function dateRangePicker(edit: StdDesignEdit, dataSource: any, dataIndex: any) {
const dates: [Dayjs, Dayjs] = dataSource
?.[dataIndex]

View file

@ -1,7 +1,8 @@
import Curd, {Pagination} from '@/api/curd'
import {Ref} from 'vue'
import type {JSX} from 'vue/jsx'
import {TableColumnType} from "ant-design-vue"
import type { Pagination } from '@/api/curd'
import type Curd from '@/api/curd'
import type { TableColumnType } from 'ant-design-vue'
import type { Ref } from 'vue'
import type { JSX } from 'vue/jsx'
export type JSXElements = JSX.Element[]
@ -25,7 +26,7 @@ export interface StdDesignEdit {
}
selector?: {
getParams?: {}
getParams?: object
recordValueIndex: any // relative to api return
selectionType: any
api: Curd
@ -52,7 +53,7 @@ export interface StdDesignEdit {
max?: number // max value for input number
error_messages?: Ref
required?: boolean
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
defaultValue?: any
addonBefore?: string // for inputNumber
addonAfter?: string // for inputNumber
@ -63,12 +64,14 @@ export interface StdDesignEdit {
flex?: Flex
}
type FlexType = string | number | boolean
export interface Flex {
sm?: string | number | boolean
md?: string | number | boolean
lg?: string | number | boolean
xl?: string | number | boolean
xxl?: string | number | boolean
sm?: FlexType
md?: FlexType
lg?: FlexType
xl?: FlexType
xxl?: FlexType
}
export interface Column extends TableColumnType {
@ -88,7 +91,7 @@ export interface Column extends TableColumnType {
batch?: boolean
customRender?: function
selector?: {
getParams?: {}
getParams?: object
recordValueIndex: any // relative to api return
selectionType: any
api: Curd

View file

@ -1,9 +1,9 @@
<script lang="ts" setup>
import type { Ref } from 'vue'
import VPIconMoon from './icons/VPIconMoon.vue'
import VPIconSun from './icons/VPIconSun.vue'
import VPSwitch from '@/components/VPSwitch/VPSwitch.vue'
import { useSettingsStore } from '@/pinia'
import VPIconMoon from './icons/VPIconMoon.vue'
import VPIconSun from './icons/VPIconSun.vue'
const settings = useSettingsStore()
const devicePrefersTheme = inject('devicePrefersTheme') as Ref<string>

View file

@ -1,11 +1,11 @@
<script setup lang="ts">
import type { TwoFAStatusResponse } from '@/api/2fa'
import twoFA from '@/api/2fa'
import OTPInput from '@/components/OTPInput/OTPInput.vue'
import { useUserStore } from '@/pinia'
import { KeyOutlined } from '@ant-design/icons-vue'
import { startAuthentication } from '@simplewebauthn/browser'
import { message } from 'ant-design-vue'
import OTPInput from '@/components/OTPInput/OTPInput.vue'
import type { TwoFAStatusResponse } from '@/api/2fa'
import twoFA from '@/api/2fa'
import { useUserStore } from '@/pinia'
defineProps<{
twoFAStatus: TwoFAStatusResponse
@ -55,7 +55,7 @@ async function passkeyAuthenticate() {
emit('submitSecureSessionID', r.session_id)
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
catch (e: any) {
message.error($gettext(e.message ?? 'Server error'))
}

View file

@ -1,10 +1,10 @@
import { createVNode, render } from 'vue'
import { Modal, message } from 'ant-design-vue'
import Authorization from '@/components/TwoFA/Authorization.vue'
import twoFA from '@/api/2fa'
import Authorization from '@/components/TwoFA/Authorization.vue'
import { useUserStore } from '@/pinia'
import { message, Modal } from 'ant-design-vue'
import { createVNode, render } from 'vue'
const use2FAModal = () => {
function use2FAModal() {
const refOTPAuthorization = ref<typeof Authorization>()
const randomId = Math.random().toString(36).substring(2, 8)
const { secureSessionId } = storeToRefs(useUserStore())

View file

@ -1,5 +1,5 @@
import type { Bread } from '@/components/Breadcrumb/types'
export const useBreadcrumbs = () => {
export function useBreadcrumbs() {
return inject('breadList') as Ref<Bread[]>
}

View file

@ -1,12 +1,12 @@
<script setup lang="ts">
import settings from '@/api/settings'
import PageHeader from '@/components/PageHeader/PageHeader.vue'
import { useSettingsStore } from '@/pinia'
import _ from 'lodash'
import { storeToRefs } from 'pinia'
import FooterLayout from './FooterLayout.vue'
import SideBar from './SideBar.vue'
import HeaderLayout from './HeaderLayout.vue'
import PageHeader from '@/components/PageHeader/PageHeader.vue'
import { useSettingsStore } from '@/pinia'
import settings from '@/api/settings'
import SideBar from './SideBar.vue'
const drawer_visible = ref(false)
const collapsed = ref(collapse())

View file

@ -1,12 +1,12 @@
<script setup lang="ts">
import { message } from 'ant-design-vue'
import { HomeOutlined, LogoutOutlined, MenuUnfoldOutlined } from '@ant-design/icons-vue'
import { useRouter } from 'vue-router'
import SetLanguage from '@/components/SetLanguage/SetLanguage.vue'
import auth from '@/api/auth'
import NginxControl from '@/components/NginxControl/NginxControl.vue'
import SwitchAppearance from '@/components/SwitchAppearance/SwitchAppearance.vue'
import Notification from '@/components/Notification/Notification.vue'
import SetLanguage from '@/components/SetLanguage/SetLanguage.vue'
import SwitchAppearance from '@/components/SwitchAppearance/SwitchAppearance.vue'
import { HomeOutlined, LogoutOutlined, MenuUnfoldOutlined } from '@ant-design/icons-vue'
import { message } from 'ant-design-vue'
import { useRouter } from 'vue-router'
const emit = defineEmits<{
clickUnFold: [void]

View file

@ -1,11 +1,11 @@
<script setup lang="ts">
import type { ComputedRef, Ref } from 'vue'
import type { AntdIconType } from '@ant-design/icons-vue/lib/components/AntdIcon'
import type { IconComponentProps } from '@ant-design/icons-vue/es/components/Icon'
import type { AntdIconType } from '@ant-design/icons-vue/lib/components/AntdIcon'
import type { Key } from 'ant-design-vue/es/_util/type'
import type { ComputedRef, Ref } from 'vue'
import EnvIndicator from '@/components/EnvIndicator/EnvIndicator.vue'
import Logo from '@/components/Logo/Logo.vue'
import { routes } from '@/routes'
import EnvIndicator from '@/components/EnvIndicator/EnvIndicator.vue'
const route = useRoute()
@ -33,41 +33,43 @@ const sidebars = computed(() => {
return routes[0].children
})
interface meta {
interface Meta {
icon: AntdIconType
hiddenInSidebar: boolean
hideChildren: boolean
name: () => string
}
interface sidebar {
interface Sidebar {
path: string
name: string
meta: meta
children: sidebar[]
meta: Meta
children: Sidebar[]
}
const visible: ComputedRef<sidebar[]> = computed(() => {
const res: sidebar[] = [];
const visible: ComputedRef<Sidebar[]> = computed(() => {
const res: Sidebar[] = [];
(sidebars.value || []).forEach(s => {
if (s.meta && ((typeof s.meta.hiddenInSidebar === 'boolean' && s.meta.hiddenInSidebar)
|| (typeof s.meta.hiddenInSidebar === 'function' && s.meta.hiddenInSidebar())))
|| (typeof s.meta.hiddenInSidebar === 'function' && s.meta.hiddenInSidebar()))) {
return
}
const t: sidebar = {
const t: Sidebar = {
path: s.path,
name: s.name as string,
meta: s.meta as unknown as meta,
meta: s.meta as unknown as Meta,
children: [],
};
(s.children || []).forEach(c => {
if (c.meta && ((typeof c.meta.hiddenInSidebar === 'boolean' && c.meta.hiddenInSidebar)
|| (typeof c.meta.hiddenInSidebar === 'function' && c.meta.hiddenInSidebar())))
|| (typeof c.meta.hiddenInSidebar === 'function' && c.meta.hiddenInSidebar()))) {
return
}
t.children.push((c as unknown as sidebar))
t.children.push((c as unknown as Sidebar))
})
res.push(t)
})

View file

@ -13,7 +13,7 @@ function bytesToSize(bytes: number) {
return `${(bytes / k ** i).toFixed(2)} ${sizes[i]}`
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
function downloadCsv(header: any, data: any[], fileName: string) {
if (!header || !Array.isArray(header) || !Array.isArray(data) || !header.length)
return
@ -25,8 +25,8 @@ function downloadCsv(header: any, data: any[], fileName: string) {
csvContent += `${_header}\n`
data.forEach((item, index) => {
let dataString = ''
for (let i = 0; i < keys.length; i++)
dataString += `${item[keys[i]]},`
for (const element of keys)
dataString += `${item[element]},`
csvContent += index < data.length ? dataString.replace(/,$/, '\n') : dataString.replace(/,$/, '')
})
@ -39,15 +39,16 @@ function downloadCsv(header: any, data: any[], fileName: string) {
window.URL.revokeObjectURL(csvContent)
}
const urlJoin = (...args: string[]) =>
args
function urlJoin(...args: string[]) {
return args
.join('/')
.replace(/[\/]+/g, '/')
.replace(/\/+/g, '/')
.replace(/^(.+):\//, '$1://')
.replace(/^file:/, 'file:/')
.replace(/\/(\?|&|#[^!])/g, '$1')
.replace(/\?/g, '&')
.replace('&', '?')
}
function fromNow(t: string) {
dayjs.extend(relativeTime)
@ -66,8 +67,8 @@ function formatDateTime(t: string) {
export {
bytesToSize,
downloadCsv,
urlJoin,
fromNow,
formatDate,
formatDateTime,
fromNow,
urlJoin,
}

View file

@ -1,12 +1,12 @@
import type { AxiosRequestConfig } from 'axios'
import axios from 'axios'
import { storeToRefs } from 'pinia'
import NProgress from 'nprogress'
import { useSettingsStore, useUserStore } from '@/pinia'
import 'nprogress/nprogress.css'
import router from '@/routes'
import use2FAModal from '@/components/TwoFA/use2FAModal'
import { useSettingsStore, useUserStore } from '@/pinia'
import router from '@/routes'
import axios from 'axios'
import NProgress from 'nprogress'
import { storeToRefs } from 'pinia'
import 'nprogress/nprogress.css'
const user = useUserStore()
const settings = useSettingsStore()
@ -30,17 +30,17 @@ instance.interceptors.request.use(
config => {
NProgress.start()
if (token.value) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
(config.headers as any).Authorization = token.value
}
if (settings.environment.id) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
(config.headers as any)['X-Node-ID'] = settings.environment.id
}
if (secureSessionId.value) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
(config.headers as any)['X-Secure-Session-ID'] = secureSessionId.value
}
@ -78,25 +78,25 @@ instance.interceptors.response.use(
const http = {
get(url: string, config: AxiosRequestConfig = {}) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
return instance.get<any, any>(url, config)
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
post(url: string, data: any = undefined, config: AxiosRequestConfig = {}) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
return instance.post<any, any>(url, data, config)
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
put(url: string, data: any = undefined, config: AxiosRequestConfig = {}) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
return instance.put<any, any>(url, data, config)
},
delete(url: string, config: AxiosRequestConfig = {}) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
return instance.delete<any, any>(url, config)
},
patch(url: string, config: AxiosRequestConfig = {}) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
return instance.patch<any, any>(url, config)
},
}

View file

@ -1,7 +1,7 @@
import ReconnectingWebSocket from 'reconnecting-websocket'
import { storeToRefs } from 'pinia'
import { useSettingsStore, useUserStore } from '@/pinia'
import { urlJoin } from '@/lib/helper'
import { useSettingsStore, useUserStore } from '@/pinia'
import { storeToRefs } from 'pinia'
import ReconnectingWebSocket from 'reconnecting-websocket'
function ws(url: string, reconnect: boolean = true): ReconnectingWebSocket | WebSocket {
const user = useUserStore()
@ -12,8 +12,7 @@ function ws(url: string, reconnect: boolean = true): ReconnectingWebSocket | Web
const node_id = (settings.environment.id > 0) ? (`&x_node_id=${settings.environment.id}`) : ''
const _url = urlJoin(protocol + window.location.host, window.location.pathname,
url, `?token=${btoa(token.value)}`, node_id)
const _url = urlJoin(protocol + window.location.host, window.location.pathname, url, `?token=${btoa(token.value)}`, node_id)
if (reconnect)
return new ReconnectingWebSocket(_url, undefined, { maxRetries: 10 })

View file

@ -1,11 +1,12 @@
import { createApp } from 'vue'
import { useSettingsStore } from '@/pinia'
import { autoAnimatePlugin } from '@formkit/auto-animate/vue'
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
import { autoAnimatePlugin } from '@formkit/auto-animate/vue'
import gettext from './gettext'
import { createApp } from 'vue'
import VueDOMPurifyHTML from 'vue-dompurify-html'
import App from './App.vue'
import gettext from './gettext'
import router from './routes'
import { useSettingsStore } from '@/pinia'
import './style.css'
const pinia = createPinia()
@ -15,6 +16,7 @@ const app = createApp(App)
pinia.use(piniaPluginPersistedstate)
app.use(pinia)
app.use(gettext)
app.use(VueDOMPurifyHTML)
// after pinia created
const settings = useSettingsStore()

View file

@ -1,7 +1,7 @@
import { useUserStore } from './moudule/user'
import { useSettingsStore } from './moudule/settings'
import { useUserStore } from './moudule/user'
export {
useUserStore,
useSettingsStore,
useUserStore,
}

View file

@ -1,5 +1,5 @@
import { defineStore } from 'pinia'
import type { NginxStatus } from '@/constants'
import { defineStore } from 'pinia'
export const useGlobalStore = defineStore('global', () => {
const nginxStatus:

View file

@ -1,6 +1,6 @@
import { defineStore } from 'pinia'
import { useCookies } from '@vueuse/integrations/useCookies'
import type { CookieChangeOptions } from 'universal-cookie'
import { useCookies } from '@vueuse/integrations/useCookies'
import { defineStore } from 'pinia'
export const useUserStore = defineStore('user', () => {
const cookies = useCookies(['nginx-ui'])

View file

@ -1,5 +1,5 @@
import type { RouteRecordRaw } from 'vue-router'
import { createRouter, createWebHashHistory } from 'vue-router'
import { useSettingsStore, useUserStore } from '@/pinia'
import {
BellOutlined,
@ -17,7 +17,7 @@ import {
} from '@ant-design/icons-vue'
import NProgress from 'nprogress'
import { useSettingsStore, useUserStore } from '@/pinia'
import { createRouter, createWebHashHistory } from 'vue-router'
import 'nprogress/nprogress.css'

View file

@ -1,8 +1,8 @@
import type { AntDesignOutlinedIconType } from '@ant-design/icons-vue/lib/icons/AntDesignOutlined'
// src/types/vue-router.d.ts
import 'vue-router'
import type {AntDesignOutlinedIconType} from '@ant-design/icons-vue/lib/icons/AntDesignOutlined'
/**
* @description Extend the types of router meta
*/

View file

@ -1,12 +1,12 @@
<script setup lang="tsx">
import { Tag, message } from 'ant-design-vue'
import type { Column } from '@/components/StdDesign/types'
import { StdCurd } from '@/components/StdDesign/StdDataDisplay'
import type { AcmeUser } from '@/api/acme_user'
import type { CustomRenderProps } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
import type { Column } from '@/components/StdDesign/types'
import acme_user from '@/api/acme_user'
import { input, switcher } from '@/components/StdDesign/StdDataEntry'
import type { customRender } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
import { StdCurd } from '@/components/StdDesign/StdDataDisplay'
import { datetime } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
import { input, switcher } from '@/components/StdDesign/StdDataEntry'
import { message, Tag } from 'ant-design-vue'
const columns: Column[] = [
{
@ -20,7 +20,8 @@ const columns: Column[] = [
required: true,
},
},
}, {
},
{
title: () => $gettext('Email'),
dataIndex: 'email',
sorter: true,
@ -31,7 +32,8 @@ const columns: Column[] = [
required: true,
},
},
}, {
},
{
title: () => $gettext('CA Dir'),
dataIndex: 'ca_dir',
sorter: true,
@ -44,7 +46,8 @@ const columns: Column[] = [
},
},
},
}, {
},
{
title: () => $gettext('Proxy'),
dataIndex: 'proxy',
hiddenInTable: true,
@ -57,10 +60,11 @@ const columns: Column[] = [
},
},
},
}, {
},
{
title: () => $gettext('Status'),
dataIndex: ['registration', 'body', 'status'],
customRender: (args: customRender) => {
customRender: (args: CustomRenderProps) => {
if (args.text === 'valid')
return <Tag color="green">{$gettext('Valid')}</Tag>
@ -68,7 +72,8 @@ const columns: Column[] = [
},
sorter: true,
pithy: true,
}, {
},
{
title: () => $gettext('Register On Startup'),
dataIndex: 'register_on_startup',
hiddenInTable: true,
@ -76,15 +81,17 @@ const columns: Column[] = [
edit: {
type: switcher,
hint: $gettext('When Enabled, Nginx UI will automatically re-register users upon startup. '
+ 'Generally, do not enable this unless you are in a dev environment and using Pebble as CA.'),
+ 'Generally, do not enable this unless you are in a dev environment and using Pebble as CA.'),
},
}, {
},
{
title: () => $gettext('Updated at'),
dataIndex: 'updated_at',
customRender: datetime,
sorter: true,
pithy: true,
}, {
},
{
title: () => $gettext('Action'),
dataIndex: 'action',
},

View file

@ -1,9 +1,9 @@
<script setup lang="ts">
import type { AcmeUser } from '@/api/acme_user'
import type { AutoCertOptions } from '@/api/auto_cert'
import type { SelectProps } from 'ant-design-vue'
import type { Ref } from 'vue'
import type { AcmeUser } from '@/api/acme_user'
import acme_user from '@/api/acme_user'
import type { AutoCertOptions } from '@/api/auto_cert'
const users = ref([]) as Ref<AcmeUser[]>
@ -51,7 +51,7 @@ onMounted(async () => {
break
page++
}
catch (e) {
catch {
break
}
}
@ -75,7 +75,7 @@ const options = computed<SelectProps['options']>(() => {
return list
})
const filterOption = (input: string, option: { label: string }) => {
function filterOption(input: string, option: { label: string }) {
return option.label.toLowerCase().includes(input.toLowerCase())
}
</script>

View file

@ -1,15 +1,15 @@
<script setup lang="ts">
import type { Cert } from '@/api/cert'
import type { Ref } from 'vue'
import { message } from 'ant-design-vue'
import cert from '@/api/cert'
import CodeEditor from '@/components/CodeEditor/CodeEditor.vue'
import FooterToolBar from '@/components/FooterToolbar/FooterToolBar.vue'
import NodeSelector from '@/components/NodeSelector/NodeSelector.vue'
import { AutoCertState } from '@/constants'
import RenewCert from '@/views/certificate/RenewCert.vue'
import CertInfo from '@/views/site/cert/CertInfo.vue'
import AutoCertStepOne from '@/views/site/cert/components/AutoCertStepOne.vue'
import CodeEditor from '@/components/CodeEditor/CodeEditor.vue'
import type { Cert } from '@/api/cert'
import cert from '@/api/cert'
import FooterToolBar from '@/components/FooterToolbar/FooterToolBar.vue'
import RenewCert from '@/views/certificate/RenewCert.vue'
import NodeSelector from '@/components/NodeSelector/NodeSelector.vue'
import { message } from 'ant-design-vue'
const route = useRoute()
@ -235,10 +235,9 @@ const isManaged = computed(() => {
:md="12"
>
<ACard :title="$gettext('Log')">
<pre
class="log-container"
v-html="log"
/>
<pre class="log-container">
{{ log }}
</pre>
</ACard>
</ACol>
</ARow>

View file

@ -1,9 +1,9 @@
<script setup lang="tsx">
import cert from '@/api/cert'
import StdTable from '@/components/StdDesign/StdDataDisplay/StdTable.vue'
import WildcardCertificate from '@/views/certificate/WildcardCertificate.vue'
import { CloudUploadOutlined, SafetyCertificateOutlined } from '@ant-design/icons-vue'
import certColumns from './certColumns'
import StdTable from '@/components/StdDesign/StdDataDisplay/StdTable.vue'
import cert from '@/api/cert'
import WildcardCertificate from '@/views/certificate/WildcardCertificate.vue'
const refWildcard = ref()
const refTable = ref()

View file

@ -1,17 +1,17 @@
import dayjs from 'dayjs'
import { Badge, Tag } from 'ant-design-vue'
import type { CustomRenderProps } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
import type { Column, JSXElements } from '@/components/StdDesign/types'
import type { customRender } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
import { datetime, mask } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
import { input } from '@/components/StdDesign/StdDataEntry'
import { PrivateKeyTypeMask } from '@/constants'
import { Badge, Tag } from 'ant-design-vue'
import dayjs from 'dayjs'
const columns: Column[] = [{
title: () => $gettext('Name'),
dataIndex: 'name',
sorter: true,
pithy: true,
customRender: (args: customRender) => {
customRender: (args: CustomRenderProps) => {
const { text, record } = args
if (!text)
return h('div', record.domain)
@ -24,26 +24,34 @@ const columns: Column[] = [{
}, {
title: () => $gettext('Type'),
dataIndex: 'auto_cert',
customRender: (args: customRender) => {
customRender: (args: CustomRenderProps) => {
const template: JSXElements = []
const { text } = args
const sync = $gettext('Sync Certificate')
const managed = $gettext('Managed Certificate')
const general = $gettext('General Certificate')
if (text === true || text === 1) {
template.push(<Tag bordered={false} color="processing">
{ managed }
</Tag>)
template.push(
<Tag bordered={false} color="processing">
{ managed }
</Tag>,
)
}
else if (text === 2) {
template.push(<Tag bordered={false} color="success">
{ sync }
</Tag>)
template.push(
<Tag bordered={false} color="success">
{ sync }
</Tag>,
)
}
else {
template.push(<Tag bordered={false} color="purple">{
general }
</Tag>)
template.push(
<Tag bordered={false} color="purple">
{
general
}
</Tag>,
)
}
return h('div', template)
@ -60,7 +68,7 @@ const columns: Column[] = [{
title: () => $gettext('Status'),
dataIndex: 'certificate_info',
pithy: true,
customRender: (args: customRender) => {
customRender: (args: CustomRenderProps) => {
const template: JSXElements = []
const text = args.text?.not_before
@ -69,11 +77,11 @@ const columns: Column[] = [{
&& !dayjs().isAfter(args.text?.not_after)
if (text) {
template.push(<Badge status="success"/>)
template.push(<Badge status="success" />)
template.push($gettext('Valid'))
}
else {
template.push(<Badge status="error"/>)
template.push(<Badge status="error" />)
template.push($gettext('Expired'))
}

View file

@ -1,7 +1,7 @@
<script setup lang="ts">
import type { DNSProvider } from '@/api/auto_cert'
import type { SelectProps } from 'ant-design-vue'
import type { Ref } from 'vue'
import type { DNSProvider } from '@/api/auto_cert'
import auto_cert from '@/api/auto_cert'
const providers = ref([]) as Ref<DNSProvider[]>
@ -62,7 +62,7 @@ const options = computed<SelectProps['options']>(() => {
return list
})
const filterOption = (input: string, option: { label: string }) => {
function filterOption(input: string, option: { label: string }) {
return option.label.toLowerCase().includes(input.toLowerCase())
}
</script>
@ -78,6 +78,7 @@ const filterOption = (input: string, option: { label: string }) => {
/>
</AFormItem>
<AFormItem>
<!-- eslint-disable sonarjs/no-vue-bypass-sanitization -->
<p v-if="current?.links?.api">
{{ $gettext('API Document') }}: <a
:href="current.links.api"
@ -92,6 +93,7 @@ const filterOption = (input: string, option: { label: string }) => {
rel="noopener noreferrer"
>{{ current.links.go_client }}</a>
</p>
<!-- eslint-enable -->
</AFormItem>
<template v-if="current?.configuration?.credentials">
<h4>{{ $gettext('Credentials') }}</h4>

View file

@ -1,11 +1,11 @@
<script setup lang="tsx">
import DNSChallenge from './DNSChallenge.vue'
import type { customRender } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
import { datetime } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
import type { CustomRenderProps } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
import type { Column } from '@/components/StdDesign/types'
import dns_credential from '@/api/dns_credential'
import StdCurd from '@/components/StdDesign/StdDataDisplay/StdCurd.vue'
import { datetime } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
import { input } from '@/components/StdDesign/StdDataEntry'
import type { Column } from '@/components/StdDesign/types'
import DNSChallenge from './DNSChallenge.vue'
const columns: Column[] = [{
title: () => $gettext('Name'),
@ -18,7 +18,7 @@ const columns: Column[] = [{
}, {
title: () => $gettext('Provider'),
dataIndex: ['config', 'name'],
customRender: (args: customRender) => {
customRender: (args: CustomRenderProps) => {
return args.record.provider
},
sorter: true,

View file

@ -1,7 +1,7 @@
<script setup lang="ts">
import { message } from 'ant-design-vue'
import ObtainCertLive from '@/views/site/cert/components/ObtainCertLive.vue'
import type { AutoCertOptions } from '@/api/auto_cert'
import ObtainCertLive from '@/views/site/cert/components/ObtainCertLive.vue'
import { message } from 'ant-design-vue'
const props = defineProps<{
options: AutoCertOptions
@ -16,7 +16,7 @@ const modalClosable = ref(true)
const refObtainCertLive = ref()
const issueCert = () => {
function issueCert() {
modalVisible.value = true
const { name, domains, key_type } = props.options

View file

@ -1,9 +1,9 @@
<script setup lang="ts">
import type { Ref } from 'vue'
import { message } from 'ant-design-vue'
import ObtainCertLive from '@/views/site/cert/components/ObtainCertLive.vue'
import type { AutoCertOptions } from '@/api/auto_cert'
import type { Ref } from 'vue'
import AutoCertStepOne from '@/views/site/cert/components/AutoCertStepOne.vue'
import ObtainCertLive from '@/views/site/cert/components/ObtainCertLive.vue'
import { message } from 'ant-design-vue'
const emit = defineEmits<{
issued: [void]
@ -39,12 +39,11 @@ const computedDomain = computed(() => {
return `*.${domain.value}`
})
const issueCert = () => {
function issueCert() {
step.value++
modalVisible.value = true
refObtainCertLive.value.issue_cert(computedDomain.value,
[computedDomain.value, domain.value], data.value.key_type)
refObtainCertLive.value.issue_cert(computedDomain.value, [computedDomain.value, domain.value], data.value.key_type)
.then(() => {
message.success($gettext('Renew successfully'))
emit('issued')

View file

@ -1,20 +1,20 @@
<script setup lang="ts">
import { message } from 'ant-design-vue'
import type { Ref } from 'vue'
import { InfoCircleOutlined } from '@ant-design/icons-vue'
import _ from 'lodash'
import { formatDateTime } from '@/lib/helper'
import FooterToolBar from '@/components/FooterToolbar/FooterToolBar.vue'
import type { Config } from '@/api/config'
import config from '@/api/config'
import CodeEditor from '@/components/CodeEditor/CodeEditor.vue'
import ngx from '@/api/ngx'
import InspectConfig from '@/views/config/InspectConfig.vue'
import ChatGPT from '@/components/ChatGPT/ChatGPT.vue'
import type { ChatComplicationMessage } from '@/api/openai'
import { useBreadcrumbs } from '@/composables/useBreadcrumbs'
import type { Ref } from 'vue'
import config from '@/api/config'
import ngx from '@/api/ngx'
import ChatGPT from '@/components/ChatGPT/ChatGPT.vue'
import CodeEditor from '@/components/CodeEditor/CodeEditor.vue'
import FooterToolBar from '@/components/FooterToolbar/FooterToolBar.vue'
import NodeSelector from '@/components/NodeSelector/NodeSelector.vue'
import { useBreadcrumbs } from '@/composables/useBreadcrumbs'
import { formatDateTime } from '@/lib/helper'
import { useSettingsStore } from '@/pinia'
import InspectConfig from '@/views/config/InspectConfig.vue'
import { InfoCircleOutlined } from '@ant-design/icons-vue'
import { message } from 'ant-design-vue'
import _ from 'lodash'
const settings = useSettingsStore()
const route = useRoute()

View file

@ -1,13 +1,13 @@
<script setup lang="ts">
import { $gettext } from '../../gettext'
import StdTable from '@/components/StdDesign/StdDataDisplay/StdTable.vue'
import config from '@/api/config'
import configColumns from '@/views/config/configColumns'
import FooterToolBar from '@/components/FooterToolbar/FooterToolBar.vue'
import InspectConfig from '@/views/config/InspectConfig.vue'
import StdTable from '@/components/StdDesign/StdDataDisplay/StdTable.vue'
import { useBreadcrumbs } from '@/composables/useBreadcrumbs'
import Mkdir from '@/views/config/components/Mkdir.vue'
import Rename from '@/views/config/components/Rename.vue'
import configColumns from '@/views/config/configColumns'
import InspectConfig from '@/views/config/InspectConfig.vue'
import { $gettext } from '../../gettext'
const table = ref()
const route = useRoute()

View file

@ -1,8 +1,7 @@
<script setup lang="ts">
import { message } from 'ant-design-vue'
import config from '@/api/config'
import use2FAModal from '@/components/TwoFA/use2FAModal'
import { message } from 'ant-design-vue'
const emit = defineEmits(['created'])
const visible = ref(false)

View file

@ -1,8 +1,8 @@
<script setup lang="ts">
import { message } from 'ant-design-vue'
import config from '@/api/config'
import use2FAModal from '@/components/TwoFA/use2FAModal'
import NodeSelector from '@/components/NodeSelector/NodeSelector.vue'
import use2FAModal from '@/components/TwoFA/use2FAModal'
import { message } from 'ant-design-vue'
const emit = defineEmits(['renamed'])
const visible = ref(false)

View file

@ -1,8 +1,8 @@
import { h } from 'vue'
import type { customRender } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
import { datetime } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
import type { CustomRenderProps } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
import type { JSXElements } from '@/components/StdDesign/types'
import { datetime } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
import { input } from '@/components/StdDesign/StdDataEntry'
import { h } from 'vue'
const configColumns = [{
title: () => $gettext('Name'),
@ -15,7 +15,7 @@ const configColumns = [{
}, {
title: () => $gettext('Type'),
dataIndex: 'is_dir',
customRender: (args: customRender) => {
customRender: (args: CustomRenderProps) => {
const template: JSXElements = []
const { text } = args
if (text === true || text > 0)

View file

@ -1,6 +1,6 @@
<script setup lang="ts">
import ServerAnalytic from '@/views/dashboard/ServerAnalytic.vue'
import Environments from '@/views/dashboard/Environments.vue'
import ServerAnalytic from '@/views/dashboard/ServerAnalytic.vue'
const key = ref(0)

View file

@ -1,16 +1,16 @@
<script setup lang="ts">
import Icon, { LinkOutlined, SendOutlined, ThunderboltOutlined } from '@ant-design/icons-vue'
import type { Node } from '@/api/environment'
import type ReconnectingWebSocket from 'reconnecting-websocket'
import type { Ref } from 'vue'
import { useSettingsStore } from '@/pinia'
import type { Node } from '@/api/environment'
import analytic from '@/api/analytic'
import environment from '@/api/environment'
import logo from '@/assets/img/logo.png'
import pulse from '@/assets/svg/pulse.svg?component'
import { formatDateTime } from '@/lib/helper'
import NodeAnalyticItem from '@/views/dashboard/components/NodeAnalyticItem.vue'
import analytic from '@/api/analytic'
import { useSettingsStore } from '@/pinia'
import { version } from '@/version.json'
import NodeAnalyticItem from '@/views/dashboard/components/NodeAnalyticItem.vue'
import Icon, { LinkOutlined, SendOutlined, ThunderboltOutlined } from '@ant-design/icons-vue'
const data = ref([]) as Ref<Node[]>

View file

@ -1,11 +1,11 @@
<script setup lang="ts">
import type { CPUInfoStat, DiskStat, HostInfoStat, LoadStat, MemStat } from '@/api/analytic'
import type { Series } from '@/components/Chart/types'
import type ReconnectingWebSocket from 'reconnecting-websocket'
import analytic from '@/api/analytic'
import AreaChart from '@/components/Chart/AreaChart.vue'
import RadialBarChart from '@/components/Chart/RadialBarChart.vue'
import type { CPUInfoStat, DiskStat, HostInfoStat, LoadStat, MemStat } from '@/api/analytic'
import analytic from '@/api/analytic'
import { bytesToSize } from '@/lib/helper'
import type { Series } from '@/components/Chart/types'
let websocket: ReconnectingWebSocket | WebSocket
@ -21,11 +21,9 @@ const cpu = ref('0.0')
const cpu_info = reactive([]) as CPUInfoStat[]
const cpu_analytic_series = reactive([{ name: 'User', data: [] }, { name: 'Total', data: [] }]) as Series[]
const net_analytic = reactive([{ name: $gettext('Receive'), data: [] },
{ name: $gettext('Send'), data: [] }]) as Series[]
const net_analytic = reactive([{ name: $gettext('Receive'), data: [] }, { name: $gettext('Send'), data: [] }]) as Series[]
const disk_io_analytic = reactive([{ name: $gettext('Writes'), data: [] },
{ name: $gettext('Reads'), data: [] }]) as Series[]
const disk_io_analytic = reactive([{ name: $gettext('Writes'), data: [] }, { name: $gettext('Reads'), data: [] }]) as Series[]
const memory = reactive({
total: '',
@ -45,11 +43,11 @@ const uptime = ref('')
const loadavg = reactive({ load1: 0, load5: 0, load15: 0 }) as LoadStat
const net = reactive({ recv: 0, sent: 0, last_recv: 0, last_sent: 0 })
const net_formatter = (bytes: number) => {
function net_formatter(bytes: number) {
return `${bytesToSize(bytes)}/s`
}
const cpu_formatter = (usage: number) => {
function cpu_formatter(usage: number) {
return usage.toFixed(2)
}

View file

@ -1,9 +1,9 @@
<script setup lang="ts">
import Icon, { ArrowDownOutlined, ArrowUpOutlined, DatabaseOutlined, LineChartOutlined } from '@ant-design/icons-vue'
import cpu from '@/assets/svg/cpu.svg?component'
import memory from '@/assets/svg/memory.svg?component'
import { bytesToSize } from '@/lib/helper'
import UsageProgressLine from '@/components/Chart/UsageProgressLine.vue'
import { bytesToSize } from '@/lib/helper'
import Icon, { ArrowDownOutlined, ArrowUpOutlined, DatabaseOutlined, LineChartOutlined } from '@ant-design/icons-vue'
defineProps<{
item: {
@ -157,5 +157,4 @@ defineProps<{
}
}
}
</style>

View file

@ -1,12 +1,11 @@
<script setup lang="ts">
import _ from 'lodash'
import { message } from 'ant-design-vue'
import type { Ref } from 'vue'
import { marked } from 'marked'
import { useRoute } from 'vue-router'
import type { Environment } from '@/api/environment'
import type { Ref } from 'vue'
import upgrade, { type RuntimeInfo } from '@/api/upgrade'
import websocket from '@/lib/websocket'
import { message } from 'ant-design-vue'
import _ from 'lodash'
import { useRoute } from 'vue-router'
const route = useRoute()
const visible = ref(false)
@ -80,7 +79,6 @@ const dryRun = computed(() => {
return !!route.query.dry_run
})
// eslint-disable-next-line sonarjs/cognitive-complexity
async function performUpgrade() {
showLogContainer.value = true
progressStatus.value = 'active'
@ -224,7 +222,7 @@ async function performUpgrade() {
{{ $gettext('Pre-release') }}
</ATag>
</h1>
<div v-html="marked.parse(data.body)" />
<div vue-dompurify-html="marked.parse(data.body)" />
</div>
<div class="flex justify-end">

View file

@ -1,10 +1,10 @@
<script setup lang="tsx">
import { message } from 'ant-design-vue'
import environment from '@/api/environment'
import StdCurd from '@/components/StdDesign/StdDataDisplay/StdCurd.vue'
import envColumns from '@/views/environment/envColumns'
import FooterToolBar from '@/components/FooterToolbar'
import StdCurd from '@/components/StdDesign/StdDataDisplay/StdCurd.vue'
import BatchUpgrader from '@/views/environment/BatchUpgrader.vue'
import envColumns from '@/views/environment/envColumns'
import { message } from 'ant-design-vue'
const curd = ref()
function loadFromSettings() {

View file

@ -1,9 +1,9 @@
import { h } from 'vue'
import { Badge, Tag } from 'ant-design-vue'
import type { CustomRenderProps } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
import type { Column, JSXElements } from '@/components/StdDesign/types'
import { input, switcher } from '@/components/StdDesign/StdDataEntry'
import type { customRender } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
import { datetime } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
import { input, switcher } from '@/components/StdDesign/StdDataEntry'
import { Badge, Tag } from 'ant-design-vue'
import { h } from 'vue'
const columns: Column[] = [{
title: () => $gettext('Name'),
@ -14,8 +14,7 @@ const columns: Column[] = [{
type: input,
},
search: true,
},
{
}, {
title: () => $gettext('URL'),
dataIndex: 'url',
sorter: true,
@ -26,13 +25,11 @@ const columns: Column[] = [{
placeholder: () => 'https://10.0.0.1:9000',
},
},
},
{
}, {
title: () => $gettext('Version'),
dataIndex: 'version',
pithy: true,
},
{
}, {
title: () => 'NodeSecret',
dataIndex: 'token',
sorter: true,
@ -77,21 +74,21 @@ const columns: Column[] = [{
{
title: () => $gettext('Status'),
dataIndex: 'status',
customRender: (args: customRender) => {
customRender: (args: CustomRenderProps) => {
const template: JSXElements = []
const { text } = args
if (args.record.enabled) {
if (text === true || text > 0) {
template.push(<Badge status="success"/>)
template.push(<Badge status="success" />)
template.push($gettext('Online'))
}
else {
template.push(<Badge status="error"/>)
template.push(<Badge status="error" />)
template.push($gettext('Offline'))
}
}
else {
template.push(<Badge status="default"/>)
template.push(<Badge status="default" />)
template.push($gettext('Disabled'))
}
@ -99,11 +96,10 @@ const columns: Column[] = [{
},
sorter: true,
pithy: true,
},
{
}, {
title: () => $gettext('Enabled'),
dataIndex: 'enabled',
customRender: (args: customRender) => {
customRender: (args: CustomRenderProps) => {
const template: JSXElements = []
const { text } = args
if (text === true || text > 0)
@ -119,15 +115,13 @@ const columns: Column[] = [{
},
sorter: true,
pithy: true,
},
{
}, {
title: () => $gettext('Updated at'),
dataIndex: 'updated_at',
customRender: datetime,
sorter: true,
pithy: true,
},
{
}, {
title: () => $gettext('Action'),
dataIndex: 'action',
}]

View file

@ -1,10 +1,10 @@
<script setup lang="ts">
import type ReconnectingWebSocket from 'reconnecting-websocket'
import { debounce } from 'lodash'
import FooterToolBar from '@/components/FooterToolbar/FooterToolBar.vue'
import type { INginxLogData } from '@/api/nginx_log'
import type ReconnectingWebSocket from 'reconnecting-websocket'
import nginx_log from '@/api/nginx_log'
import FooterToolBar from '@/components/FooterToolbar/FooterToolBar.vue'
import ws from '@/lib/websocket'
import { debounce } from 'lodash'
const logContainer = ref()
let websocket: ReconnectingWebSocket | WebSocket
@ -24,7 +24,9 @@ const control: INginxLogData = reactive({
})
function logType() {
return route.path.indexOf('access') > 0 ? 'access' : route.path.indexOf('error') > 0 ? 'error' : 'site'
if (route.path.indexOf('access') > 0)
return 'access'
return route.path.indexOf('error') > 0 ? 'error' : 'site'
}
function openWs() {
@ -162,8 +164,9 @@ const computedBuffer = computed(() => {
ref="logContainer"
class="nginx-log-container"
@scroll="debounce_scroll_log"
v-html="computedBuffer"
/>
>
{{ computedBuffer }}
</pre>
</ACard>
<FooterToolBar v-if="control.type === 'site'">
<AButton @click="router.go(-1)">

View file

@ -1,9 +1,9 @@
<script setup lang="ts">
import { message } from 'ant-design-vue'
import StdCurd from '@/components/StdDesign/StdDataDisplay/StdCurd.vue'
import notification from '@/api/notification'
import StdCurd from '@/components/StdDesign/StdDataDisplay/StdCurd.vue'
import { useUserStore } from '@/pinia'
import notificationColumns from '@/views/notification/notificationColumns'
import { message } from 'ant-design-vue'
const { unreadCount } = storeToRefs(useUserStore())

View file

@ -1,33 +1,41 @@
import { Tag } from 'ant-design-vue'
import type { CustomRenderProps } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
import type { Column } from '@/components/StdDesign/types'
import type { customRender } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
import { detailRender } from '@/components/Notification/detailRender'
import { datetime } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
import { NotificationTypeT } from '@/constants'
import { detailRender } from '@/components/Notification/detailRender'
import { Tag } from 'ant-design-vue'
const columns: Column[] = [{
title: () => $gettext('Type'),
dataIndex: 'type',
customRender: (args: customRender) => {
customRender: (args: CustomRenderProps) => {
if (args.text === NotificationTypeT.Error) {
return <Tag color="error">
{ $gettext('Error') }
</Tag>
return (
<Tag color="error">
{ $gettext('Error') }
</Tag>
)
}
else if (args.text === NotificationTypeT.Warning) {
return <Tag color="warning">
{ $gettext('Warning') }
</Tag>
return (
<Tag color="warning">
{ $gettext('Warning') }
</Tag>
)
}
else if (args.text === NotificationTypeT.Info) {
return <Tag color="info">
{ $gettext('Info')}
</Tag>
return (
<Tag color="info">
{ $gettext('Info')}
</Tag>
)
}
else if (args.text === NotificationTypeT.Success) {
return <Tag color="success">
{ $gettext('Success') }
</Tag>
return (
<Tag color="success">
{ $gettext('Success') }
</Tag>
)
}
},
sorter: true,
@ -35,7 +43,7 @@ const columns: Column[] = [{
}, {
title: () => $gettext('Title'),
dataIndex: 'title',
customRender: (args: customRender) => {
customRender: (args: CustomRenderProps) => {
return h('span', $gettext(args.text))
},
pithy: true,

View file

@ -1,5 +1,4 @@
<script setup lang="ts">
const route = useRoute()
const info = computed(() => {

View file

@ -1,11 +1,11 @@
<script setup lang="ts">
import install from '@/api/install'
import SetLanguage from '@/components/SetLanguage/SetLanguage.vue'
import SwitchAppearance from '@/components/SwitchAppearance/SwitchAppearance.vue'
import { DatabaseOutlined, LockOutlined, MailOutlined, UserOutlined } from '@ant-design/icons-vue'
import { Form, message } from 'ant-design-vue'
import { useRouter } from 'vue-router'
import { DatabaseOutlined, LockOutlined, MailOutlined, UserOutlined } from '@ant-design/icons-vue'
import SetLanguage from '@/components/SetLanguage/SetLanguage.vue'
import install from '@/api/install'
import SwitchAppearance from '@/components/SwitchAppearance/SwitchAppearance.vue'
const thisYear = new Date().getFullYear()
const loading = ref(false)
@ -47,16 +47,14 @@ const rulesRef = reactive({
database: [
{
message: () =>
$gettext('The filename cannot contain the following characters: %{c}',
{ c: '& &quot; ? < > # {} % ~ / \\' },
),
$gettext('The filename cannot contain the following characters: %{c}', { c: '& &quot; ? < > # {} % ~ / \\' }),
},
],
})
const { validate, validateInfos } = Form.useForm(modelRef, rulesRef)
const onSubmit = () => {
function onSubmit() {
validate().then(() => {
// modelRef
loading.value = true

View file

@ -1,15 +1,15 @@
<script setup lang="ts">
import { KeyOutlined, LockOutlined, UserOutlined } from '@ant-design/icons-vue'
import { Form, message } from 'ant-design-vue'
import { startAuthentication } from '@simplewebauthn/browser'
import { useUserStore } from '@/pinia'
import auth from '@/api/auth'
import install from '@/api/install'
import passkey from '@/api/passkey'
import SetLanguage from '@/components/SetLanguage/SetLanguage.vue'
import SwitchAppearance from '@/components/SwitchAppearance/SwitchAppearance.vue'
import Authorization from '@/components/TwoFA/Authorization.vue'
import gettext from '@/gettext'
import passkey from '@/api/passkey'
import { useUserStore } from '@/pinia'
import { KeyOutlined, LockOutlined, UserOutlined } from '@ant-design/icons-vue'
import { startAuthentication } from '@simplewebauthn/browser'
import { Form, message } from 'ant-design-vue'
const thisYear = new Date().getFullYear()
@ -53,7 +53,7 @@ const userStore = useUserStore()
const { login, passkeyLogin } = userStore
const { secureSessionId } = storeToRefs(userStore)
const onSubmit = () => {
function onSubmit() {
validate().then(async () => {
loading.value = true
@ -121,7 +121,7 @@ auth.get_casdoor_uri()
message.error($gettext(e.message ?? 'Server error'))
})
const loginWithCasdoor = () => {
function loginWithCasdoor() {
window.location.href = casdoor_uri.value
}
@ -172,7 +172,7 @@ async function handlePasskeyLogin() {
await router.push(next)
}
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line ts/no-explicit-any
catch (e: any) {
message.error($gettext(e.message ?? 'Server error'))
}

View file

@ -1,12 +1,12 @@
<script setup lang="tsx">
import { message } from 'ant-design-vue'
import type { BannedIP, Settings } from '@/api/settings'
import type { CustomRenderProps } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
import type { Ref } from 'vue'
import setting from '@/api/settings'
import TOTP from '@/views/preference/components/TOTP.vue'
import { message } from 'ant-design-vue'
import dayjs from 'dayjs'
import PasskeyRegistration from './components/Passkey.vue'
import type { BannedIP, Settings } from '@/api/settings'
import setting from '@/api/settings'
import type { customRender } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
import TOTP from '@/views/preference/components/TOTP.vue'
const data: Settings = inject('data') as Settings
@ -19,7 +19,7 @@ const bannedIPColumns = [{
}, {
title: $gettext('Banned Until'),
dataIndex: 'expired_at',
customRender: (args: customRender) => {
customRender: (args: CustomRenderProps) => {
return dayjs.unix(args.text).format('YYYY-MM-DD HH:mm:ss')
},
}, {

View file

@ -1,7 +1,7 @@
<script setup lang="ts">
import Draggable from 'vuedraggable'
import { DeleteOutlined, HolderOutlined } from '@ant-design/icons-vue'
import type { Settings } from '@/api/settings'
import { DeleteOutlined, HolderOutlined } from '@ant-design/icons-vue'
import Draggable from 'vuedraggable'
const data: Settings = inject('data') as Settings
const errors: Record<string, Record<string, string>> = inject('errors') as Record<string, Record<string, string>>

View file

@ -1,18 +1,18 @@
<script setup lang="ts">
import { message } from 'ant-design-vue'
import type { Ref } from 'vue'
import { storeToRefs } from 'pinia'
import FooterToolBar from '@/components/FooterToolbar/FooterToolBar.vue'
import settings from '@/api/settings'
import BasicSettings from '@/views/preference/BasicSettings.vue'
import OpenAISettings from '@/views/preference/OpenAISettings.vue'
import NginxSettings from '@/views/preference/NginxSettings.vue'
import type { Settings } from '@/api/settings'
import LogrotateSettings from '@/views/preference/LogrotateSettings.vue'
import type { Ref } from 'vue'
import settings from '@/api/settings'
import FooterToolBar from '@/components/FooterToolbar/FooterToolBar.vue'
import use2FAModal from '@/components/TwoFA/use2FAModal'
import { useSettingsStore } from '@/pinia'
import AuthSettings from '@/views/preference/AuthSettings.vue'
import use2FAModal from '@/components/TwoFA/use2FAModal'
import BasicSettings from '@/views/preference/BasicSettings.vue'
import CertSettings from '@/views/preference/CertSettings.vue'
import LogrotateSettings from '@/views/preference/LogrotateSettings.vue'
import NginxSettings from '@/views/preference/NginxSettings.vue'
import OpenAISettings from '@/views/preference/OpenAISettings.vue'
import { message } from 'ant-design-vue'
import { storeToRefs } from 'pinia'
const data = ref<Settings>({
app: {
@ -135,7 +135,6 @@ onMounted(() => {
if (route.query?.tab)
activeKey.value = route.query.tab.toString()
})
</script>
<template>

Some files were not shown because too many files have changed in this diff Show more