diff --git a/auth.go b/auth.go new file mode 100644 index 0000000..5591381 --- /dev/null +++ b/auth.go @@ -0,0 +1,71 @@ +package main + +import ( + "crypto/rand" + "myproject/tools" + "net/http" + "strings" + + "github.com/gorilla/sessions" + "github.com/labstack/echo/v4" +) + +func NewAuthStore() *sessions.CookieStore { + auth := make([]byte, 32) + _, _ = rand.Read(auth) + enc := make([]byte, 16) + _, _ = rand.Read(enc) + s := sessions.NewCookieStore(auth, enc) + s.Options.Secure = false + s.Options.SameSite = http.SameSiteDefaultMode + s.MaxAge(3600) + return s +} + +func setAuth(onlyAdmin bool, g *echo.Group) *echo.Group { + g.Use( + func(next echo.HandlerFunc) echo.HandlerFunc { + return func(c echo.Context) error { + sess, err := c.Get("authStore").(*sessions.CookieStore).New(c.Request(), tools.SessionName) + if err != nil { + // journal.Debug(ctx, commerr.Trace(err).Error()) + } + + userName := sess.Values[tools.UserNameSessionKey] + if userName == nil { + return echo.ErrUnauthorized + } + + email, lp, domain := SplitEmail(userName.(string)) + c.Set(tools.UserCtxKey, email) + c.Set(tools.LpCtxKey, lp) + c.Set(tools.DomainCtxKey, domain) + + return next(c) + } + }, + func(next echo.HandlerFunc) echo.HandlerFunc { + return func(c echo.Context) error { + if onlyAdmin && tools.GetUser(c) != "admin" { + return echo.ErrUnauthorized + } + + return next(c) + } + }, + ) + + return g +} + +func SplitEmail(toSplit string) (email, user, domain string) { + email = strings.TrimSpace(toSplit) + email = strings.ToLower(email) + parts := strings.Split(email, "@") + user = parts[0] + if len(parts) > 1 { + domain = parts[1] + } + + return +} diff --git a/echo.go b/echo.go new file mode 100644 index 0000000..ecfccde --- /dev/null +++ b/echo.go @@ -0,0 +1,98 @@ +package main + +import ( + "context" + "fmt" + "myproject/tools" + "net" + "net/http" + "strings" + "time" + + "github.com/labstack/echo/v4" + "github.com/labstack/echo/v4/middleware" +) + +func NewEcho(ctx context.Context, restartMode *bool) *echo.Echo { + timeout := 5 * time.Minute + e := echo.New() + e.HideBanner = true + e.Server.ReadTimeout = timeout + e.Server.WriteTimeout = timeout + e.Server.BaseContext = func(listener net.Listener) context.Context { + return ctx + } + e.HTTPErrorHandler = func(err error, c echo.Context) { + httpError, ok := err.(*echo.HTTPError) + if ok { + errorCode := httpError.Code + switch errorCode { + case http.StatusServiceUnavailable: + tools.Serve503(c) + case http.StatusTooManyRequests: + tools.Serve429(c) + case http.StatusForbidden: + tools.Serve403(c) + case http.StatusUnauthorized: + tools.Serve401(c) + case http.StatusNotFound, http.StatusMethodNotAllowed: + if strings.HasPrefix(c.Request().RequestURI, "/backend") { + switch errorCode { + case http.StatusNotFound: + tools.Serve404(c) + case http.StatusMethodNotAllowed: + tools.Serve405(c) + } + return + } + c.Redirect(http.StatusTemporaryRedirect, fmt.Sprintf("/?redirect=%s", c.Request().RequestURI)) + default: + tools.Serve500(c) + } + } + } + + authStore := NewAuthStore() + + e.Use( + middleware.CORSWithConfig(middleware.CORSConfig{ + AllowOrigins: []string{"http://localhost:7777", "http://localhost:8808"}, + AllowHeaders: []string{ + echo.HeaderOrigin, + echo.HeaderContentType, + echo.HeaderAccept, + echo.HeaderAccessControlAllowOrigin, + echo.HeaderAccessControlAllowCredentials, + echo.HeaderAccessControlAllowHeaders, + echo.HeaderAccessControlRequestHeaders, + echo.HeaderAuthorization, + }, + AllowCredentials: true, + }), + middleware.GzipWithConfig(middleware.GzipConfig{ + Level: 6, + }), + func(next echo.HandlerFunc) echo.HandlerFunc { + return func(c echo.Context) error { + c.Set("authStore", authStore) + + return next(c) + } + }, + func(next echo.HandlerFunc) echo.HandlerFunc { + return func(c echo.Context) error { + + return next(c) + } + }, + func(next echo.HandlerFunc) echo.HandlerFunc { + return func(c echo.Context) error { + c.Set(tools.RootCtxKey, ctx) + + return next(c) + } + }, + ) + + return e +} diff --git a/frontend/.env.development b/frontend/.env.development new file mode 100644 index 0000000..1bb4252 --- /dev/null +++ b/frontend/.env.development @@ -0,0 +1 @@ +VITE_API_URL=http://localhost:8888 \ No newline at end of file diff --git a/frontend/.env.production b/frontend/.env.production new file mode 100644 index 0000000..3452b5c --- /dev/null +++ b/frontend/.env.production @@ -0,0 +1 @@ +VITE_API_URL= \ No newline at end of file diff --git a/frontend/.gitignore b/frontend/.gitignore new file mode 100644 index 0000000..a52d458 --- /dev/null +++ b/frontend/.gitignore @@ -0,0 +1,29 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +.DS_Store +dist-ssr +coverage +*.local + +/cypress/videos/ +/cypress/screenshots/ + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +*.tsbuildinfo diff --git a/frontend/README.md b/frontend/README.md index 98f4a52..74e1fcc 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -1,23 +1,33 @@ -# Vue 3 + TypeScript + Vite +# js -This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue -3 ` - + + + + + Tegu + + +
+ + - diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 68c0354..ae0b5d5 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,46 +1,63 @@ { - "name": "frontend", + "name": "js", "version": "0.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "frontend", + "name": "js", "version": "0.0.0", "dependencies": { - "vue": "^3.2.37" + "@ant-design/icons-vue": "^7.0.1", + "ant-design-vue": "^4.2.3", + "pinia": "^2.1.7", + "pinia-plugin-persistedstate": "^3.2.1", + "vue": "^3.4.21", + "vue-i18n": "^9.13.1", + "vue-router": "^4.3.0" }, "devDependencies": { - "@babel/types": "^7.18.10", - "@vitejs/plugin-vue": "^3.0.3", - "typescript": "^4.6.4", - "vite": "^3.0.7", - "vue-tsc": "^1.8.27" + "@tsconfig/node20": "^20.1.4", + "@types/node": "^20.12.5", + "@vitejs/plugin-vue": "^5.0.4", + "@vue/tsconfig": "^0.5.1", + "less": "^4.3.0", + "less-loader": "^12.2.0", + "npm-run-all2": "^6.1.2", + "typescript": "~5.4.0", + "vite": "^5.2.8", + "vue-tsc": "^2.0.11" } }, - "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", - "engines": { - "node": ">=6.9.0" + "node_modules/@ant-design/colors": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-6.0.0.tgz", + "integrity": "sha512-qAZRvPzfdWHtfameEGP2Qvuf838NhergR35o+EuVyB5XvSA98xod5r4utvi4TJ3ywmevm290g9nsCG5MryrdWQ==", + "dependencies": { + "@ctrl/tinycolor": "^3.4.0" } }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", - "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", - "engines": { - "node": ">=6.9.0" + "node_modules/@ant-design/icons-svg": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@ant-design/icons-svg/-/icons-svg-4.4.2.tgz", + "integrity": "sha512-vHbT+zJEVzllwP+CM+ul7reTEfBR0vgxFe7+lREAsAA7YGsYpboiq2sQNeQeRvh09GfQgs/GyFEvZpJ9cLXpXA==" + }, + "node_modules/@ant-design/icons-vue": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@ant-design/icons-vue/-/icons-vue-7.0.1.tgz", + "integrity": "sha512-eCqY2unfZK6Fe02AwFlDHLfoyEFreP6rBwAZMIJ1LugmfMiVgwWDYlp1YsRugaPtICYOabV1iWxXdP12u9U43Q==", + "dependencies": { + "@ant-design/colors": "^6.0.0", + "@ant-design/icons-svg": "^4.2.1" + }, + "peerDependencies": { + "vue": ">=3.0.3" } }, "node_modules/@babel/parser": { - "version": "7.27.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.5.tgz", - "integrity": "sha512-OsQd175SxWkGlzbny8J3K8TnnDD0N3lrIUtB92xwyRpzaenGZhxDvxN/JgU00U3CDZNj9tPuDJ5H0WS4Nt3vKg==", - "dependencies": { - "@babel/types": "^7.27.3" - }, + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.7.tgz", + "integrity": "sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==", "bin": { "parser": "bin/babel-parser.js" }, @@ -48,22 +65,55 @@ "node": ">=6.0.0" } }, - "node_modules/@babel/types": { - "version": "7.27.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.6.tgz", - "integrity": "sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q==", + "node_modules/@babel/runtime": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.7.tgz", + "integrity": "sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==", "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1" + "regenerator-runtime": "^0.14.0" }, "engines": { "node": ">=6.9.0" } }, + "node_modules/@ctrl/tinycolor": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz", + "integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz", + "integrity": "sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==" + }, + "node_modules/@emotion/unitless": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", + "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==" + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", + "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@esbuild/android-arm": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz", - "integrity": "sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", + "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", "cpu": [ "arm" ], @@ -76,10 +126,154 @@ "node": ">=12" } }, + "node_modules/@esbuild/android-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", + "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", + "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", + "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", + "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", + "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", + "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", + "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", + "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", + "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@esbuild/linux-loong64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.18.tgz", - "integrity": "sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", + "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", "cpu": [ "loong64" ], @@ -92,111 +286,570 @@ "node": ">=12" } }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", + "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", + "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", + "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", + "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", + "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", + "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", + "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", + "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", + "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", + "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", + "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@intlify/core-base": { + "version": "9.13.1", + "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.13.1.tgz", + "integrity": "sha512-+bcQRkJO9pcX8d0gel9ZNfrzU22sZFSA0WVhfXrf5jdJOS24a+Bp8pozuS9sBI9Hk/tGz83pgKfmqcn/Ci7/8w==", + "dependencies": { + "@intlify/message-compiler": "9.13.1", + "@intlify/shared": "9.13.1" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + } + }, + "node_modules/@intlify/message-compiler": { + "version": "9.13.1", + "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.13.1.tgz", + "integrity": "sha512-SKsVa4ajYGBVm7sHMXd5qX70O2XXjm55zdZB3VeMFCvQyvLew/dLvq3MqnaIsTMF1VkkOb9Ttr6tHcMlyPDL9w==", + "dependencies": { + "@intlify/shared": "9.13.1", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + } + }, + "node_modules/@intlify/shared": { + "version": "9.13.1", + "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.13.1.tgz", + "integrity": "sha512-u3b6BKGhE6j/JeRU6C/RL2FgyJfy6LakbtfeVF8fJXURpZZTzfh3e05J0bu0XPw447Q6/WUp3C4ajv4TMS4YsQ==", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + } + }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.0.tgz", + "integrity": "sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.18.0.tgz", + "integrity": "sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.18.0.tgz", + "integrity": "sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.18.0.tgz", + "integrity": "sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.18.0.tgz", + "integrity": "sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.18.0.tgz", + "integrity": "sha512-l3m9ewPgjQSXrUMHg93vt0hYCGnrMOcUpTz6FLtbwljo2HluS4zTXFy2571YQbisTnfTKPZ01u/ukJdQTLGh9A==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.18.0.tgz", + "integrity": "sha512-rJ5D47d8WD7J+7STKdCUAgmQk49xuFrRi9pZkWoRD1UeSMakbcepWXPF8ycChBoAqs1pb2wzvbY6Q33WmN2ftw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.18.0.tgz", + "integrity": "sha512-be6Yx37b24ZwxQ+wOQXXLZqpq4jTckJhtGlWGZs68TgdKXJgw54lUUoFYrg6Zs/kjzAQwEwYbp8JxZVzZLRepQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.18.0.tgz", + "integrity": "sha512-hNVMQK+qrA9Todu9+wqrXOHxFiD5YmdEi3paj6vP02Kx1hjd2LLYR2eaN7DsEshg09+9uzWi2W18MJDlG0cxJA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.18.0.tgz", + "integrity": "sha512-ROCM7i+m1NfdrsmvwSzoxp9HFtmKGHEqu5NNDiZWQtXLA8S5HBCkVvKAxJ8U+CVctHwV2Gb5VUaK7UAkzhDjlg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.18.0.tgz", + "integrity": "sha512-0UyyRHyDN42QL+NbqevXIIUnKA47A+45WyasO+y2bGJ1mhQrfrtXUpTxCOrfxCR4esV3/RLYyucGVPiUsO8xjg==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.18.0.tgz", + "integrity": "sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.18.0.tgz", + "integrity": "sha512-LKaqQL9osY/ir2geuLVvRRs+utWUNilzdE90TpyoX0eNqPzWjRm14oMEE+YLve4k/NAqCdPkGYDaDF5Sw+xBfg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.18.0.tgz", + "integrity": "sha512-7J6TkZQFGo9qBKH0pk2cEVSRhJbL6MtfWxth7Y5YmZs57Pi+4x6c2dStAUvaQkHQLnEQv1jzBUW43GvZW8OFqA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.18.0.tgz", + "integrity": "sha512-Txjh+IxBPbkUB9+SXZMpv+b/vnTEtFyfWZgJ6iyCmt2tdx0OF5WhFowLmnh8ENGNpfUlUZkdI//4IEmhwPieNg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.18.0.tgz", + "integrity": "sha512-UOo5FdvOL0+eIVTgS4tIdbW+TtnBLWg1YBCcU2KWM7nuNwRz9bksDX1bekJJCpu25N1DVWaCwnT39dVQxzqS8g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@simonwep/pickr": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@simonwep/pickr/-/pickr-1.8.2.tgz", + "integrity": "sha512-/l5w8BIkrpP6n1xsetx9MWPWlU6OblN5YgZZphxan0Tq4BByTCETL6lyIeY8lagalS2Nbt4F2W034KHLIiunKA==", + "dependencies": { + "core-js": "^3.15.1", + "nanopop": "^2.1.0" + } + }, + "node_modules/@tsconfig/node20": { + "version": "20.1.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node20/-/node20-20.1.4.tgz", + "integrity": "sha512-sqgsT69YFeLWf5NtJ4Xq/xAF8p4ZQHlmGW74Nu2tD4+g5fAsposc4ZfaaPixVu4y01BEiDCWLRDCvDM5JOsRxg==", + "dev": true + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.14.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.2.tgz", + "integrity": "sha512-xyu6WAMVwv6AKFLB+e/7ySZVr/0zLCzOa7rSpq6jNwpqOrUbcACDWC+53d4n2QHOnDou0fbIsg8wZu/sxrnI4Q==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } }, "node_modules/@vitejs/plugin-vue": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-3.2.0.tgz", - "integrity": "sha512-E0tnaL4fr+qkdCNxJ+Xd0yM31UwMkQje76fsDVBBUCoGOUPexu2VDUYHL8P4CwV+zMvWw6nlRw19OnRKmYAJpw==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.0.5.tgz", + "integrity": "sha512-LOjm7XeIimLBZyzinBQ6OSm3UBCNVCpLkxGC0oWmm2YPzVZoxMsdvNVimLTBzpAnR9hl/yn1SHGuRfe6/Td9rQ==", "dev": true, "engines": { - "node": "^14.18.0 || >=16.0.0" + "node": "^18.0.0 || >=20.0.0" }, "peerDependencies": { - "vite": "^3.0.0", + "vite": "^5.0.0", "vue": "^3.2.25" } }, "node_modules/@volar/language-core": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-1.11.1.tgz", - "integrity": "sha512-dOcNn3i9GgZAcJt43wuaEykSluAuOkQgzni1cuxLxTV0nJKanQztp7FxyswdRILaKH+P2XZMPRp2S4MV/pElCw==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.3.0.tgz", + "integrity": "sha512-pvhL24WUh3VDnv7Yw5N1sjhPtdx7q9g+Wl3tggmnkMcyK8GcCNElF2zHiKznryn0DiUGk+eez/p2qQhz+puuHw==", "dev": true, "dependencies": { - "@volar/source-map": "1.11.1" + "@volar/source-map": "2.3.0" } }, "node_modules/@volar/source-map": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-1.11.1.tgz", - "integrity": "sha512-hJnOnwZ4+WT5iupLRnuzbULZ42L7BWWPMmruzwtLhJfpDVoZLjNBxHDi2sY2bgZXCKlpU5XcsMFoYrsQmPhfZg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.3.0.tgz", + "integrity": "sha512-G/228aZjAOGhDjhlyZ++nDbKrS9uk+5DMaEstjvzglaAw7nqtDyhnQAsYzUg6BMP9BtwZ59RIw5HGePrutn00Q==", "dev": true, "dependencies": { - "muggle-string": "^0.3.1" + "muggle-string": "^0.4.0" } }, "node_modules/@volar/typescript": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-1.11.1.tgz", - "integrity": "sha512-iU+t2mas/4lYierSnoFOeRFQUhAEMgsFuQxoxvwn5EdQopw43j+J27a4lt9LMInx1gLJBC6qL14WYGlgymaSMQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.3.0.tgz", + "integrity": "sha512-PtUwMM87WsKVeLJN33GSTUjBexlKfKgouWlOUIv7pjrOnTwhXHZNSmpc312xgXdTjQPpToK6KXSIcKu9sBQ5LQ==", "dev": true, "dependencies": { - "@volar/language-core": "1.11.1", - "path-browserify": "^1.0.1" + "@volar/language-core": "2.3.0", + "path-browserify": "^1.0.1", + "vscode-uri": "^3.0.8" } }, "node_modules/@vue/compiler-core": { - "version": "3.5.16", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.16.tgz", - "integrity": "sha512-AOQS2eaQOaaZQoL1u+2rCJIKDruNXVBZSiUD3chnUrsoX5ZTQMaCvXlWNIfxBJuU15r1o7+mpo5223KVtIhAgQ==", + "version": "3.4.27", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.27.tgz", + "integrity": "sha512-E+RyqY24KnyDXsCuQrI+mlcdW3ALND6U7Gqa/+bVwbcpcR3BRRIckFoz7Qyd4TTlnugtwuI7YgjbvsLmxb+yvg==", "dependencies": { - "@babel/parser": "^7.27.2", - "@vue/shared": "3.5.16", + "@babel/parser": "^7.24.4", + "@vue/shared": "3.4.27", "entities": "^4.5.0", "estree-walker": "^2.0.2", - "source-map-js": "^1.2.1" + "source-map-js": "^1.2.0" } }, "node_modules/@vue/compiler-dom": { - "version": "3.5.16", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.16.tgz", - "integrity": "sha512-SSJIhBr/teipXiXjmWOVWLnxjNGo65Oj/8wTEQz0nqwQeP75jWZ0n4sF24Zxoht1cuJoWopwj0J0exYwCJ0dCQ==", + "version": "3.4.27", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.27.tgz", + "integrity": "sha512-kUTvochG/oVgE1w5ViSr3KUBh9X7CWirebA3bezTbB5ZKBQZwR2Mwj9uoSKRMFcz4gSMzzLXBPD6KpCLb9nvWw==", "dependencies": { - "@vue/compiler-core": "3.5.16", - "@vue/shared": "3.5.16" + "@vue/compiler-core": "3.4.27", + "@vue/shared": "3.4.27" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.5.16", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.16.tgz", - "integrity": "sha512-rQR6VSFNpiinDy/DVUE0vHoIDUF++6p910cgcZoaAUm3POxgNOOdS/xgoll3rNdKYTYPnnbARDCZOyZ+QSe6Pw==", + "version": "3.4.27", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.27.tgz", + "integrity": "sha512-nDwntUEADssW8e0rrmE0+OrONwmRlegDA1pD6QhVeXxjIytV03yDqTey9SBDiALsvAd5U4ZrEKbMyVXhX6mCGA==", "dependencies": { - "@babel/parser": "^7.27.2", - "@vue/compiler-core": "3.5.16", - "@vue/compiler-dom": "3.5.16", - "@vue/compiler-ssr": "3.5.16", - "@vue/shared": "3.5.16", + "@babel/parser": "^7.24.4", + "@vue/compiler-core": "3.4.27", + "@vue/compiler-dom": "3.4.27", + "@vue/compiler-ssr": "3.4.27", + "@vue/shared": "3.4.27", "estree-walker": "^2.0.2", - "magic-string": "^0.30.17", - "postcss": "^8.5.3", - "source-map-js": "^1.2.1" + "magic-string": "^0.30.10", + "postcss": "^8.4.38", + "source-map-js": "^1.2.0" } }, "node_modules/@vue/compiler-ssr": { - "version": "3.5.16", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.16.tgz", - "integrity": "sha512-d2V7kfxbdsjrDSGlJE7my1ZzCXViEcqN6w14DOsDrUCHEA6vbnVCpRFfrc4ryCP/lCKzX2eS1YtnLE/BuC9f/A==", + "version": "3.4.27", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.27.tgz", + "integrity": "sha512-CVRzSJIltzMG5FcidsW0jKNQnNRYC8bT21VegyMMtHmhW3UOI7knmUehzswXLrExDLE6lQCZdrhD4ogI7c+vuw==", "dependencies": { - "@vue/compiler-dom": "3.5.16", - "@vue/shared": "3.5.16" + "@vue/compiler-dom": "3.4.27", + "@vue/shared": "3.4.27" } }, + "node_modules/@vue/devtools-api": { + "version": "6.6.3", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.3.tgz", + "integrity": "sha512-0MiMsFma/HqA6g3KLKn+AGpL1kgKhFWszC9U29NfpWK5LE7bjeXxySWJrOJ77hBz+TBrBQ7o4QJqbPbqbs8rJw==" + }, "node_modules/@vue/language-core": { - "version": "1.8.27", - "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-1.8.27.tgz", - "integrity": "sha512-L8Kc27VdQserNaCUNiSFdDl9LWT24ly8Hpwf1ECy3aFb9m6bDhBGQYOujDm21N7EW3moKIOKEanQwe1q5BK+mA==", + "version": "2.0.21", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.0.21.tgz", + "integrity": "sha512-vjs6KwnCK++kIXT+eI63BGpJHfHNVJcUCr3RnvJsccT3vbJnZV5IhHR2puEkoOkIbDdp0Gqi1wEnv3hEd3WsxQ==", "dev": true, "dependencies": { - "@volar/language-core": "~1.11.1", - "@volar/source-map": "~1.11.1", - "@vue/compiler-dom": "^3.3.0", - "@vue/shared": "^3.3.0", + "@volar/language-core": "~2.3.0-alpha.15", + "@vue/compiler-dom": "^3.4.0", + "@vue/shared": "^3.4.0", "computeds": "^0.0.1", "minimatch": "^9.0.3", - "muggle-string": "^0.3.1", "path-browserify": "^1.0.1", "vue-template-compiler": "^2.7.14" }, @@ -210,49 +863,115 @@ } }, "node_modules/@vue/reactivity": { - "version": "3.5.16", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.16.tgz", - "integrity": "sha512-FG5Q5ee/kxhIm1p2bykPpPwqiUBV3kFySsHEQha5BJvjXdZTUfmya7wP7zC39dFuZAcf/PD5S4Lni55vGLMhvA==", + "version": "3.4.27", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.27.tgz", + "integrity": "sha512-kK0g4NknW6JX2yySLpsm2jlunZJl2/RJGZ0H9ddHdfBVHcNzxmQ0sS0b09ipmBoQpY8JM2KmUw+a6sO8Zo+zIA==", "dependencies": { - "@vue/shared": "3.5.16" + "@vue/shared": "3.4.27" } }, "node_modules/@vue/runtime-core": { - "version": "3.5.16", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.16.tgz", - "integrity": "sha512-bw5Ykq6+JFHYxrQa7Tjr+VSzw7Dj4ldR/udyBZbq73fCdJmyy5MPIFR9IX/M5Qs+TtTjuyUTCnmK3lWWwpAcFQ==", + "version": "3.4.27", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.27.tgz", + "integrity": "sha512-7aYA9GEbOOdviqVvcuweTLe5Za4qBZkUY7SvET6vE8kyypxVgaT1ixHLg4urtOlrApdgcdgHoTZCUuTGap/5WA==", "dependencies": { - "@vue/reactivity": "3.5.16", - "@vue/shared": "3.5.16" + "@vue/reactivity": "3.4.27", + "@vue/shared": "3.4.27" } }, "node_modules/@vue/runtime-dom": { - "version": "3.5.16", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.16.tgz", - "integrity": "sha512-T1qqYJsG2xMGhImRUV9y/RseB9d0eCYZQ4CWca9ztCuiPj/XWNNN+lkNBuzVbia5z4/cgxdL28NoQCvC0Xcfww==", + "version": "3.4.27", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.27.tgz", + "integrity": "sha512-ScOmP70/3NPM+TW9hvVAz6VWWtZJqkbdf7w6ySsws+EsqtHvkhxaWLecrTorFxsawelM5Ys9FnDEMt6BPBDS0Q==", "dependencies": { - "@vue/reactivity": "3.5.16", - "@vue/runtime-core": "3.5.16", - "@vue/shared": "3.5.16", + "@vue/runtime-core": "3.4.27", + "@vue/shared": "3.4.27", "csstype": "^3.1.3" } }, "node_modules/@vue/server-renderer": { - "version": "3.5.16", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.16.tgz", - "integrity": "sha512-BrX0qLiv/WugguGsnQUJiYOE0Fe5mZTwi6b7X/ybGB0vfrPH9z0gD/Y6WOR1sGCgX4gc25L1RYS5eYQKDMoNIg==", + "version": "3.4.27", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.27.tgz", + "integrity": "sha512-dlAMEuvmeA3rJsOMJ2J1kXU7o7pOxgsNHVr9K8hB3ImIkSuBrIdy0vF66h8gf8Tuinf1TK3mPAz2+2sqyf3KzA==", "dependencies": { - "@vue/compiler-ssr": "3.5.16", - "@vue/shared": "3.5.16" + "@vue/compiler-ssr": "3.4.27", + "@vue/shared": "3.4.27" }, "peerDependencies": { - "vue": "3.5.16" + "vue": "3.4.27" } }, "node_modules/@vue/shared": { - "version": "3.5.16", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.16.tgz", - "integrity": "sha512-c/0fWy3Jw6Z8L9FmTyYfkpM5zklnqqa9+a6dz3DvONRKW2NEbh46BP0FHuLFSWi2TnQEtp91Z6zOWNrU6QiyPg==" + "version": "3.4.27", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.27.tgz", + "integrity": "sha512-DL3NmY2OFlqmYYrzp39yi3LDkKxa5vZVwxWdQ3rG0ekuWscHraeIbnI8t+aZK7qhYqEqWKTUdijadunb9pnrgA==" + }, + "node_modules/@vue/tsconfig": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@vue/tsconfig/-/tsconfig-0.5.1.tgz", + "integrity": "sha512-VcZK7MvpjuTPx2w6blwnwZAu5/LgBUtejFOi3pPGQFXQN5Ela03FUtd2Qtg4yWGGissVL0dr6Ro1LfOFh+PCuQ==", + "dev": true + }, + "node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ant-design-vue": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/ant-design-vue/-/ant-design-vue-4.2.3.tgz", + "integrity": "sha512-kqGyWvZtFlSInFP93Ow6wS8LzEsxxUgpI+ZY5jQQkuX8WAcqdwXCA7IcHMpECW6JB89DZMo2Bw85jUg2SjlgQA==", + "dependencies": { + "@ant-design/colors": "^6.0.0", + "@ant-design/icons-vue": "^7.0.0", + "@babel/runtime": "^7.10.5", + "@ctrl/tinycolor": "^3.5.0", + "@emotion/hash": "^0.9.0", + "@emotion/unitless": "^0.8.0", + "@simonwep/pickr": "~1.8.0", + "array-tree-filter": "^2.1.0", + "async-validator": "^4.0.0", + "csstype": "^3.1.1", + "dayjs": "^1.10.5", + "dom-align": "^1.12.1", + "dom-scroll-into-view": "^2.0.0", + "lodash": "^4.17.21", + "lodash-es": "^4.17.15", + "resize-observer-polyfill": "^1.5.1", + "scroll-into-view-if-needed": "^2.2.25", + "shallow-equal": "^1.0.0", + "stylis": "^4.1.3", + "throttle-debounce": "^5.0.0", + "vue-types": "^3.0.0", + "warning": "^4.0.0" + }, + "engines": { + "node": ">=12.22.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ant-design-vue" + }, + "peerDependencies": { + "vue": ">=3.2.0" + } + }, + "node_modules/array-tree-filter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-tree-filter/-/array-tree-filter-2.1.0.tgz", + "integrity": "sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw==" + }, + "node_modules/async-validator": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz", + "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==" }, "node_modules/balanced-match": { "version": "1.0.2", @@ -269,23 +988,79 @@ "balanced-match": "^1.0.0" } }, + "node_modules/compute-scroll-into-view": { + "version": "1.0.20", + "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz", + "integrity": "sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==" + }, "node_modules/computeds": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/computeds/-/computeds-0.0.1.tgz", "integrity": "sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==", "dev": true }, + "node_modules/copy-anything": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", + "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", + "dev": true, + "dependencies": { + "is-what": "^3.14.1" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/core-js": { + "version": "3.37.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.37.1.tgz", + "integrity": "sha512-Xn6qmxrQZyB0FFY8E3bgRXei3lWDJHhvI+u0q9TKIYM49G8pAr0FgnnrFRAmsbptZL1yxRADVXn+x5AGsbBfyw==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, + "node_modules/dayjs": { + "version": "1.11.11", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.11.tgz", + "integrity": "sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg==" + }, "node_modules/de-indent": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", "dev": true }, + "node_modules/dom-align": { + "version": "1.12.4", + "resolved": "https://registry.npmjs.org/dom-align/-/dom-align-1.12.4.tgz", + "integrity": "sha512-R8LUSEay/68zE5c8/3BDxiTEvgb4xZTF0RKmAHfiEVN3klfIpXfi2/QCoiWPccVQ0J/ZGdz9OjzL4uJEP/MRAw==" + }, + "node_modules/dom-scroll-into-view": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/dom-scroll-into-view/-/dom-scroll-into-view-2.0.1.tgz", + "integrity": "sha512-bvVTQe1lfaUr1oFzZX80ce9KLDlZ3iU+XGNE/bz9HnGdklTieqsbmsLHe+rT2XWqopvL0PckkYqN7ksmm5pe3w==" + }, "node_modules/entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", @@ -297,10 +1072,23 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "dev": true, + "optional": true, + "dependencies": { + "prr": "~1.0.1" + }, + "bin": { + "errno": "cli.js" + } + }, "node_modules/esbuild": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.18.tgz", - "integrity": "sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", + "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", "dev": true, "hasInstallScript": true, "bin": { @@ -310,348 +1098,29 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/android-arm": "0.15.18", - "@esbuild/linux-loong64": "0.15.18", - "esbuild-android-64": "0.15.18", - "esbuild-android-arm64": "0.15.18", - "esbuild-darwin-64": "0.15.18", - "esbuild-darwin-arm64": "0.15.18", - "esbuild-freebsd-64": "0.15.18", - "esbuild-freebsd-arm64": "0.15.18", - "esbuild-linux-32": "0.15.18", - "esbuild-linux-64": "0.15.18", - "esbuild-linux-arm": "0.15.18", - "esbuild-linux-arm64": "0.15.18", - "esbuild-linux-mips64le": "0.15.18", - "esbuild-linux-ppc64le": "0.15.18", - "esbuild-linux-riscv64": "0.15.18", - "esbuild-linux-s390x": "0.15.18", - "esbuild-netbsd-64": "0.15.18", - "esbuild-openbsd-64": "0.15.18", - "esbuild-sunos-64": "0.15.18", - "esbuild-windows-32": "0.15.18", - "esbuild-windows-64": "0.15.18", - "esbuild-windows-arm64": "0.15.18" - } - }, - "node_modules/esbuild-android-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.18.tgz", - "integrity": "sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-android-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.18.tgz", - "integrity": "sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-darwin-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.18.tgz", - "integrity": "sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-darwin-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz", - "integrity": "sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-freebsd-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.18.tgz", - "integrity": "sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-freebsd-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.18.tgz", - "integrity": "sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-32": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.18.tgz", - "integrity": "sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.18.tgz", - "integrity": "sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-arm": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.18.tgz", - "integrity": "sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.18.tgz", - "integrity": "sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-mips64le": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.18.tgz", - "integrity": "sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-ppc64le": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.18.tgz", - "integrity": "sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-riscv64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.18.tgz", - "integrity": "sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-s390x": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.18.tgz", - "integrity": "sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-netbsd-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.18.tgz", - "integrity": "sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-openbsd-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.18.tgz", - "integrity": "sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-sunos-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.18.tgz", - "integrity": "sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-32": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.18.tgz", - "integrity": "sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.18.tgz", - "integrity": "sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.18.tgz", - "integrity": "sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" + "@esbuild/aix-ppc64": "0.20.2", + "@esbuild/android-arm": "0.20.2", + "@esbuild/android-arm64": "0.20.2", + "@esbuild/android-x64": "0.20.2", + "@esbuild/darwin-arm64": "0.20.2", + "@esbuild/darwin-x64": "0.20.2", + "@esbuild/freebsd-arm64": "0.20.2", + "@esbuild/freebsd-x64": "0.20.2", + "@esbuild/linux-arm": "0.20.2", + "@esbuild/linux-arm64": "0.20.2", + "@esbuild/linux-ia32": "0.20.2", + "@esbuild/linux-loong64": "0.20.2", + "@esbuild/linux-mips64el": "0.20.2", + "@esbuild/linux-ppc64": "0.20.2", + "@esbuild/linux-riscv64": "0.20.2", + "@esbuild/linux-s390x": "0.20.2", + "@esbuild/linux-x64": "0.20.2", + "@esbuild/netbsd-x64": "0.20.2", + "@esbuild/openbsd-x64": "0.20.2", + "@esbuild/sunos-x64": "0.20.2", + "@esbuild/win32-arm64": "0.20.2", + "@esbuild/win32-ia32": "0.20.2", + "@esbuild/win32-x64": "0.20.2" } }, "node_modules/estree-walker": { @@ -673,26 +1142,12 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } + "optional": true }, "node_modules/he": { "version": "1.2.0", @@ -703,33 +1158,197 @@ "he": "bin/he" } }, - "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, + "optional": true, "dependencies": { - "hasown": "^2.0.2" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=0.10.0" + } + }, + "node_modules/image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", + "dev": true, + "optional": true, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-plain-object": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.1.tgz", + "integrity": "sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-what": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", + "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/json-parse-even-better-errors": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.2.tgz", + "integrity": "sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/less": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/less/-/less-4.3.0.tgz", + "integrity": "sha512-X9RyH9fvemArzfdP8Pi3irr7lor2Ok4rOttDXBhlwDg+wKQsXOXgHWduAJE1EsF7JJx0w0bcO6BC6tCKKYnXKA==", + "dev": true, + "dependencies": { + "copy-anything": "^2.0.1", + "parse-node-version": "^1.0.1", + "tslib": "^2.3.0" + }, + "bin": { + "lessc": "bin/lessc" + }, + "engines": { + "node": ">=14" + }, + "optionalDependencies": { + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "make-dir": "^2.1.0", + "mime": "^1.4.1", + "needle": "^3.1.0", + "source-map": "~0.6.0" + } + }, + "node_modules/less-loader": { + "version": "12.2.0", + "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-12.2.0.tgz", + "integrity": "sha512-MYUxjSQSBUQmowc0l5nPieOYwMzGPUaTzB6inNW/bdPEG9zOL3eAAD1Qw5ZxSPk7we5dMojHwNODYMV1hq4EVg==", + "dev": true, + "engines": { + "node": ">= 18.12.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "less": "^3.5.0 || ^4.0.0", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" } }, "node_modules/magic-string": { - "version": "0.30.17", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", - "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "version": "0.30.10", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", + "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0" + "@jridgewell/sourcemap-codec": "^1.4.15" + } + }, + "node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "optional": true, + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "optional": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", + "dev": true, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "optional": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" } }, "node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" @@ -742,15 +1361,15 @@ } }, "node_modules/muggle-string": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.3.1.tgz", - "integrity": "sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", + "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", "dev": true }, "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "funding": [ { "type": "github", @@ -764,27 +1383,175 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/nanopop": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/nanopop/-/nanopop-2.4.2.tgz", + "integrity": "sha512-NzOgmMQ+elxxHeIha+OG/Pv3Oc3p4RU2aBhwWwAqDpXrdTbtRylbRLQztLy8dMMwfl6pclznBdfUhccEn9ZIzw==" + }, + "node_modules/needle": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.3.1.tgz", + "integrity": "sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==", + "dev": true, + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.3", + "sax": "^1.2.4" + }, + "bin": { + "needle": "bin/needle" + }, + "engines": { + "node": ">= 4.4.x" + } + }, + "node_modules/npm-normalize-package-bin": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", + "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-run-all2": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/npm-run-all2/-/npm-run-all2-6.2.0.tgz", + "integrity": "sha512-wA7yVIkthe6qJBfiJ2g6aweaaRlw72itsFGF6HuwCHKwtwAx/4BY1vVpk6bw6lS8RLMsexoasOkd0aYOmsFG7Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.2.1", + "cross-spawn": "^7.0.3", + "memorystream": "^0.3.1", + "minimatch": "^9.0.0", + "pidtree": "^0.6.0", + "read-package-json-fast": "^3.0.2", + "shell-quote": "^1.7.3" + }, + "bin": { + "npm-run-all": "bin/npm-run-all/index.js", + "npm-run-all2": "bin/npm-run-all/index.js", + "run-p": "bin/run-p/index.js", + "run-s": "bin/run-s/index.js" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0", + "npm": ">= 8" + } + }, + "node_modules/parse-node-version": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/path-browserify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", "dev": true }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } }, "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==" + }, + "node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true, + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pinia": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/pinia/-/pinia-2.1.7.tgz", + "integrity": "sha512-+C2AHFtcFqjPih0zpYuvof37SFxMQ7OEG2zV9jRI12i9BOy3YQVAHwdKtyyc8pDcDyIc33WCIsZaCFWU7WWxGQ==", + "dependencies": { + "@vue/devtools-api": "^6.5.0", + "vue-demi": ">=0.14.5" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "@vue/composition-api": "^1.4.0", + "typescript": ">=4.4.4", + "vue": "^2.6.14 || ^3.3.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/pinia-plugin-persistedstate": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/pinia-plugin-persistedstate/-/pinia-plugin-persistedstate-3.2.1.tgz", + "integrity": "sha512-MK++8LRUsGF7r45PjBFES82ISnPzyO6IZx3CH5vyPseFLZCk1g2kgx6l/nW8pEBKxxd4do0P6bJw+mUSZIEZUQ==", + "peerDependencies": { + "pinia": "^2.0.0" + } + }, + "node_modules/pinia/node_modules/vue-demi": { + "version": "0.14.8", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.8.tgz", + "integrity": "sha512-Uuqnk9YE9SsWeReYqK2alDI5YzciATE0r2SkA6iMAtuXvNTMNACJLJEXNXaEy94ECuBe4Sk6RzRU80kjdbIo1Q==", + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } }, "node_modules/postcss": { - "version": "8.5.4", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.4.tgz", - "integrity": "sha512-QSa9EBe+uwlGTFmHsPKokv3B/oEMQZxfqW0QqNCyhpa6mB1afzulwn8hihglqAb2pOw+BJgNlmXQ8la2VeHB7w==", + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", "funding": [ { "type": "opencollective", @@ -800,53 +1567,105 @@ } ], "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.2.0" }, "engines": { "node": "^10 || ^12 || >=14" } }, - "node_modules/resolve": { - "version": "1.22.10", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", - "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "node_modules/prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", + "dev": true, + "optional": true + }, + "node_modules/read-package-json-fast": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", + "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", "dev": true, "dependencies": { - "is-core-module": "^2.16.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" + "json-parse-even-better-errors": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, + "node_modules/resize-observer-polyfill": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", + "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==" + }, "node_modules/rollup": { - "version": "2.79.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz", - "integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.18.0.tgz", + "integrity": "sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==", "dev": true, + "dependencies": { + "@types/estree": "1.0.5" + }, "bin": { "rollup": "dist/bin/rollup" }, "engines": { - "node": ">=10.0.0" + "node": ">=18.0.0", + "npm": ">=8.0.0" }, "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.18.0", + "@rollup/rollup-android-arm64": "4.18.0", + "@rollup/rollup-darwin-arm64": "4.18.0", + "@rollup/rollup-darwin-x64": "4.18.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.18.0", + "@rollup/rollup-linux-arm-musleabihf": "4.18.0", + "@rollup/rollup-linux-arm64-gnu": "4.18.0", + "@rollup/rollup-linux-arm64-musl": "4.18.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.18.0", + "@rollup/rollup-linux-riscv64-gnu": "4.18.0", + "@rollup/rollup-linux-s390x-gnu": "4.18.0", + "@rollup/rollup-linux-x64-gnu": "4.18.0", + "@rollup/rollup-linux-x64-musl": "4.18.0", + "@rollup/rollup-win32-arm64-msvc": "4.18.0", + "@rollup/rollup-win32-ia32-msvc": "4.18.0", + "@rollup/rollup-win32-x64-msvc": "4.18.0", "fsevents": "~2.3.2" } }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "optional": true + }, + "node_modules/sax": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", + "dev": true, + "optional": true + }, + "node_modules/scroll-into-view-if-needed": { + "version": "2.2.31", + "resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.31.tgz", + "integrity": "sha512-dGCXy99wZQivjmjIqihaBQNjryrz5rueJY7eHfTdyWEiR4ttYpsajb14rn9s5d4DY4EcY6+4+U/maARBXJedkA==", + "dependencies": { + "compute-scroll-into-view": "^1.0.20" + } + }, "node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -855,62 +1674,123 @@ "node": ">=10" } }, - "node_modules/source-map-js": { + "node_modules/shallow-equal": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "resolved": "https://registry.npmjs.org/shallow-equal/-/shallow-equal-1.2.1.tgz", + "integrity": "sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA==" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, "engines": { - "node": ">= 0.4" - }, + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stylis": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.2.tgz", + "integrity": "sha512-bhtUjWd/z6ltJiQwg0dUfxEJ+W+jdqQd8TbWLWyeIJHlnsqmGLRFFd8e5mA0AZi/zx90smXRlN66YMTcaSFifg==" + }, + "node_modules/throttle-debounce": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-5.0.0.tgz", + "integrity": "sha512-2iQTSgkkc1Zyk0MeVrt/3BvuOXYPl/R8Z0U2xxo9rjwNciaHDG3R+Lm6dh4EeUci49DanvBnuqI6jshoQQRGEg==", + "engines": { + "node": ">=12.22" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true + }, "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", "devOptional": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=14.17" } }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, "node_modules/vite": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.11.tgz", - "integrity": "sha512-K/jGKL/PgbIgKCiJo5QbASQhFiV02X9Jh+Qq0AKCRCRKZtOTVi4t6wh75FDpGf2N9rYOnzH87OEFQNaFy6pdxQ==", + "version": "5.2.13", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.13.tgz", + "integrity": "sha512-SSq1noJfY9pR3I1TUENL3rQYDQCFqgD+lM6fTRAM8Nv6Lsg5hDLaXkjETVeBt+7vZBCMoibD+6IWnT2mJ+Zb/A==", "dev": true, "dependencies": { - "esbuild": "^0.15.9", - "postcss": "^8.4.18", - "resolve": "^1.22.1", - "rollup": "^2.79.1" + "esbuild": "^0.20.1", + "postcss": "^8.4.38", + "rollup": "^4.13.0" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^14.18.0 || >=16.0.0" + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" }, "optionalDependencies": { - "fsevents": "~2.3.2" + "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": ">= 14", + "@types/node": "^18.0.0 || >=20.0.0", "less": "*", + "lightningcss": "^1.21.0", "sass": "*", "stylus": "*", "sugarss": "*", @@ -923,6 +1803,9 @@ "less": { "optional": true }, + "lightningcss": { + "optional": true + }, "sass": { "optional": true }, @@ -937,16 +1820,22 @@ } } }, + "node_modules/vscode-uri": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz", + "integrity": "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==", + "dev": true + }, "node_modules/vue": { - "version": "3.5.16", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.16.tgz", - "integrity": "sha512-rjOV2ecxMd5SiAmof2xzh2WxntRcigkX/He4YFJ6WdRvVUrbt6DxC1Iujh10XLl8xCDRDtGKMeO3D+pRQ1PP9w==", + "version": "3.4.27", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.4.27.tgz", + "integrity": "sha512-8s/56uK6r01r1icG/aEOHqyMVxd1bkYcSe9j8HcKtr/xTOFWvnzIVTehNW+5Yt89f+DLBe4A569pnZLS5HzAMA==", "dependencies": { - "@vue/compiler-dom": "3.5.16", - "@vue/compiler-sfc": "3.5.16", - "@vue/runtime-dom": "3.5.16", - "@vue/server-renderer": "3.5.16", - "@vue/shared": "3.5.16" + "@vue/compiler-dom": "3.4.27", + "@vue/compiler-sfc": "3.4.27", + "@vue/runtime-dom": "3.4.27", + "@vue/server-renderer": "3.4.27", + "@vue/shared": "3.4.27" }, "peerDependencies": { "typescript": "*" @@ -957,6 +1846,39 @@ } } }, + "node_modules/vue-i18n": { + "version": "9.13.1", + "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.13.1.tgz", + "integrity": "sha512-mh0GIxx0wPtPlcB1q4k277y0iKgo25xmDPWioVVYanjPufDBpvu5ySTjP5wOrSvlYQ2m1xI+CFhGdauv/61uQg==", + "dependencies": { + "@intlify/core-base": "9.13.1", + "@intlify/shared": "9.13.1", + "@vue/devtools-api": "^6.5.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + }, + "peerDependencies": { + "vue": "^3.0.0" + } + }, + "node_modules/vue-router": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.3.3.tgz", + "integrity": "sha512-8Q+u+WP4N2SXY38FDcF2H1dUEbYVHVPtPCPZj/GTZx8RCbiB8AtJP9+YIxn4Vs0svMTNQcLIzka4GH7Utkx9xQ==", + "dependencies": { + "@vue/devtools-api": "^6.5.1" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "vue": "^3.2.0" + } + }, "node_modules/vue-template-compiler": { "version": "2.7.16", "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.16.tgz", @@ -968,13 +1890,13 @@ } }, "node_modules/vue-tsc": { - "version": "1.8.27", - "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-1.8.27.tgz", - "integrity": "sha512-WesKCAZCRAbmmhuGl3+VrdWItEvfoFIPXOvUJkjULi+x+6G/Dy69yO3TBRJDr9eUlmsNAwVmxsNZxvHKzbkKdg==", + "version": "2.0.21", + "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-2.0.21.tgz", + "integrity": "sha512-E6x1p1HaHES6Doy8pqtm7kQern79zRtIewkf9fiv7Y43Zo4AFDS5hKi+iHi2RwEhqRmuiwliB1LCEFEGwvxQnw==", "dev": true, "dependencies": { - "@volar/typescript": "~1.11.1", - "@vue/language-core": "1.8.27", + "@volar/typescript": "~2.3.0-alpha.15", + "@vue/language-core": "2.0.21", "semver": "^7.5.4" }, "bin": { @@ -983,6 +1905,43 @@ "peerDependencies": { "typescript": "*" } + }, + "node_modules/vue-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/vue-types/-/vue-types-3.0.2.tgz", + "integrity": "sha512-IwUC0Aq2zwaXqy74h4WCvFCUtoV0iSWr0snWnE9TnU18S66GAQyqQbRf2qfJtUuiFsBf6qp0MEwdonlwznlcrw==", + "dependencies": { + "is-plain-object": "3.0.1" + }, + "engines": { + "node": ">=10.15.0" + }, + "peerDependencies": { + "vue": "^3.0.0" + } + }, + "node_modules/warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } } } } diff --git a/frontend/package.json b/frontend/package.json index e65d0ef..4a162c9 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,21 +1,34 @@ { - "name": "frontend", - "private": true, + "name": "js", "version": "0.0.0", + "private": true, "type": "module", "scripts": { - "dev": "vite", - "build": "vue-tsc --noEmit && vite build", - "preview": "vite preview" + "dev": "vite --port 7777", + "build": "run-p type-check \"build-only {@}\" --", + "preview": "vite preview", + "build-only": "vite build", + "type-check": "vue-tsc --build --force" }, "dependencies": { - "vue": "^3.2.37" + "@ant-design/icons-vue": "^7.0.1", + "ant-design-vue": "^4.2.3", + "pinia": "^2.1.7", + "pinia-plugin-persistedstate": "^3.2.1", + "vue": "^3.4.21", + "vue-i18n": "^9.13.1", + "vue-router": "^4.3.0" }, "devDependencies": { - "@vitejs/plugin-vue": "^3.0.3", - "typescript": "^4.6.4", - "vite": "^3.0.7", - "vue-tsc": "^1.8.27", - "@babel/types": "^7.18.10" + "@tsconfig/node20": "^20.1.4", + "@types/node": "^20.12.5", + "@vitejs/plugin-vue": "^5.0.4", + "@vue/tsconfig": "^0.5.1", + "less": "^4.3.0", + "less-loader": "^12.2.0", + "npm-run-all2": "^6.1.2", + "typescript": "~5.4.0", + "vite": "^5.2.8", + "vue-tsc": "^2.0.11" } } diff --git a/frontend/package.json.md5 b/frontend/package.json.md5 index 706e5db..e8f60bf 100755 --- a/frontend/package.json.md5 +++ b/frontend/package.json.md5 @@ -1 +1 @@ -bb7ffb87329c9ad4990374471d4ce9a4 \ No newline at end of file +5b1aa7f7c882c7e08d0d390c73602d71 \ No newline at end of file diff --git a/frontend/public/favicon.ico b/frontend/public/favicon.ico new file mode 100644 index 0000000..d2c771e Binary files /dev/null and b/frontend/public/favicon.ico differ diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 86cde97..4e65980 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -1,22 +1,83 @@ - - + diff --git a/frontend/src/assets/base.css b/frontend/src/assets/base.css new file mode 100644 index 0000000..dfa90a4 --- /dev/null +++ b/frontend/src/assets/base.css @@ -0,0 +1,36 @@ +/* color palette from */ + + +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; +} + +body { + min-height: 100vh; + color: var(--color-text); + background: var(--color-background); + transition: + color 0.5s, + background-color 0.5s; + line-height: 1.6; + font-family: + Inter, + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + Roboto, + Oxygen, + Ubuntu, + Cantarell, + 'Fira Sans', + 'Droid Sans', + 'Helvetica Neue', + sans-serif; + font-size: 15px; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} diff --git a/frontend/src/assets/fonts/OFL.txt b/frontend/src/assets/fonts/OFL.txt deleted file mode 100644 index 9cac04c..0000000 --- a/frontend/src/assets/fonts/OFL.txt +++ /dev/null @@ -1,93 +0,0 @@ -Copyright 2016 The Nunito Project Authors (contact@sansoxygen.com), - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 b/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 deleted file mode 100644 index 2f9cc59..0000000 Binary files a/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 and /dev/null differ diff --git a/frontend/src/assets/g69.png b/frontend/src/assets/g69.png new file mode 100644 index 0000000..00578f7 Binary files /dev/null and b/frontend/src/assets/g69.png differ diff --git a/frontend/src/assets/images/logo-universal.png b/frontend/src/assets/images/logo-universal.png deleted file mode 100644 index d63303b..0000000 Binary files a/frontend/src/assets/images/logo-universal.png and /dev/null differ diff --git a/frontend/src/assets/logo-200x200.png b/frontend/src/assets/logo-200x200.png new file mode 100644 index 0000000..f0e47b7 Binary files /dev/null and b/frontend/src/assets/logo-200x200.png differ diff --git a/frontend/src/assets/main.css b/frontend/src/assets/main.css new file mode 100644 index 0000000..f0f4472 --- /dev/null +++ b/frontend/src/assets/main.css @@ -0,0 +1,47 @@ +@import './base.css'; + + +#nav.ant-menu-horizontal>.ant-menu-item:after,#nav.ant-menu-horizontal { + bottom: auto; +} + +.root-view { + padding: 8px; +} + +.form-input-number { + width: 50%; + min-width: 80px; +} + +.disabled-router-link { + pointer-events: none; +} + +.main-view { + padding-right: 8px; + padding-left: 8px; + max-height: calc(100vh - 70px); + overflow: auto; + margin: auto; +} + +.bw-list-panel-content { + min-width: 600px; + max-width: 60%; + margin: auto; +} + +.disabled-div { + pointer-events: none; + opacity: 0.4; +} + +.middle-of-screen { + margin: 0; + position: absolute; + top: 50%; + left: 50%; + -ms-transform: translate(-50%, -50%); + transform: translate(-50%, -50%); +} \ No newline at end of file diff --git a/frontend/src/components/HelloWorld.vue b/frontend/src/components/HelloWorld.vue deleted file mode 100644 index 3ab3df7..0000000 --- a/frontend/src/components/HelloWorld.vue +++ /dev/null @@ -1,71 +0,0 @@ - - - - - diff --git a/frontend/src/components/Logo.vue b/frontend/src/components/Logo.vue new file mode 100644 index 0000000..2c5cde6 --- /dev/null +++ b/frontend/src/components/Logo.vue @@ -0,0 +1,35 @@ + + + diff --git a/frontend/src/components/NotImplemented.vue b/frontend/src/components/NotImplemented.vue new file mode 100644 index 0000000..87c23e5 --- /dev/null +++ b/frontend/src/components/NotImplemented.vue @@ -0,0 +1,53 @@ + + + diff --git a/frontend/src/components/PageNotFound.vue b/frontend/src/components/PageNotFound.vue new file mode 100644 index 0000000..3789eba --- /dev/null +++ b/frontend/src/components/PageNotFound.vue @@ -0,0 +1,44 @@ + + + diff --git a/frontend/src/components/admin/Dashboard.vue b/frontend/src/components/admin/Dashboard.vue new file mode 100644 index 0000000..441daa2 --- /dev/null +++ b/frontend/src/components/admin/Dashboard.vue @@ -0,0 +1,465 @@ + + + + diff --git a/frontend/src/components/admin/domains/Add.vue b/frontend/src/components/admin/domains/Add.vue new file mode 100644 index 0000000..1ca40f9 --- /dev/null +++ b/frontend/src/components/admin/domains/Add.vue @@ -0,0 +1,120 @@ + + + + diff --git a/frontend/src/components/admin/domains/DKIM.vue b/frontend/src/components/admin/domains/DKIM.vue new file mode 100644 index 0000000..89a8ed4 --- /dev/null +++ b/frontend/src/components/admin/domains/DKIM.vue @@ -0,0 +1,156 @@ + + + + diff --git a/frontend/src/components/admin/domains/IncomingRules.vue b/frontend/src/components/admin/domains/IncomingRules.vue new file mode 100644 index 0000000..0a9ab3a --- /dev/null +++ b/frontend/src/components/admin/domains/IncomingRules.vue @@ -0,0 +1,61 @@ + + + diff --git a/frontend/src/components/admin/domains/MailsPermDeletion.vue b/frontend/src/components/admin/domains/MailsPermDeletion.vue new file mode 100644 index 0000000..2f77cdc --- /dev/null +++ b/frontend/src/components/admin/domains/MailsPermDeletion.vue @@ -0,0 +1,344 @@ + + + + diff --git a/frontend/src/components/admin/domains/Migration.vue b/frontend/src/components/admin/domains/Migration.vue new file mode 100644 index 0000000..0d51772 --- /dev/null +++ b/frontend/src/components/admin/domains/Migration.vue @@ -0,0 +1,151 @@ + + + + diff --git a/frontend/src/components/admin/domains/OutgoingRules.vue b/frontend/src/components/admin/domains/OutgoingRules.vue new file mode 100644 index 0000000..8f554f9 --- /dev/null +++ b/frontend/src/components/admin/domains/OutgoingRules.vue @@ -0,0 +1,68 @@ + + + diff --git a/frontend/src/components/admin/domains/SharedAddressBooks.vue b/frontend/src/components/admin/domains/SharedAddressBooks.vue new file mode 100644 index 0000000..3b2821e --- /dev/null +++ b/frontend/src/components/admin/domains/SharedAddressBooks.vue @@ -0,0 +1,25 @@ + + diff --git a/frontend/src/components/admin/domains/SharedCalendars.vue b/frontend/src/components/admin/domains/SharedCalendars.vue new file mode 100644 index 0000000..d034d52 --- /dev/null +++ b/frontend/src/components/admin/domains/SharedCalendars.vue @@ -0,0 +1,21 @@ + + diff --git a/frontend/src/components/admin/domains/SharedFolders.vue b/frontend/src/components/admin/domains/SharedFolders.vue new file mode 100644 index 0000000..e9101b4 --- /dev/null +++ b/frontend/src/components/admin/domains/SharedFolders.vue @@ -0,0 +1,25 @@ + + diff --git a/frontend/src/components/admin/domains/cidr_access/Policy.vue b/frontend/src/components/admin/domains/cidr_access/Policy.vue new file mode 100644 index 0000000..defacae --- /dev/null +++ b/frontend/src/components/admin/domains/cidr_access/Policy.vue @@ -0,0 +1,471 @@ + + + diff --git a/frontend/src/components/admin/domains/cidr_access/Pools.vue b/frontend/src/components/admin/domains/cidr_access/Pools.vue new file mode 100644 index 0000000..aca6637 --- /dev/null +++ b/frontend/src/components/admin/domains/cidr_access/Pools.vue @@ -0,0 +1,397 @@ + + + diff --git a/frontend/src/components/admin/domains/mailstorage/Export.vue b/frontend/src/components/admin/domains/mailstorage/Export.vue new file mode 100644 index 0000000..858801a --- /dev/null +++ b/frontend/src/components/admin/domains/mailstorage/Export.vue @@ -0,0 +1,158 @@ + + + diff --git a/frontend/src/components/admin/domains/mailstorage/Mailboxes.vue b/frontend/src/components/admin/domains/mailstorage/Mailboxes.vue new file mode 100644 index 0000000..1c2849f --- /dev/null +++ b/frontend/src/components/admin/domains/mailstorage/Mailboxes.vue @@ -0,0 +1,747 @@ + + + diff --git a/frontend/src/components/admin/domains/mailstorage/Settings.vue b/frontend/src/components/admin/domains/mailstorage/Settings.vue new file mode 100644 index 0000000..7f343ac --- /dev/null +++ b/frontend/src/components/admin/domains/mailstorage/Settings.vue @@ -0,0 +1,1071 @@ + + + + diff --git a/frontend/src/components/admin/domains/resources/Categories.vue b/frontend/src/components/admin/domains/resources/Categories.vue new file mode 100644 index 0000000..bf17e3e --- /dev/null +++ b/frontend/src/components/admin/domains/resources/Categories.vue @@ -0,0 +1,328 @@ + + + + diff --git a/frontend/src/components/admin/domains/resources/Offices.vue b/frontend/src/components/admin/domains/resources/Offices.vue new file mode 100644 index 0000000..9266084 --- /dev/null +++ b/frontend/src/components/admin/domains/resources/Offices.vue @@ -0,0 +1,352 @@ + + + + diff --git a/frontend/src/components/admin/domains/resources/Resources.vue b/frontend/src/components/admin/domains/resources/Resources.vue new file mode 100644 index 0000000..3664b35 --- /dev/null +++ b/frontend/src/components/admin/domains/resources/Resources.vue @@ -0,0 +1,608 @@ + + + + diff --git a/frontend/src/components/admin/domains/userdb/Add.vue b/frontend/src/components/admin/domains/userdb/Add.vue new file mode 100644 index 0000000..e795035 --- /dev/null +++ b/frontend/src/components/admin/domains/userdb/Add.vue @@ -0,0 +1,115 @@ + + + + diff --git a/frontend/src/components/admin/domains/userdb/Groups.vue b/frontend/src/components/admin/domains/userdb/Groups.vue new file mode 100644 index 0000000..8583d6f --- /dev/null +++ b/frontend/src/components/admin/domains/userdb/Groups.vue @@ -0,0 +1,434 @@ + + + diff --git a/frontend/src/components/admin/domains/userdb/Redirects.vue b/frontend/src/components/admin/domains/userdb/Redirects.vue new file mode 100644 index 0000000..6dd19e1 --- /dev/null +++ b/frontend/src/components/admin/domains/userdb/Redirects.vue @@ -0,0 +1,245 @@ + + + diff --git a/frontend/src/components/admin/domains/userdb/Settings.vue b/frontend/src/components/admin/domains/userdb/Settings.vue new file mode 100644 index 0000000..a328157 --- /dev/null +++ b/frontend/src/components/admin/domains/userdb/Settings.vue @@ -0,0 +1,812 @@ + + + + diff --git a/frontend/src/components/admin/domains/userdb/Users.vue b/frontend/src/components/admin/domains/userdb/Users.vue new file mode 100644 index 0000000..1573fee --- /dev/null +++ b/frontend/src/components/admin/domains/userdb/Users.vue @@ -0,0 +1,294 @@ + + + diff --git a/frontend/src/components/admin/security/BlockedIPs.vue b/frontend/src/components/admin/security/BlockedIPs.vue new file mode 100644 index 0000000..11238a7 --- /dev/null +++ b/frontend/src/components/admin/security/BlockedIPs.vue @@ -0,0 +1,164 @@ + + + + diff --git a/frontend/src/components/admin/security/black_list/Email.vue b/frontend/src/components/admin/security/black_list/Email.vue new file mode 100644 index 0000000..2f308df --- /dev/null +++ b/frontend/src/components/admin/security/black_list/Email.vue @@ -0,0 +1,215 @@ + + + + diff --git a/frontend/src/components/admin/security/black_list/IP.vue b/frontend/src/components/admin/security/black_list/IP.vue new file mode 100644 index 0000000..d1b91da --- /dev/null +++ b/frontend/src/components/admin/security/black_list/IP.vue @@ -0,0 +1,213 @@ + + + + diff --git a/frontend/src/components/admin/security/white_list/Email.vue b/frontend/src/components/admin/security/white_list/Email.vue new file mode 100644 index 0000000..081181e --- /dev/null +++ b/frontend/src/components/admin/security/white_list/Email.vue @@ -0,0 +1,215 @@ + + + + diff --git a/frontend/src/components/admin/security/white_list/IP.vue b/frontend/src/components/admin/security/white_list/IP.vue new file mode 100644 index 0000000..3acd126 --- /dev/null +++ b/frontend/src/components/admin/security/white_list/IP.vue @@ -0,0 +1,213 @@ + + + + diff --git a/frontend/src/components/admin/settings/AddressRules.vue b/frontend/src/components/admin/settings/AddressRules.vue new file mode 100644 index 0000000..53abca4 --- /dev/null +++ b/frontend/src/components/admin/settings/AddressRules.vue @@ -0,0 +1,50 @@ + + + diff --git a/frontend/src/components/admin/settings/Calendars.vue b/frontend/src/components/admin/settings/Calendars.vue new file mode 100644 index 0000000..5132f4b --- /dev/null +++ b/frontend/src/components/admin/settings/Calendars.vue @@ -0,0 +1,110 @@ + + + + diff --git a/frontend/src/components/admin/settings/License.vue b/frontend/src/components/admin/settings/License.vue new file mode 100644 index 0000000..5f42ca7 --- /dev/null +++ b/frontend/src/components/admin/settings/License.vue @@ -0,0 +1,272 @@ + + + + diff --git a/frontend/src/components/admin/settings/Main.vue b/frontend/src/components/admin/settings/Main.vue new file mode 100644 index 0000000..0c30fa6 --- /dev/null +++ b/frontend/src/components/admin/settings/Main.vue @@ -0,0 +1,1010 @@ + + + diff --git a/frontend/src/components/admin/settings/SettingsDB.vue b/frontend/src/components/admin/settings/SettingsDB.vue new file mode 100644 index 0000000..bd281ec --- /dev/null +++ b/frontend/src/components/admin/settings/SettingsDB.vue @@ -0,0 +1,257 @@ + + + + diff --git a/frontend/src/components/admin/settings/smtp_queue/Manage.vue b/frontend/src/components/admin/settings/smtp_queue/Manage.vue new file mode 100644 index 0000000..7e6ac1d --- /dev/null +++ b/frontend/src/components/admin/settings/smtp_queue/Manage.vue @@ -0,0 +1,388 @@ + + diff --git a/frontend/src/components/admin/settings/smtp_queue/Settings.vue b/frontend/src/components/admin/settings/smtp_queue/Settings.vue new file mode 100644 index 0000000..b4a2451 --- /dev/null +++ b/frontend/src/components/admin/settings/smtp_queue/Settings.vue @@ -0,0 +1,304 @@ + + + + diff --git a/frontend/src/components/common/AddressBooks.vue b/frontend/src/components/common/AddressBooks.vue new file mode 100644 index 0000000..3d72446 --- /dev/null +++ b/frontend/src/components/common/AddressBooks.vue @@ -0,0 +1,815 @@ + + + diff --git a/frontend/src/components/common/Calendars.vue b/frontend/src/components/common/Calendars.vue new file mode 100644 index 0000000..8f58465 --- /dev/null +++ b/frontend/src/components/common/Calendars.vue @@ -0,0 +1,475 @@ + + + diff --git a/frontend/src/components/common/CalendarsAccess.vue b/frontend/src/components/common/CalendarsAccess.vue new file mode 100644 index 0000000..af99748 --- /dev/null +++ b/frontend/src/components/common/CalendarsAccess.vue @@ -0,0 +1,504 @@ + + + diff --git a/frontend/src/components/common/SharedFolders.vue b/frontend/src/components/common/SharedFolders.vue new file mode 100644 index 0000000..76f1728 --- /dev/null +++ b/frontend/src/components/common/SharedFolders.vue @@ -0,0 +1,755 @@ + + + diff --git a/frontend/src/components/common/TimezoneSelect.vue b/frontend/src/components/common/TimezoneSelect.vue new file mode 100644 index 0000000..628ccea --- /dev/null +++ b/frontend/src/components/common/TimezoneSelect.vue @@ -0,0 +1,40 @@ + + diff --git a/frontend/src/components/common/WorkDaysSelect.vue b/frontend/src/components/common/WorkDaysSelect.vue new file mode 100644 index 0000000..2cb5caa --- /dev/null +++ b/frontend/src/components/common/WorkDaysSelect.vue @@ -0,0 +1,36 @@ + + diff --git a/frontend/src/components/common/WorkHoursRangePicker.vue b/frontend/src/components/common/WorkHoursRangePicker.vue new file mode 100644 index 0000000..6afc936 --- /dev/null +++ b/frontend/src/components/common/WorkHoursRangePicker.vue @@ -0,0 +1,6 @@ + + diff --git a/frontend/src/components/common/approval/Day.vue b/frontend/src/components/common/approval/Day.vue new file mode 100644 index 0000000..ef9ba98 --- /dev/null +++ b/frontend/src/components/common/approval/Day.vue @@ -0,0 +1,118 @@ + + diff --git a/frontend/src/components/common/approval/Interval.vue b/frontend/src/components/common/approval/Interval.vue new file mode 100644 index 0000000..d24ca14 --- /dev/null +++ b/frontend/src/components/common/approval/Interval.vue @@ -0,0 +1,66 @@ + + + + diff --git a/frontend/src/components/common/rules/Actions.vue b/frontend/src/components/common/rules/Actions.vue new file mode 100644 index 0000000..4dace56 --- /dev/null +++ b/frontend/src/components/common/rules/Actions.vue @@ -0,0 +1,74 @@ + + + diff --git a/frontend/src/components/common/rules/Conditions.vue b/frontend/src/components/common/rules/Conditions.vue new file mode 100644 index 0000000..7c729b8 --- /dev/null +++ b/frontend/src/components/common/rules/Conditions.vue @@ -0,0 +1,91 @@ + + + diff --git a/frontend/src/components/common/rules/Rules.vue b/frontend/src/components/common/rules/Rules.vue new file mode 100644 index 0000000..9e21905 --- /dev/null +++ b/frontend/src/components/common/rules/Rules.vue @@ -0,0 +1,588 @@ + + + diff --git a/frontend/src/components/common/rules/address/Actions.vue b/frontend/src/components/common/rules/address/Actions.vue new file mode 100644 index 0000000..80fd4d0 --- /dev/null +++ b/frontend/src/components/common/rules/address/Actions.vue @@ -0,0 +1,61 @@ + + + + diff --git a/frontend/src/components/common/rules/address/Conditions.vue b/frontend/src/components/common/rules/address/Conditions.vue new file mode 100644 index 0000000..6867710 --- /dev/null +++ b/frontend/src/components/common/rules/address/Conditions.vue @@ -0,0 +1,192 @@ + + + + diff --git a/frontend/src/components/common/rules/incoming/Actions.vue b/frontend/src/components/common/rules/incoming/Actions.vue new file mode 100644 index 0000000..f7eddcf --- /dev/null +++ b/frontend/src/components/common/rules/incoming/Actions.vue @@ -0,0 +1,210 @@ + + + + diff --git a/frontend/src/components/common/rules/incoming/Conditions.vue b/frontend/src/components/common/rules/incoming/Conditions.vue new file mode 100644 index 0000000..3da96af --- /dev/null +++ b/frontend/src/components/common/rules/incoming/Conditions.vue @@ -0,0 +1,503 @@ + + + + diff --git a/frontend/src/components/common/rules/outgoing/Actions.vue b/frontend/src/components/common/rules/outgoing/Actions.vue new file mode 100644 index 0000000..d14fe12 --- /dev/null +++ b/frontend/src/components/common/rules/outgoing/Actions.vue @@ -0,0 +1,381 @@ + + + + diff --git a/frontend/src/components/common/rules/outgoing/Conditions.vue b/frontend/src/components/common/rules/outgoing/Conditions.vue new file mode 100644 index 0000000..6730c5a --- /dev/null +++ b/frontend/src/components/common/rules/outgoing/Conditions.vue @@ -0,0 +1,300 @@ + + + + diff --git a/frontend/src/components/user/AddressBooks/AvaliableToMe.vue b/frontend/src/components/user/AddressBooks/AvaliableToMe.vue new file mode 100644 index 0000000..b1e944a --- /dev/null +++ b/frontend/src/components/user/AddressBooks/AvaliableToMe.vue @@ -0,0 +1,176 @@ + + + + diff --git a/frontend/src/components/user/AddressBooks/MyBooks.vue b/frontend/src/components/user/AddressBooks/MyBooks.vue new file mode 100644 index 0000000..da1b65a --- /dev/null +++ b/frontend/src/components/user/AddressBooks/MyBooks.vue @@ -0,0 +1,23 @@ + + diff --git a/frontend/src/components/user/Calendars/AvaliableToMe.vue b/frontend/src/components/user/Calendars/AvaliableToMe.vue new file mode 100644 index 0000000..babb382 --- /dev/null +++ b/frontend/src/components/user/Calendars/AvaliableToMe.vue @@ -0,0 +1,176 @@ + + + + diff --git a/frontend/src/components/user/Calendars/EventsPlanner/List.vue b/frontend/src/components/user/Calendars/EventsPlanner/List.vue new file mode 100644 index 0000000..783723a --- /dev/null +++ b/frontend/src/components/user/Calendars/EventsPlanner/List.vue @@ -0,0 +1,360 @@ + + + + diff --git a/frontend/src/components/user/Calendars/EventsPlanner/NewOrEdit.vue b/frontend/src/components/user/Calendars/EventsPlanner/NewOrEdit.vue new file mode 100644 index 0000000..c3b5273 --- /dev/null +++ b/frontend/src/components/user/Calendars/EventsPlanner/NewOrEdit.vue @@ -0,0 +1,1430 @@ + + + + diff --git a/frontend/src/components/user/Calendars/EventsPlanner/ScriptErrorNotify.vue b/frontend/src/components/user/Calendars/EventsPlanner/ScriptErrorNotify.vue new file mode 100644 index 0000000..41f6bf9 --- /dev/null +++ b/frontend/src/components/user/Calendars/EventsPlanner/ScriptErrorNotify.vue @@ -0,0 +1,90 @@ + + diff --git a/frontend/src/components/user/Calendars/MyCalendars.vue b/frontend/src/components/user/Calendars/MyCalendars.vue new file mode 100644 index 0000000..0cf3d84 --- /dev/null +++ b/frontend/src/components/user/Calendars/MyCalendars.vue @@ -0,0 +1,23 @@ + + diff --git a/frontend/src/components/user/Calendars/ShareFreeTime.vue b/frontend/src/components/user/Calendars/ShareFreeTime.vue new file mode 100644 index 0000000..58c640b --- /dev/null +++ b/frontend/src/components/user/Calendars/ShareFreeTime.vue @@ -0,0 +1,255 @@ + + + + diff --git a/frontend/src/components/user/IncomingRules.vue b/frontend/src/components/user/IncomingRules.vue new file mode 100644 index 0000000..a14fdeb --- /dev/null +++ b/frontend/src/components/user/IncomingRules.vue @@ -0,0 +1,55 @@ + + + diff --git a/frontend/src/components/user/MailboxSharedAccess.vue b/frontend/src/components/user/MailboxSharedAccess.vue new file mode 100644 index 0000000..6e2bd58 --- /dev/null +++ b/frontend/src/components/user/MailboxSharedAccess.vue @@ -0,0 +1,345 @@ + + + + diff --git a/frontend/src/components/user/Profile.vue b/frontend/src/components/user/Profile.vue new file mode 100644 index 0000000..a6915fc --- /dev/null +++ b/frontend/src/components/user/Profile.vue @@ -0,0 +1,277 @@ + + + diff --git a/frontend/src/components/user/RecoveryFolder.vue b/frontend/src/components/user/RecoveryFolder.vue new file mode 100644 index 0000000..a123b12 --- /dev/null +++ b/frontend/src/components/user/RecoveryFolder.vue @@ -0,0 +1,84 @@ + + + + diff --git a/frontend/src/components/user/SharedFolders.vue b/frontend/src/components/user/SharedFolders.vue new file mode 100644 index 0000000..1762cbf --- /dev/null +++ b/frontend/src/components/user/SharedFolders.vue @@ -0,0 +1,23 @@ + + diff --git a/frontend/src/composables/alert.ts b/frontend/src/composables/alert.ts new file mode 100644 index 0000000..2f171ad --- /dev/null +++ b/frontend/src/composables/alert.ts @@ -0,0 +1,27 @@ +import { notification } from "ant-design-vue"; +import i18n from "@/locale"; + +notification.config({ + maxCount: 1, +}); + +export function notifyError(msg: string) { + notification["error"]({ + message: i18n.global.t("common.notify.error"), + description: msg, + }); +} + +export function notifySuccess(msg: string) { + notification["success"]({ + message: i18n.global.t("common.notify.success"), + description: msg, + }); +} + +export function notifyWarning(msg: string) { + notification["warning"]({ + message: i18n.global.t("common.notify.warning"), + description: msg, + }); +} diff --git a/frontend/src/composables/apiFetch.ts b/frontend/src/composables/apiFetch.ts new file mode 100644 index 0000000..79c3c2e --- /dev/null +++ b/frontend/src/composables/apiFetch.ts @@ -0,0 +1,47 @@ +import { useAuthStore } from "@/stores/auth"; +import router from "@/router"; +import { RouteLogin } from "@/router/consts"; +import { useReturnToPageStore } from "@/stores/returnToPage"; +import { useRoute } from "vue-router"; + +export const apiFetch = async (request: any, opts?: any): Promise => { + if (opts && opts.body && !opts.isFormData) { + opts.body = JSON.stringify(opts.body); + } + + const headers = new Headers(); + //headers.set("Authorization", "Bearer " + useAuthStore().token); + + if (opts && !opts.isFormData) { + headers.set("Content-Type", "application/json"); + } + const resp = await fetch( + import.meta.env.VITE_API_URL + "/backend" + request, + { + headers, + credentials: "include", + ...opts, + } + ); + + const { result, total, error } = await resp.json(); + + if (resp.status != 200) { + if (resp.status == 401) { + useAuthStore().resetAuth(); + useReturnToPageStore().setPath( + router.currentRoute.value.path, + useRoute().query + ); + router.push(RouteLogin); + } + } + + return { data: result, total, error }; +}; + +export interface Response { + data: any; + total: number; + error: string; +} diff --git a/frontend/src/composables/misc.ts b/frontend/src/composables/misc.ts new file mode 100644 index 0000000..0a439ed --- /dev/null +++ b/frontend/src/composables/misc.ts @@ -0,0 +1,79 @@ +import { message } from "ant-design-vue"; +import i18n from "@/locale"; + +export const timeToDateTime = (time: any) => { + if (time == undefined) { + return; + } + var d = new Date(time); + return ( + ("0" + d.getHours()).slice(-2) + + ":" + + ("0" + d.getMinutes()).slice(-2) + + " " + + ("0" + d.getDate()).slice(-2) + + "/" + + ("0" + (d.getMonth() + 1)).slice(-2) + + "/" + + d.getFullYear() + ); +}; + +export const timeToDate = (time: any) => { + if (time == undefined) { + return; + } + var d = new Date(time); + return ( + ("0" + d.getDate()).slice(-2) + "/" + ("0" + (d.getMonth() + 1)).slice(-2) + ); +}; + +export const timeToFullDate = (time: any) => { + if (time == undefined) { + return; + } + var d = new Date(time); + return ( + ("0" + d.getDate()).slice(-2) + + "." + + ("0" + (d.getMonth() + 1)).slice(-2) + + "." + + d.getFullYear() + ); +}; + +export const copyToClipboard = (text: string) => { + navigator.clipboard.writeText(text); + message.info(i18n.global.t("common.misc.copy")); +}; + +export const genRandomString = (length: number) => { + let result = ""; + const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + const charactersLength = characters.length; + let counter = 0; + while (counter < length) { + result += characters.charAt(Math.floor(Math.random() * charactersLength)); + counter += 1; + } + return result; +}; + +export const getTimezoneString = () => { + let offset = new Date().getTimezoneOffset(); + offset = offset / -60; + let resStr = "UTC"; + if (offset < 0) { + resStr += "-"; + offset *= -1; + } else { + resStr += "+"; + } + if (offset < 10) { + resStr += "0"; + } + resStr += offset; + resStr += ":00"; + return resStr; +}; diff --git a/frontend/src/composables/restart.ts b/frontend/src/composables/restart.ts new file mode 100644 index 0000000..202761d --- /dev/null +++ b/frontend/src/composables/restart.ts @@ -0,0 +1,31 @@ +import { ExclamationCircleOutlined } from "@ant-design/icons-vue"; +import { Modal } from "ant-design-vue"; +import { createVNode } from "vue"; +import router from "@/router"; +import { RouteLogin } from "@/router/consts"; +import i18n from "@/locale"; +import { apiFetch } from "./apiFetch"; +import { notifyError } from "./alert"; + +export function saveAndRestart(callback: () => Promise) { + Modal.confirm({ + title: i18n.global.t("common.save_and_restart.confirm_title"), + icon: createVNode(ExclamationCircleOutlined), + content: i18n.global.t("common.save_and_restart.confirm_content"), + okText: i18n.global.t("common.save_and_restart.ok"), + cancelText: i18n.global.t("common.save_and_restart.cancel"), + async onOk() { + if (await callback()) { + const res = await apiFetch("/admin/restart", { + method: "POST", + }); + + if (res.error) { + notifyError(res.error); + return; + } + router.push(RouteLogin); + } + }, + }); +} diff --git a/frontend/src/locale/index.ts b/frontend/src/locale/index.ts new file mode 100644 index 0000000..33a16dc --- /dev/null +++ b/frontend/src/locale/index.ts @@ -0,0 +1,32 @@ +import { createI18n } from "vue-i18n"; +import { translations } from "./translations"; + +const defaultLocale = "eng"; + +export function getLocale() { + const locale = localStorage.getItem("locale"); + if (!locale) { + return defaultLocale; + } + return locale; +} + +export function setLocale(locale: any) { + localStorage.setItem("locale", locale); + i18n.global.locale.value = locale; +} + +var locale = localStorage.getItem("locale"); +if (!locale) { + locale = defaultLocale; + localStorage.setItem("locale", locale); +} + +const i18n = createI18n({ + legacy: false, + locale: locale, + fallbackLocale: defaultLocale, + messages: translations, +}); + +export default i18n; diff --git a/frontend/src/locale/translations.ts b/frontend/src/locale/translations.ts new file mode 100644 index 0000000..5b455bf --- /dev/null +++ b/frontend/src/locale/translations.ts @@ -0,0 +1,2593 @@ +import type Policy from "@/components/admin/domains/cidr_access/Policy.vue"; + +export const translations = { + eng: { + tegu: "Tegu Mail Server", + common: { + not_found: { + page_not_found: "Page not found", + return: "To home", + }, + save_and_restart: { + confirm_title: "Save settings?", + confirm_content: "Service will be restarted", + ok: "Restart service", + cancel: "Cancel", + }, + notify: { + error: "Error!", + success: "Success!", + warning: "Warning!", + }, + suffixes: { + mb: "MB", + sec: "sec", + min: "min", + hours: "hours", + bits: "bits", + }, + misc: { + copy: "Copied to clipboard", + ok: "Ok", + cancel: "Cancel", + edit: "Edit", + delete: "Delete", + search: "Search", + yes: "Yes", + no: "No", + save_changes: "Save changes", + }, + }, + login: { + title: "Login", + mail: "Email", + empty_mail: "Enter email", + pass: "Password", + empty_pass: "Enter password", + login: "Login", + error: "Auth error", + }, + shared: { + free_time: { + title: "User's free time", + }, + events_external_approval: { + title: "Free time select", + title_event_part: " for event ", + subject: "Subject", + creator: "Creator", + message: "Message", + participants: "Participants", + timezone: "Timezone", + send_button: "Send avaliable free time to creator", + desc: "Using mouse (click or hold), select all the time slots that suits you.", + success: + "Your free time information has been sent to the event creator. You will receive a notification email once the event is confirmed.", + }, + }, + user: { + title: "", + top_menu: { + search: "Search in user control panel", + logout: "Logout", + }, + left_menu: { + profile: "Profile", + rules: "Incoming rules", + recovery: "Recovery folder", + shared_folders: "Shared folders", + mailbox_shared_access: "Mailbox shared access", + address_books: "Address books", + address_books_menu: { + my: "My books", + with_access: "Available to me", + }, + calendars: "Calendars", + calendars_menu: { + my: "My calendars", + with_access: "Available to me", + share_free_time: "Share free time", + events_planner: "Planning assistant", + }, + }, + }, + admin: { + title: "Admin", + top_menu: { + search: "Search in admin control panel", + control_panel: "Control panel", + documentation: "Documentation", + logout: "Logout", + }, + left_menu: { + dashboard: "Dashboard", + dashboard_aliases: "info information status dns", + settings: "Settings", + settings_menu: { + main: "Main", + main_aliases: + "working size inbox name imap imaps smtp smtps lmtp ip port queue concurrent milter antispam antivirus master protect security ban auth ssl certificate tls version fullallowed greylist blacklist dnsbl spf empty sender dav carddav caldav reports migration", + smtp_queue: "SMTP Queue", + smtp_queue_menu: { + manage: "Manage", + manage_aliases: "queue delete message awaiting resend process", + settings: "Settings", + settings_aliases: "queue settings", + }, + settings_db: "Settings DB", + address_change: "Global address change", + address_change_aliases: "rewrite rules", + calendars: "Calendars", + calendars_aliases: "caldav dav", + license: "License", + license_aliases: "eula key", + }, + security: "Security", + security_menu: { + blocked_ips: "Blocked IPs", + blocked_ips_aliases: "unblock", + white_list: "Senders white list", + black_list: "Senders black list", + bw_list_menu: { + ip: "IP", + email: "Email", + }, + }, + domains: "Domains", + domains_menu: { + add: "Add domain", + mail_storage: "Mail storage", + mail_storage_menu: { + mailboxes: "Mailboxes", + settings: "Settings", + other: "More", + other_menu: { + delete: "Delete provider", + }, + }, + users_providers: "User DB providers", + users_providers_menu: { + add: "Add provider", + users: "Users", + groups: "Groups", + redirects: "Redirects", + settings: "Settings", + other: "More", + other_menu: { + delete: "Delete", + delete_success: "Provider deleted", + delete_title: "Delete provider?", + delete_content: "User DB provider will be deleted", + delete_ok: "OK", + delete_cancel: "Cancel", + }, + }, + shared_folders: "Shared folders", + books: "Shared address books", + calendars: "Shared calendars", + resources: "Shared resources", + resources_menu: { + resources: "Resources", + categories: "Categories", + offices: "Offices", + }, + incoming_routing: "Incoming rules", + outgoing_routing: "Outgoing rules", + dkim: "DKIM", + migrate: "Migration", + cidr_access: "Access restrict by CIDR", + cidr_access_menu: { + pools: "Access pools", + policy: "Policy", + }, + other: "More", + other_menu: { + mails_perm_deletion: "Mails permanent deletion", + rename: "Rename domain", + rename_exists: "Domain already exists", + rename_active: "Rename in progress", + delete: "Delete domain", + delete_success: "Domain deleted", + delete_title: "Delete domain?", + delete_content: "Domain and all settings will be deleted", + delete_ok: "OK", + delete_cancel: "Cancel", + }, + }, + }, + }, + components: { + admin: { + dashboard: { + license: { + title: "Tegu Enterprise Mail Server", + developer: "Developer", + version: "Version", + license: "License", + license_empty: "Not installed or empty", + license_mismatch: "Installed key and server edition mismatch", + }, + mailboxes: { + title: "Mailboxes", + license_allowed: "Allowed by license", + used: "Used", + remains: "Remains", + archived: "Archived", + used_last_month: "Used in the last month", + used_current_month: "Used in the current month", + }, + smtp_queue: { + title: "SMTP Queue", + type: "Type", + host: "Host", + }, + antispam: { + title: "Antispam/antivirus", + type: "Type", + status: "Status", + status_enabled: "Enabled", + status_disabled: "Disabled", + host: "Host", + }, + imap: { + title: "IMAP", + server: "Server", + port: "Port", + encryption: "Encryption", + auth: "Authorization", + auth_text: "Plain password / Login", + }, + smtp: { + title: "SMTP", + server: "Server", + port: "Port", + encryption: "Encryption", + auth: "Authorization", + auth_text: "Plain password / Login", + }, + dav: { + title: "DAV Services", + books: "Address books connection URL", + calendars: "Calendars connection URL", + }, + domain: { + mailstorage: "Mail storage", + userdb_providers: "User DB providers", + dns_record: "DNS recommendations", + dns_show: "show", + dns_copy: "Copy to clipboard", + }, + }, + settings: { + main: { + main: "Main", + main_content: { + ServerName: "Server name (used in SMTP hello and HELO/EHLO)", + WebInboxCn: + "A clear alias for the INBOX folder (displayed in the WEB panel)", + MsgSizeLimit: "Max. letter size", + Vardir: "FS directory for server working data", + }, + imap: "IMAP", + imap_content: { + IMAPListenIP: "IP on which to listen to the IMAP port", + IMAPListenPort: "IMAP port", + IMAPSListenPort: "IMAPS port (SSL)", + IMAPMaxClients: + "Max. number of simultaneous incoming IMAP connections", + }, + smtp: "SMTP", + smtp_content: { + SMTPListenIP: "IP on which to listen to the SMTP port", + SMTPListenPort: "SMTP port", + SMTPSListenPort: "SMTPS port (SSL)", + SMTPMaxClients: + "Max. number of simultaneous incoming SMTP connections", + }, + lmtp: "LMTP", + lmtp_content: { + LMTPDelivery: + "Enable email delivery via LMTP (otherwise it will start its own IMAP server)", + LMTPHost: "LMTP host to connect to", + LMTPPort: "LMTP port", + }, + + queue: "Message queue", + queue_content: { + QueueConcurrentJobs: "Number of concurrent SMTP queue processors", + QueueJobTtlMinutes: + "Maximum time for one SMTP queue processing pass (minutes)", + }, + + antispam: "Antispam/antivirus", + antispam_content: { + MilterScan: + "Enable antivirus and/or antispam support (milter protocol)", + MilterHostPort: + "Milter host and port for connecting to antivirus/antispam (host:port)", + MilterNetTimeout: + "Network timeout for antivirus/antispam response (sec)", + SpamScoreMimeHeader: + "Letter header name to indicate the number of spam points (set by antispam)", + }, + + auth: "Authorization", + auth_content: { + MasterUserSep: "Master user login separator", + AllowCrossDomainSharedAccess: + "Allow access to shared resources between domains (including master user)", + AuthNeedTLS: "Require TLS/SSL encryption for authorization", + AuthSecurity: "Enable authorization protection system (ban)", + FailedAuthLookupMinutes: + "Lifetime of a failed authorization attempt record (minutes)", + BanTimeMinutes: "Ban duration (minutes)", + MaxFailedAuthAttempts: + "Max. number of authorization failures before ban", + FailedAuthWhitelist: + "IP exclusion list of the authorization protection system (192.168.0.1 or 192.168.0.0/24)", + }, + + ssl: "SSL", + ssl_content: { + TLSMinVer: "Minimum TLS version for incoming connections", + SslCert: "Path to SSL certificate", + SslKey: "Path to SSL private key", + }, + mail_sending: "Mail sending", + mail_sending_content: { + RemoteTLSMinVer: + "Minimum TLS version for outgoing SMTP connections", + UseOnlySecureCiphers: "Use only secure ciphers", + SmtpAllowPlainForDomains: + "Recipient domains that are allowed to send unencrypted (one per line)", + SettQueueSendTimeoutSec: + "Maximum time to send one letter (seconds)", + }, + smtp_sessions: "SMTP sessions", + smtp_sessions_group: { + access: "Access", + greylist: "Greylist", + dnsdbl: "DNSBL", + spf: "SPF", + }, + smtp_sessions_content: { + access: { + SmtpAcl: "Enable white/black lists of IP/email senders", + FullallowedHosts: "IP list with full access (one per line)", + AllowEmptySenderForFullallowedHosts: + "Allow empty email sender for IP with full access", + }, + greylist: { + CheckGreylist: "Enable Greylist", + GreylistSkipDomains: + "Sender domain exclusion list for greylist (one per line)", + GreylistRecordLifetimeHours: "Greylist entry lifetime (hours)", + WhitelistRecordLifetimeHours: + "Greylist whitelist entry lifetime (hours)", + CleanExpiredGreyrecordsIntervalSec: + "Interval for clearing outdated greylist entries (sec)", + }, + dnsbl: { + CheckDnsbl: "Enable DNSBL checks", + DnsblListedAtThreshold: + "Number of DNSBL lists in which the sender was found to block the letter", + }, + spf: { + BlockSpfFailedSenders: + "Block emails whose senders have not passed SPF verification", + AllowSPFNoneOrNeutral: + "Allow emails for which SPF records are incorrect or missing from senders", + }, + }, + + dav_services: "DAV-services", + dav_services_content: { + DAVPortHTTP: "HTTP port", + DAVPortHTTPS: "HTTPS Port", + }, + reports: "Delivery reports", + reports_content: { + AllowNotifyExternalUsers: + "Allow delivery problem reports to be sent to external senders", + RetryBeforeNotify: + "Number of delivery attempts after which a problem report will be sent to the sender", + }, + logging: "Logging", + logging_content: { + LogConnOpenClose: "Log start and end of sessions (IMAP/SMTP)", + }, + migration: "Migrations", + migration_content: { + MigrationMode: "Enable migration mode from another server", + }, + save: "Save settings", + }, + settings_db: { + Type: "Settings DB type", + ConnParams: { + Host: "Server address", + Port: "Server port", + Db: "Database name", + User: "Username", + Pass: "Password", + MaxConn: "Maximum number of simultaneous connections", + }, + PathParams: { + DatabaseDir: "Path to the directory with the parameters database", + }, + save: "Save settings", + change: "Change type and save settings", + check: "Check connect", + check_error: "Check connect failed: ", + check_success: "Check connect success", + }, + smtp_queue: { + settings: { + Type: "Queue type", + ConnParams: { + Host: "Server address", + Port: "Server port", + Db: "Database name", + User: "Username", + Pass: "Password", + MaxConn: "Maximum number of simultaneous connections", + MaxQueueItems: "Number of emails processed per pass", + }, + PathParams: { + DatabaseDir: "Path to the directory for smtp queue files", + }, + save: "Save settings", + change: "Change type and save settings", + check: "Check connect", + check_error: "Check connect failed: ", + check_success: "Check connect success", + }, + manage: { + total: "Total messages", + new: "New messages", + resend: "Awaiting resend", + + clear_filtered: "Delete filtered messages", + process_filtered: "Proccess filtered", + clear_all: "Delete all messages", + delete_awaiting_resend: "Delete all awaiting resend", + delete_awaiting_resend_filter: "Delete filtered awaiting resend", + process_awaiting_resend: "Proccess all awaiting resend", + + process_now: "Proccess now", + delete: "Delete message", + column_sender: "Sender", + column_receiver: "Receiver", + column_added: "Added in queue", + column_will_resend: "Will be resend", + column_will_resend_now: "Now", + ok: "Ok", + cancel: "Cancel", + search: "Search message", + }, + }, + license: { + no_install: "The license is not installed", + accept: "Accept", + title: "License Info", + id: "License ID", + edition: "Tegu Edition", + valid_till: "Valid till", + valid_forever: "Forever", + max_mailbox_count: "Maximum number of mailboxes", + send_report: "Send report", + send_report_no: "No", + customer_name: "Customer name", + customer_type: "Customer type", + customer_data: "Customer data", + show_eula: "Show EULA", + load: "Load license file", + fiz_type: "Individual", + ur_type: "Legal entity", + }, + calendars: { + freebusy: "Free/Busy access by default", + showfrom: "Don't display events older than N weeks", + showto: "Don't display events newer than N weeks", + localpart: + "Local part (up to {'@'}) of the notification sender address", + success: "Settings saved", + save: "Save settings", + }, + }, + security: { + blocked_ips: { + unblock: "Unblock", + unblock_all: "Unblock all", + search: "Search IP", + unblock_found: "Unblock found IPs", + ip: "IP", + }, + bw_list_email: { + delete: "Delete", + delete_all: "Delete all", + delete_found: "Delete found", + email: "Email", + add_email: "Add email to list", + add: "Add", + add_email_placeholder: "Email", + search: "Search email", + }, + bw_list_ip: { + delete: "Delete", + delete_all: "Delete all", + delete_found: "Delete found", + ip: "IP", + add_ip: "Add IP to list", + add: "Add", + add_ip_placeholder: "IP", + search: "Search IP", + }, + }, + domains: { + add: { + Domain: "New domain", + Type: "Storage type", + create: "Create domain", + success: "Domain created", + }, + mailstorage: { + mailboxes: { + search: "Search mailbox", + storage_filter: "All storages", + clear_recovery_all: "Clear all RECOVERY folders", + clear_recovery_found: "Clear found RECOVERY folders", + change_storage: "Change storage", + change_storage_for: "Change storage for ", + change: "Change", + delete_all: "Delete all mailboxes", + delete_found: "Delete found mailboxes", + delete: "Delete", + clear_recovery: "Clear RECOVERY folder", + archive: "Block", + unarchive: "Unblock", + in_archive: "Mailbox blocked", + deleted: "Mailbox deleted", + export: "Export", + ok: "OK", + cancel: "Cancel", + col_email: "Mailbox Email", + col_msg_count: "Msg. count", + col_size: "Mailbox size", + col_quota: "Quota", + col_quota_used: "Used", + col_recovery_size: "RECOVERY size", + col_table_prefix: "Mailbox table prefix", + col_table_access_key: "Storage", + col_actions: "Actions", + rename: "Rename", + rename_exists: "Mailbox already exists", + }, + export: { + title: "Export mailbox", + catalog: "Export folder", + hostname: "Export hostname", + start_export: "Start export", + success: "Export completed. Duration: ", + }, + settings: { + panel_connect: "Connection settings", + panel_multi: "Multi-storage", + panel_additional: "Additional settings", + + multi_storage: { + conns_nums: "connections", + col_access_key: "Unique connection key", + col_hostport: "Host:port", + mailbox_distribution_pattern: "Mailbox distribution pattern", + add_connect: "Add connection", + edit_access_key: "Edit connection key", + save: "Save", + edit_connect: "Edit connection", + save_connect: "Save", + delete_action: "Delete", + edit_action: "Edit", + }, + + Type: "Mail storage type", + Host: "Server address", + Port: "Server port", + MboxesDb: "Database name", + User: "User", + Pass: "Password", + MaxConn: "Maximum number of simultaneous connections", + MailDirRoot: "Maildir root directory", + IMAPDefaultFolders: { + Archive: "Archive folder", + Drafts: "Drafts folder", + Junk: "Junk folder", + Sent: "Sent folder", + Trash: "Trash folder", + SharedRoot: "Root folder for shared folders", + Recovery: "Recovery folder", + }, + SmartHost: "Smarthost", + SmartHostFormat: `user:pass{'@'}host:port or host:port`, + RecoveryEnabled: "Enable recovery folder", + DefaultUserQuota: "Default quota", + TrashAdditionalQuota: "Additional quota for trash", + QuotaNotifyThreshold: "Notification after filling the mailbox", + + change: "Change type and save settings", + save: "Save settings", + save_success: "Save success", + check: "Check connect", + check_error: "Check connect failed: ", + check_success: "Check connect success", + }, + }, + userdb: { + add: { + Name: "Name", + Type: "Type", + create: "Create provider", + success: "Provider created", + }, + users: { + col_name: "Name", + col_email: "Email", + add: "Add user", + edit: "Edit", + delete: "Delete", + ok: "OK", + cancel: "Cancel", + add_modal: { + display_name: "Display name", + email: "Email", + alt_emails: "Alternate emails", + quota: "Quota", + password: "Password", + password_again: "Repeat password", + cancel: "Cancel", + save: "Save", + }, + }, + redirects: { + col_name: "Name", + col_email: "Email", + add: "Add redirect", + edit: "Edit", + delete: "Delete", + ok: "OK", + cancel: "Cancel", + add_modal: { + name: "Name", + email: "Email", + destinations: "Destinations", + cancel: "Cancel", + save: "Save", + }, + }, + groups: { + col_name: "Name", + col_email: "Email", + col_users_count: "Users count", + col_group_count: "Groups count", + add: "Add group", + edit: "Edit", + members: "Members", + delete: "Delete", + ok: "OK", + cancel: "Cancel", + add_modal: { + name: "Name", + email: "Email", + alt_emails: "Alternate emails", + cancel: "Cancel", + save: "Save", + }, + }, + settings: { + Name: "Name", + UseInGal: "Use in GAL", + Dir: "Directory path of user/group databases", + MasterUsersGroup: "Group name of master users", + CacheTTL: "Cache TTL (seconds)", + + ConnectionGroup: "Connections", + ConnectURIs: "LDAP connection URIs (one per line)", + ConnectBindDN: "BindDN", + ConnectPassword: "Password", + ConnectBaseDN: "Base DN", + ConnectTLSMinVer: "Minimum TLS version for outgoing connections", + + UserGroup: "Users", + UserObjectclass: "objectClass for user", + UserMailAttr: "Attr for mailbox e-mail", + UserQuotaAttr: "Attr for mailbox quota (value in MB)", + MemberofAttr: "User memberOf attr", + UserAddSearchFilter: "Additional user search filter", + + GroupsGroup: "Groups", + EmailGroups: "Use groups", + GroupObjectclass: "objectClass for group", + GroupNameAttr: "Attr for group name", + GroupMailAttr: "Attr for group email", + GroupMemberAttr: "Attr for group members", + GroupMemberDn: "Group member attr contains DN", + UserRDNAttr: "Attr for user RDN", + GroupAddSearchFilter: "Additional group search filter", + + RedirectGroup: "Aliases (redirects)", + EmailRedirect: "Use mailbox alias (redirect list)", + AliasObjectclass: "objectClass for alias", + AliasMailAttr: "Attr for alias email", + AliasRedirectAttr: "Attr for email redirect to", + + AltEmailGroup: "Alternative emails", + EmailAlternate: "Use mailbox alternative email", + AlternateMailAttr: "Attr for mailbox alternative email", + + MasterGroup: "Master users", + MasterUserGroupNameAttr: "Attr for group name of master-users", + MasterUserGroup: "Group name of master-users", + + GALGroup: "Global Address List (GAL)", + GALCacheTTL: "GAL Cache TTL (minutes)", + GALObjectsFilter: "GAL objects filter", + + GALUserGroup: "Users", + GALUserNameAttr: "GAL attr for user name", + GALUserEmailAttr: "GAL attr for user email", + GALUserAltEmailAttr: "GAL attr for alternative user email", + GALUserPhoneAttr: "GAL attr for user phone", + GALUserPhotoAttr: "GAL attr for user photo", + GALUserBirthdayAttr: "GAL attr for user birthday", + GALUserAddressAttr: "GAL attr for user address", + GALUserOrganizationAttr: "GAL attr for user organization", + GALUserRoleAttr: "GAL attr for user role", + + GALGroupsGroup: "Groups", + GALGroupNameAttr: "GAL attr for group name", + GALGroupEmailAttr: "GAL attr for group email", + + GALAliasesGroup: "Aliases", + GALAliasNameAttr: "GAL attr for alias name", + GALAliasEmailAttr: "GAL attr for alias email", + + change: "Change type and save settings", + save: "Save settings", + save_success: "Save success", + check: "Check connect", + check_email: "Email to check", + check_error: "Check connect failed: ", + check_success: "Check connect success", + }, + }, + cidr_access: { + pools: { + col_name: "Name", + delete: "Delete", + delete_found: "Delete found", + delete_all: "Delete all", + properties: "Properties", + update_pool: "Update pool", + add_pool: "Add pool", + add_name: "Name", + add_ips: "CIDR list", + add_ips_placeholder: + "One IP per line (127.0.0.1 or 127.0.0.1/16)", + ok: "Ok", + cancel: "Cancel", + search: "Search pools", + }, + policy: { + enabled: "Enable access restrict by CIDR", + col_name: "Group", + col_count: "Active pools", + delete: "Delete", + delete_found: "Delete found", + delete_all: "Delete all", + properties: "Manage access", + add_policy: "Add access policy for group", + select_group: "Select group", + update_policy: "Update access policy for ", + ok: "Ok", + cancel: "Cancel", + search: "Search group", + }, + }, + resources: { + offices: { + col_name: "Name", + col_timezone: "Timezone", + add_office: "Add office", + edit_office: "Edit office", + create_success: "Office created", + update_success: "Office updated", + delete_success: "Office deleted", + }, + categories: { + col_name: "Name", + col_office_bind: "Office bind", + col_script: "Script", + add_category: "Add category", + edit_category: "Edit category", + create_success: "Category created", + update_success: "Category updated", + delete_success: "Category deleted", + }, + resources: { + col_name: "Name", + col_category: "Category", + col_script: "Script", + col_office: "Office", + col_show_time_as: "Show time as", + time_busy: "Busy", + time_free: "Free", + add_resource: "Add resource", + edit_resource: "Edit resource", + check_script: "Check script", + check_script_good: "No errors found", + any_category: "Any category", + any_office: "Any office", + create_success: "Resource created", + update_success: "Resource updated", + delete_success: "Resource deleted", + }, + }, + dkim: { + title: "TXT record for DNS zone", + delete: "Delete", + delete_success: "DKIM deleted", + selector: "Selector", + key_size: "Key size in bits", + create: "Create DKIM", + success: "DKIM created", + }, + migration: { + enabled: "Enable migration for this domain", + virtual_domain: "Virtual domain", + other_servers: "Other domain servers (host:port - one per line)", + local_emails: "Local emails (one per line)", + save: "Save settings", + success: "Settings saved", + }, + mails_perm_deletion: { + filter: "Mails filter", + found: "Mails found", + find: "Find mails", + delete: "Delete found mails: ", + delete_text: "Mails will be permamently deleted", + success: "Mails have been permamently deleted", + ok: "Delete", + cancel: "Cancel", + }, + }, + }, + user: { + profile: { + mailbox: { + title: "Mailbox", + user: "Email", + size: "Size", + count: "Messages", + }, + imap: { + title: "IMAP", + server: "Server", + port: "Port", + encryption: "Encryption", + auth: "Authorization", + auth_text: "Plain password / Login", + auth_login: "Login/Username", + }, + smtp: { + title: "SMTP", + server: "Server", + port: "Port", + encryption: "Encryption", + auth: "Authorization", + auth_text: "Plain password / Login", + auth_login: "Login/Username", + }, + dav: { + title: "DAV Services", + books: "Address books connection URL", + calendars: "Calendars connection URL", + login: "Login/Username", + }, + }, + recovery: { + show: "Show recovery folder", + save: "Save settings", + success: "Settings saved", + }, + mailbox_shared_access: { + search: "Search", + col_name: "Access to", + type_email: "Users", + type_email_placeholder: "Email", + type_email_add: "Add access to user", + type_group_add: "Add access to group", + add: "Add access", + type_group: "Groups", + delete: "Delete", + delete_found: "Delete found", + delete_all: "Delete all", + ok: "Ok", + cancel: "Cancel", + }, + address_books: { + with_access: { + col_name: "Name", + col_owner: "Owner", + col_permission: "Permissions", + search: "Search address book", + }, + }, + calendars: { + with_access: { + col_name: "Name", + col_owner: "Owner", + col_permission: "Permissions", + search: "Search calendar", + }, + share_free_time: { + timezone: "Timezone", + work_days: "Work days", + work_days_names: { + monday: "Monday", + tuesday: "Tuesday", + wednesday: "Wednesday", + thursday: "Thursday", + friday: "Friday", + saturday: "Saturday", + sunday: "Sunday", + }, + work_hours: "Work hours", + time_between_events: "Time between events", + two_month_restriction: "Share time no more than 2 months", + gen_link: "Generate new access link", + gen_link_success: "New link generated", + }, + events_planner: { + my_events: { + search: "Search event", + col_name: "Name", + col_start: "Start at", + col_finish: "Finish at", + col_participants: "Participants count", + status_under_approval: "Under approval", + status_approval_done: "Approval done", + new_event: "New event", + approval_with_ft: "Participants who indicated free time", + approval_without_ft: + "Participants who did not indicate their free time", + }, + script_error_notify: { + title: "Script execution error", + resource_name: "Resource name", + error: "Error", + output: "Script output", + script: "Script text", + }, + new_edit: { + subject: "Subject", + subject_placeholder: "Subject of event", + message: "Message", + message_placeholder: "Invite message", + participants: "Participants (one per line)", + include_creator: "Include me as participant", + resources: "Resources", + first_avaliable: "First avaliable", + + mandatory: "Mandatory emails", + optional: "Optional emails", + duration: "Duration", + duration_type: { + mins: "minites", + hours: "hours", + days: "days", + weeks: "weeks", + months: "months", + }, + start: "Start time", + time_not_selected: "Time not selected", + find_time: { + title: "Select available time", + start_search: "Start search", + search_from: "Search from", + depth: "Search depth", + selected_day: "Selected day", + selected_time: "Selected time", + not_found: "Free time not found", + depth_values: { + day: "Day", + week: "Week", + month: "Month", + }, + select_and_create_button: "Select time and create event", + select_and_update_button: "Select time and update event", + choose_time_button: "Submit for time approval", + choose_time_desc_part_1: + "Participants include external users. It is possible to send an event for approval and collect information about free time. ", + choose_time_desc_part_2: + "External participants without information about free time: ", + choose_time_desc_part_3: + "For all external participants there is information about free time", + choose_time_text_1: + "Send a request for time coordination to the following participants:", + choose_time_text_2: + "Each participant must respond to the request within this time:", + choose_time_text_3: + "You will receive a notification after all free time has been collected from all participants, or after the time above has expired.", + choose_time_interval: "Wait time", + choose_time_and_create_button: + "Submit for time approval and create event", + choose_time_and_update_button: + "Submit for time approval and update event", + }, + reset_warning: + "The event time has been reset. Please search for free time again", + update_button: "Update event", + update_success: "Event updated", + create_success: "Event created", + }, + }, + }, + }, + common: { + rules: { + col_enabled: "Enabled", + col_name: "Name", + col_action: "Order", + add_rule: "Add rule", + save_rule: "Save rule", + edit_rule: "Edit rule", + delete_rule: "Delete rule", + ok: "Ok", + cancel: "Cancel", + edit_name: "Name", + edit_conditions: "Conditions", + edit_conditions_all: "All", + edit_conditions_any: "Any", + edit_actions: "Actions", + add_condition: "Add condition", + add_action: "Add action", + delete: "Delete", + + incoming: { + conditions: { + op_equal: "equal", + op_less: "less", + op_greater: "greater", + op_not_equal: "not equal", + op_starts: "starts with", + op_ends: "ends with", + op_contains: "contains", + op_not_contains: "not contains", + op_greater_or_equal: "greater or equal", + op_less_or_equal: "less or equal", + + date: "Date", + to: "To", + from: "From", + header_to: "Header 'To'", + header_from: "Header 'From'", + subject: "Subject", + copy_recipient: "Copy recipient", + size: "Size", + spam_score: "Spam score", + body: "Body", + all: "All emails", + }, + actions: { + to_folder: "Put in folder", + copy_to_folder: "Copy to folder", + mark_as_seen: "Mark as read", + mark_as_flagged: "Mark flagged", + redirect_to: "Redirect to", + copy_to: "Send copy to", + reply_msg: "Reply message", + reject: "Reject", + stop: "Stop processing rules", + }, + }, + outgoing: { + conditions: { + op_contains: "contains", + op_not_contains: "not contains", + op_equal: "equal", + op_not_equal: "not equal", + op_starts: "starts with", + op_ends: "ends with", + + from: "Sender", + to: "Recipient", + from_group: "Sender group", + to_group: "Recipient group", + body: "Body", + subject: "Subject", + all: "All emails", + }, + actions: { + transform_from_address: "Transform sender email", + transform_to_address: "Transform recipient email", + transform_from_address_and_header: + "Transform sender email and header 'From'", + transform_to_address_and_header: + "Transform recipient email and header 'To'", + copy_to: "Send copy to", + premoderation: "Send to premoderation", + send_via_smart_host: "Send via smart-host", + add_text_to_start: "Add text to the start of mail body", + add_text_to_end: "Add text to the end of mail body", + + reject_external: "Reject delivery to external recipients", + reject_external_count: + "Reject delivery of more than N emails to external recipients per day", + reject_internal_count: + "Reject delivery of more than N emails to internal recipients per day", + reject_groups: "Reject delivery to group", + reject_in_group: "Reject delivery to group members", + reject_any: "Reject delivery", + allow_external: "Allow delivery to external recipients", + allow_groups: "Allow delivery to group", + allow_in_group: "Allow delivery to group members", + allow_any: "Allow delivery", + send_response: + "Notify sender with message when rule is triggered", + send_response_default: + "Your message has been modified or blocked by your email service.", + add_text_default: "Text to add", + }, + }, + address: { + conditions: { + op_contains: "contains", + op_not_contains: "not contains", + op_equal: "equal", + op_not_equal: "not equal", + op_starts: "starts with", + op_ends: "ends with", + + from: "Sender", + to: "Recipient", + from_group: "Sender group", + to_group: "Recipient group", + all: "All emails", + }, + actions: { + transform_from_address: "Transform sender address", + transform_to_address: "Transform recipient address", + }, + }, + }, + shared_folders: { + root_folder: "Root folder", + col_folder: "Folder", + col_owner: "Owner", + + edit_access: "Access", + delete: "Delete", + delete_found: "Delete found", + delete_all: "Delete all", + add_folder: "Add folder", + add_name: "Name", + ok: "Ok", + cancel: "Cancel", + search: "Search in ", + + access_search: "Search", + access_col_name: "Access to", + access_type_email: "Users", + access_type_email_placeholder: "Email", + access_type_email_add: "Add access to user", + access_type_group_add: "Add access to group", + access_add: "Add access", + access_type_group: "Groups", + }, + shared_address_books: { + col_name: "Name", + edit_access: "Access", + delete: "Delete", + delete_found: "Delete found", + delete_all: "Delete all", + properties: "Properties", + update_book: "Update book", + add_book: "Add address book", + add_name: "Name", + ok: "Ok", + cancel: "Cancel", + search: "Search address book", + + access_search: "Search", + access_col_name: "Access to", + access_col_permissions: "Permissions", + access_perm_all: "Full access", + access_perm_read: "Read only", + access_type_email: "Users", + access_type_email_placeholder: "Email", + access_type_email_add: "Add access to user", + access_type_group_add: "Add access to group", + access_add: "Add access", + access_type_group: "Groups", + }, + shared_calendars: { + col_name: "Name", + edit_access: "Access", + edit_cal_access: "Access", + delete: "Delete", + delete_found: "Delete found", + delete_all: "Delete all", + properties: "Properties", + update_calendar: "Update calendar", + add_calendar: "Add calendar", + add_name: "Name", + add_freebusy: "Provide information about busy time (Free/Busy)", + add_showfrom: "Don't display events older than N weeks", + add_showto: "Don't display events newer than N weeks", + add_color: "Color", + ok: "Ok", + cancel: "Cancel", + search: "Search calendar", + + access_search: "Search", + access_col_name: "Access to", + access_col_permissions: "Permissions", + access_perm_all: "Full access", + access_perm_read: "Read only", + access_type_email: "Users", + access_type_email_placeholder: "Email", + access_type_email_add: "Add access to user", + access_type_group_add: "Add access to group", + access_add: "Add access", + access_type_group: "Groups", + + add_success: "Access added", + update_success: "Access updated", + remove_success: "Access removed", + }, + }, + }, + eula: `ЛИЦЕНЗИОННОЕ СОГЛАШЕНИЕ С КОНЕЧНЫМ ПОЛЬЗОВАТЕЛЕМ ОБ ИСПОЛЬЗОВАНИИ ПОЧТОВОГО СЕРВЕРА TEGU PROFESSIONAL/ TEGU ENTERPRISE + +Настоящее лицензионное соглашение (далее – «Соглашение») определяет условия, на которых Общество с ограниченной ответственностью «Лаборатория МБК» (далее – «МБК Лаб») предоставляет Вам право использования ПОЧТОВОГО СЕРВЕРА TEGU PROFESSIONAL/ TEGU ENTERPRISE (далее - "Программный продукт") на условиях простой (неисключительной) лицензии. Соглашение заключается в упрощенном порядке и признается надлежащим в той степени, в которой законодательство Российской Федерации допускает такое заключение договора о передаче прав на использование программ для ЭВМ (ст.1286.1 ГК РФ). Соглашение действительно, если Вы являетесь физическим или юридическим лицом, которое приобрело правомерно введенные в гражданский оборот «МБК Лаб» или с его согласия третьими лицами экземпляры Программного продукта. В этом случае Вы и «МБК Лаб» являетесь надлежащими сторонами Соглашения (далее –«Стороны»). + +ФАКТОМ ЗАГРУЗКИ ИЛИ УСТАНОВКИ В ПАМЯТЬ ЭВМ, ВОСПРОИЗВЕДЕНИЯ ИЛИ ЛЮБОЙ ДРУГОЙ ФОРМЫ ИСПОЛЬЗОВАНИЯ ПРОГРАММ ДЛЯ ЭВМ, ОПРЕДЕЛЕННЫХ В СОГЛАШЕНИИ, ВЫ УДОСТОВЕРЯЕТЕ НАЧАЛО ИХ ИСПОЛЬЗОВАНИЯ, ЧТО ОЗНАЧАЕТ ВАШЕ СОГЛАСИЕ СО ВСЕМИ ТЕРМИНАМИ И ОПРЕДЕЛЕНИЯМИ, А ТАКЖЕ УСЛОВИЯМИ СОГЛАШЕНИЯ. + +Если Вы являетесь покупателем экземпляров программ для ЭВМ, определенных в Соглашении, и не согласны с условиями Соглашения, Вы обязуетесь незамедлительно вернуть неиспользованные экземпляры, а также удалить все копии программ для ЭВМ, определенных в Соглашении, из памяти Вашей ЭВМ и других носителей информации. + +Если Вы выражаете согласие с условиями Соглашения, «МБК Лаб» предоставляет Вам права использования Программного продукта в соответствии с нижеследующим: + +1. ТЕРМИНЫ И ОПРЕДЕЛЕНИЯ + +1.1. Программный продукт – ПОЧТОВЫЙ СЕРВЕР TEGU PROFESSIONAL/TEGU ENTERPRISE, представляющий собой составное произведение, исключительными правами на использование которого обладает «МБК Лаб». Действие настоящего соглашения распространяется на все компоненты Программного продукта как единого целого. +1.2.Экземпляр Программного продукта - это копия Программного продукта, передаваемая по сети Интернет, право на использование которой Вам предоставляется условиями данного Соглашения. +1.3. Компоненты Программного продукта – программы для ЭВМ, являющиеся неотделимой частью Программного продукта как составного произведения. +1.4. Программный продукт является сложным объектом и содержит компоненты собственной разработки «МБК Лаб» с применением свободных библиотек, распространяемых по открытой лицензии. +1.5. Объектный код – результат обработки исходного кода компилятором. +1.6. Исходный код – текст программы для ЭВМ на языке программирования. +1.7. Модификация – внесение любых изменений в Программный продукт и его Компоненты, которые не охватывают изменения, осуществляемые исключительно в целях обеспечения функционирования Программного продукта на принадлежащих Вам ЭВМ. +1.8. Обновление – программа для ЭВМ, предназначенная для модификации Программного продукта и (или) его Компонентов в целях исправления ошибок и (или) улучшения их функциональных возможностей. +1.9. Техническое средство защиты программы – буквенно-цифровой код, необходимый для начала использования программы после установки. +1.10. Почтовый ящик - сущность (виртуальный объект) почтового сервера, предназначенная для получения, хранения и отправки электронных писем пользователем, определяемая его адресом, состоящим из двух частей: имени пользователя (логина) и имени интернет-домена, которые разделяются специальным символом {'@'} (имя_пользователя{'@'}имя_домена). +1.11. Сайт – совокупность веб-страниц, размещенных в сети Интернет, доступных по адресу www.mbk-lab.ru. + +2. СФЕРА ПРИМЕНЕНИЯ СОГЛАШЕНИЯ + +2.1. Соглашение определяет условия, на которых «МБК Лаб» предоставляет Вам право использования ПОЧТОВОГО СЕРВЕРА TEGU PROFESSIONAL/TEGU ENTERPRISE на условиях простой (неисключительной) лицензии. Данные условия также распространяются на Обновления, которые могут быть предоставлены Вам «МБК Лаб». +2.2. Соглашение устанавливает ограничения на использование Вами Компонентов Программного продукта в части, не противоречащей условиям, определенным обладателями исключительных прав на Компоненты Программного продукта. Если на основании условий, определенных правообладателями, Вы обладаете большими правами на использование Компонентов Программного продукта, то применяются условия, определенные правообладателями. Условия использования Компонентов Программного продукта размещены на сайте правообладателей таких Компонентов. +2.3. Состав и условия оказания «МБК Лаб» технической поддержки определяются отдельными соглашениями между Вами и «МБК Лаб». + +3. УСЛОВИЯ ИСПОЛЬЗОВАНИЯ ПРОГРАММНОГО ПРОДУКТА + +3.1. По данному Соглашению Вы приобретаете право использования Программного продукта на условиях простой (неисключительной) лицензии только для использования в собственной хозяйственной деятельности по функциональному назначению. +3.2. Вам предоставляется право: +3.2.1. Установить и использовать экземпляр Программного продукта на одной или нескольких ЭВМ (виртуальных машинах), при этом число почтовых ящиков не должно превышать указанное в документах на приобретение экземпляра Программного продукта. +3.2.2. Использовать Программный продукт на условиях ограничений авторских прав, установленных действующим российским законодательством, в том числе путем создания резервной копии Программного продукта. +3.2.3.Права, прямо не указанные в Соглашении, считаются не предоставленными. +3.2.4.По окончании периода предоставления прав использования Программного продукта Вам следует удалить установленные экземпляры Программного продукта, архивную копию Программного продукта, в случае ее изготовления, либо приобрести право использования Программного продукта на новый срок. +3.3. Вам не предоставляется право: +3.3.1. Позволять третьим лицам использовать Программный продукт или его компоненты на локальных или подключенных к сети Интернет ЭВМ, за исключением случаев, специально оговоренных документами на приобретение права использования Программного продукта. +3.3.2. Осуществлять действия, направленные на снятие ограничений использования Программного продукта, установленных техническими средствами защиты авторского права. +3.3.3. Удалять или изменять информацию об авторском праве на Программный продукт. +3.3.4. Без письменного согласия «МБК Лаб» передавать третьим лицам право использования Программного продукта, приобретенное по Соглашению. +3.3.5. Осуществлять преобразование объектного кода Программного продукта в исходный код. +3.4. «МБК Лаб» может изменить данное Лицензионного соглашения с конечным пользователем или любые его составляющие, обновив его на сайте www.mbk-lab.ru. Изменения Лицензионного соглашения с конечным пользователем распространяются на все права использования Программного продукта, которые приобретаются или продлеваются после даты изменения. + +4. ГАРАНТИЙНЫЕ ОБЯЗАТЕЛЬСТВА + +4.1. Стороны гарантируют наличие у них прав для заключения и исполнения Соглашения. При исполнении обязательств, возникших из Соглашения, Стороны обязуются не нарушать права третьих лиц. +4.2. «МБК Лаб» гарантирует, что на момент вступления Соглашения в действие является обладателем исключительных прав на Программный продукт и обладает достаточными для заключения и исполнения Соглашения правами на все Компоненты Программного продукта. +4.3. «МБК Лаб» гарантирует работу Программного продукта в соответствии с описанием, изложенным в документации, только при условии использования Вами рекомендованных системной аппаратной архитектуры и операционной системы. Перечень рекомендованных к применению системных архитектур и операционных систем опубликован на сайте www.mbk-lab.ru. +4.4. Программный продукт предоставляется на условиях «как есть» (AS IS): «МБК Лаб» не предоставляет никаких гарантий соответствия Программного продукта конкретным целям и ожиданиям, кроме заявленных функциональных характеристик, а также не предоставляет никаких иных гарантий, прямо не указанных в настоящем Соглашении. Вы принимает на себя ответственность за выбор Программного продукта с целью достижения желаемых результатов и в отношении результатов, получаемых в ходе его использования. +4.5. «МБК Лаб» ни при каких условиях не несет ответственности за какие-либо специальные, случайные, прямые или косвенные убытки, понесенные в результате использования Программного продукта. +4.6. Вы соглашаетесь с тем, что Вы несете риск в связи: +4.6.1. с выбором и использованием Программного продукта в собственной хозяйственной деятельности по функциональному назначению. +4.6.2. с внесением любых изменений, разработанных Вами или по Вашему поручению третьими лицами в Программный продукт и его Компоненты. +4.6.3. с использованием Обновлений, предоставленных третьими лицами. + +5. РАЗМЕР ВОЗНАГРАЖДЕНИЯ И СРОК ПЕРЕДАЧИ ПРАВ +5.1. Размер вознаграждения за право использования Программного продукта содержится в документах на приобретение экземпляра Программного продукта. +5.2. Права на использование Программного продукта передаются Вам на срок, определяемый документами на его приобретение и исчисляемый с момента правомерного приобретения экземпляра, но не превышающий срок действия исключительного права на Программный продукт. + +6. КОНФИДЕНЦИАЛЬНОСТЬ + +6.1. Стороны обязуются принять меры по предотвращению случайного или преднамеренного разглашения третьим лицам информации, о конфиденциальности которой Стороны специально уведомили друг друга. Стороны примут все необходимые меры для того, чтобы предотвратить полное или частичное разглашение указанных сведений или ознакомление с ними третьих лиц без взаимной письменной договоренности. +6.2. Обязательства Сторон относительно конфиденциальности информации не распространяются на общедоступную информацию, а также на случаи, когда раскрытие той или иной информации является обязательным в силу требований законодательства. + +7. ОТВЕТСТВЕННОСТЬ СТОРОН + +7.1. В случае предъявления Вам третьим лицом каких-либо претензий или исков, вызванных нарушением прав этого лица в связи с использованием Программного продукта на условиях Соглашения, Вы обязуетесь незамедлительно информировать об этом «МБК Лаб». +7.2. Если Вам стала известна какая-либо информация, указывающая на нарушение авторских прав «МБК Лаб», просим направлять указанную информацию по адресу: mbk{'@'}mbk-lab.ru. +7.3. Если ответственность за неисполнение или ненадлежащее исполнение Сторонами своих обязательств не определена Соглашением, то она устанавливается в соответствии с действующим законодательством Российской Федерации. +7.4. При возникновении обстоятельств непреодолимой силы, при которых Стороны, действующие с разумной осмотрительностью, по независящим от них причинам не могут исполнить обязательства надлежащим образом, сроки исполнения обязательств продлеваются на то время, в течение которого действуют эти обстоятельства. +7.5. Сторона освобождается от ответственности за неисполнение или ненадлежащее исполнение обязательств, если докажет, что надлежащее исполнение обязательств оказалось невозможным вследствие непреодолимой силы, при условии что она незамедлительно известила другую Сторону о таких обстоятельствах и их влиянии на исполнение обязательств, возникших из Соглашения. + +8. ПРЕКРАЩЕНИЕ СОГЛАШЕНИЯ + +«МБК Лаб» в одностороннем порядке может отказаться от исполнения Соглашения в случае использования Вами Программного продукта в целях и/или способами, не предусмотренными Соглашением. + +9. ПОРЯДОК РАЗРЕШЕНИЯ СПОРОВ + +9.1. Правом, подлежащим применению к правам и обязанностям Сторон по Соглашению, является право Российской Федерации. +9.2. Все споры, разногласия или требования, возникающие из настоящего Соглашения или в связи с ним, подлежат разрешению в процессе переговоров Сторон. +9.3. В том случае если переговоры Сторон оказались безуспешными, рассмотрение спора передается в Арбитражный суд г.Москвы. +9.4. При реорганизации одной из Сторон права и обязанности данной Стороны по Соглашению переходят к ее правопреемникам. При ликвидации одной из Сторон или ее правопреемников, к которым перешли права и обязанности данной Стороны по Соглашению, Соглашение прекращает свое действие. +9.5 В случае если компетентный суд признает какое-либо положение настоящего Соглашения недействительным, Соглашение продолжает действовать в остальной части.`, + }, + rus: { + tegu: "Почтовый сервер Tegu", + common: { + not_found: { + page_not_found: "Страница не найдена", + return: "Домой", + }, + save_and_restart: { + confirm_title: "Сохранить настройки?", + confirm_content: "Сервер будет перезапущен", + ok: "Перезапустить сервер", + cancel: "Отмена", + }, + notify: { + error: "Ошибка!", + success: "Успешно!", + warning: "Внимание!", + }, + suffixes: { + mb: "MБ", + sec: "сек", + min: "мин", + hours: "часов", + bits: "бит", + }, + misc: { + copy: "Скопировано в буфер обмена", + ok: "Ок", + cancel: "Отмена", + delete: "Удалить", + edit: "Редактировать", + search: "Поиск", + yes: "Да", + no: "Нет", + save_changes: "Сохранить изменения", + }, + }, + login: { + title: "Логин", + mail: "Email", + empty_mail: "Введите email", + pass: "Пароль", + empty_pass: "Введите пароль", + login: "Логин", + error: "Ошибка авторизации", + }, + shared: { + free_time: { + title: "Свободное время пользователя", + }, + events_external_approval: { + title: "Выбор свободного времени", + title_event_part: " для события ", + subject: "Название", + creator: "Создатель", + message: "Сообщение", + participants: "Участники", + timezone: "Часовой пояс", + send_button: "Отправить информацию об свободном времени", + desc: "Используя мышь (клик или удержание), выберите все подходящие вам временные интервалы.", + success: + "Информация о вашем свободном времени была отправлена создателю события. Как только событие будет подтверждено, вам придет письмо-уведомление.", + }, + }, + user: { + title: "", + top_menu: { + search: "Поиск в контрольной панели пользователя", + logout: "Выйти", + }, + left_menu: { + profile: "Профиль", + rules: "Правила входящих сообщений", + recovery: "Папка восстановления", + shared_folders: "Общие папки", + mailbox_shared_access: "Общий доступ к почтовому ящику", + address_books: "Адресные книги", + address_books_menu: { + my: "Мои книги", + with_access: "Доступные мне", + }, + calendars: "Календари", + calendars_menu: { + my: "Мои календари", + with_access: "Доступные мне", + share_free_time: "Поделиться свободным временем", + events_planner: "Помощник планирования", + }, + }, + }, + admin: { + title: "Панель администратора", + top_menu: { + search: "Поиск в контрольной панели администратора", + control_panel: "Контрольная панель", + documentation: "Документация", + logout: "Выйти", + }, + left_menu: { + dashboard: "Дашборд", + dashboard_aliases: "панель инфо информация статус dns", + settings: "Настройки", + settings_menu: { + main: "Основные", + main_aliases: + "рабочих размер имя порт очередь параллельных обработчиков антиспам антивирус шифрования шифрование мастер защиты защита авторизации авторизация бан бана провалы провалов исключения сертификат версия полный доступ полным доступом пустой отправитель отчётов отчёты миграция миграции inbox imap imaps smtp smtps lmtp ip milter ssl tls greylist dnsbl spf dav carddav caldav", + smtp_queue: "Очередь SMTP", + smtp_queue_menu: { + manage: "Управление", + manage_aliases: + "очередью очередь удалить письма письмо ожидающие повтора", + settings: "Настройки", + settings_aliases: "параметры очереди", + }, + settings_db: "База параметров", + address_change: "Изменения адресов", + address_change_aliases: "переписывание правила", + calendars: "Календари", + calendars_aliases: "caldav dav", + license: "Лицензия", + license_aliases: "eula ключ", + }, + security: "Безопасность", + security_menu: { + blocked_ips: "Заблокированные IP", + blocked_ips_aliases: "разблокировать", + white_list: "Белый список отправителей", + black_list: "Черный список отправителей", + bw_list_menu: { + ip: "IP", + email: "Email", + }, + }, + domains: "Домены", + domains_menu: { + add: "Добавить домен", + mail_storage: "Хранилища почты", + mail_storage_menu: { + mailboxes: "Почтовые ящики", + settings: "Настройки", + other: "Ещё", + other_menu: { + delete: "Удалить хранилище", + }, + }, + users_providers: "Провайдеры БД пользователей", + users_providers_menu: { + add: "Добавить провайдера", + users: "Пользователи", + groups: "Группы", + redirects: "Перенаправления", + settings: "Настройки", + other: "Ещё", + other_menu: { + delete: "Удалить", + delete_success: "Провайдер удален", + delete_title: "Удалить провайдер?", + delete_content: "Провайдер БД пользователей будет удален", + delete_ok: "OK", + delete_cancel: "Отмена", + }, + }, + shared_folders: "Общие папки", + books: "Общие адресные книги", + calendars: "Общие календари", + resources: "Общие ресурсы", + resources_menu: { + resources: "Ресурсы", + categories: "Категории", + offices: "Офисы", + }, + incoming_routing: "Правила входящих сообщений", + outgoing_routing: "Правила исходящих сообщений", + dkim: "DKIM", + migrate: "Миграции", + cidr_access: "Ограничение доступа по CIDR", + cidr_access_menu: { + pools: "Пулы доступа", + policy: "Политики", + }, + other: "Ещё", + other_menu: { + mails_perm_deletion: "Безвозвратное удаление писем", + rename: "Переименовать домен", + rename_exists: "Домен уже существует", + rename_active: "Переименование запущено", + delete: "Удалить домен", + delete_success: "Домен удален", + delete_title: "Удалить домен?", + delete_content: "Домен и все настройки будут удалены", + delete_ok: "OK", + delete_cancel: "Отмена", + }, + }, + }, + }, + components: { + admin: { + dashboard: { + license: { + title: "Почтовый сервер Tegu", + developer: "Разработчик", + version: "Версия", + license: "Лицензия", + license_empty: "Не установлена или отсутствует", + license_mismatch: + "Установленный ключ не соответствует редакции сервера", + }, + mailboxes: { + title: "Почтовые ящики", + license_allowed: "Всего по лицензии", + used: "Размещено на сервере", + remains: "Осталось", + archived: "В архиве", + used_last_month: "Использовано в предыдущий месяц", + used_current_month: "Использовано в текущем месяце", + }, + smtp_queue: { + title: "Очередь SMTP", + type: "Тип", + host: "Хост", + }, + antispam: { + title: "Антиспам/антивирус", + type: "Тип", + status: "Статус", + status_enabled: "Включен", + status_disabled: "Выключен", + host: "Хост", + }, + imap: { + title: "IMAP", + server: "Server", + port: "Port", + encryption: "Шифрование", + auth: "Проверка подлинности", + auth_text: "Простой пароль / Логин", + }, + smtp: { + title: "SMTP", + server: "Server", + port: "Port", + encryption: "Шифрование", + auth: "Проверка подлинности", + auth_text: "Простой пароль / Логин", + }, + dav: { + title: "DAV сервисы", + books: "Строка подключения адресных книг", + calendars: "Строка подключения календарей", + }, + domain: { + mailstorage: "Хранилище почты", + userdb_providers: "Провайдеры БД пользователей", + dns_record: "Рекомендации для зоны DNS", + dns_show: "показать", + dns_copy: "Скопировать в буфер обмена", + }, + }, + settings: { + main: { + main: "Основные", + main_content: { + ServerName: + "Имя сервера (используется в приветствии SMTP и в HELO/EHLO)", + WebInboxCn: + "Понятный псевдоним для папки INBOX (отображается в WEB-панели)", + MsgSizeLimit: "Макс. размер письма в МБ", + Vardir: "Каталог ФС для рабочих данных сервера", + }, + imap: "IMAP", + imap_content: { + IMAPListenIP: "IP, на котором слушать порт IMAP", + IMAPListenPort: "Порт IMAP", + IMAPSListenPort: "Порт IMAPS (SSL)", + IMAPMaxClients: + "Макс. количество одновременных входящих соединений IMAP", + }, + smtp: "SMTP", + smtp_content: { + SMTPListenIP: "IP, на котором слушать порт SMTP", + SMTPListenPort: "Порт SMTP", + SMTPSListenPort: "Порт SMTPS (SSL)", + SMTPMaxClients: + "Макс. количество одновременных входящих соединений SMTP", + }, + lmtp: "LMTP", + lmtp_content: { + LMTPDelivery: + "Включить доставку писем через LMTP (в противном случае будет запущен собственный сервер IMAP", + LMTPHost: "Хост LMTP, с которым будем соединяться", + LMTPPort: "Порт LMTP", + }, + + queue: "Очередь писем", + queue_content: { + QueueConcurrentJobs: + "Число параллельных обработчиков очереди SMTP", + QueueJobTtlMinutes: + "Максимальное время одного прохода обработки очереди SMTP (минут)", + }, + + antispam: "Антиспам/антивирус", + antispam_content: { + MilterScan: + "Включить поддержку антивируса и/или антиспама (протокол milter)", + MilterHostPort: + "Хост и порт milter для подключения к антивирусу/антиспаму (хост:порт)", + MilterNetTimeout: + "Сетевой таймаут ответа антивируса/антиспама (сек)", + SpamScoreMimeHeader: + "Имя заголовка письма для указания количества очков спама (устанавливается антиспамом)", + }, + + auth: "Авторизация", + auth_content: { + MasterUserSep: "Разделитель логина мастер-пользователя", + AllowCrossDomainSharedAccess: + "Разрешать входить в общие ресурсы между доменами (мастер-пользователю в том числе)", + AuthNeedTLS: "Требовать шифрования TLS/SSL для авторизации", + AuthSecurity: "Включить систему защиты авторизации (бан)", + FailedAuthLookupMinutes: + "Время жизни записи о проваленной попытке авторизации (минуты)", + BanTimeMinutes: "Длительность бана (минуты)", + MaxFailedAuthAttempts: + "Макс. количество провалов авторизации до бана", + FailedAuthWhitelist: + "Список исключения IP системы защиты авторизации (192.168.0.1 или 192.168.0.0/24)", + }, + + ssl: "SSL", + ssl_content: { + TLSMinVer: "Минимальная версия TLS для входящих соединений", + SslCert: "Путь до сертификата SSL", + SslKey: "Путь до закрытого ключа SSL", + }, + mail_sending: "Отправка писем", + mail_sending_content: { + RemoteTLSMinVer: + "Минимальная версия TLS для исходящих соединений SMTP", + UseOnlySecureCiphers: "Использовать только безопасные шифры", + SmtpAllowPlainForDomains: + "Домены получателей, для которых разрешена незашифрованная отправка (один на строку)", + SettQueueSendTimeoutSec: + "Максимальное время отправки одного письма (секунды)", + }, + smtp_sessions: "Сессии SMTP", + smtp_sessions_group: { + access: "Доступ", + greylist: "Greylist", + dnsdbl: "DNSBL", + spf: "SPF", + }, + smtp_sessions_content: { + access: { + SmtpAcl: "Включить белые/чёрный списки IP/email отправителей", + FullallowedHosts: + "Список IP с полным доступом (один на строку)", + AllowEmptySenderForFullallowedHosts: + "Разрешить пустой email отправителя для IP с полным доступом", + }, + greylist: { + CheckGreylist: "Включить Greylist", + GreylistSkipDomains: + "Список исключения доменов отправителей для greylist-а (один на строку)", + GreylistRecordLifetimeHours: + "Срок жизни записи серого списка greylist-а (часы)", + WhitelistRecordLifetimeHours: + "Срок жизни записи белого списка greylist-а (часы)", + CleanExpiredGreyrecordsIntervalSec: + "Интервал очистки устаревших записей greylist-а (сек)", + }, + dnsbl: { + CheckDnsbl: "Включить проверки DNSBL", + DnsblListedAtThreshold: + "Количество списков DNSBL в которых найден отправитель для блокировки письма", + }, + spf: { + BlockSpfFailedSenders: + "Блокировать письма, отправители которых не прошли проверку SPF", + AllowSPFNoneOrNeutral: + "Разрешить письма, для отправителей которых записи SPF неправильные, либо отсутствуют", + }, + }, + + dav_services: "DAV-сервисы (адресные книги, календари, файлы...)", + dav_services_content: { + DAVPortHTTP: "Порт HTTP", + DAVPortHTTPS: "Порт HTTPS", + }, + reports: "Отчёты о доставке", + reports_content: { + AllowNotifyExternalUsers: + "Разрешить отправку внешним отправителям отчётов о проблемах доставки", + RetryBeforeNotify: + "Количество попыток доставки, после которых отправителю будет послан отчёт о проблеме", + }, + logging: "Журналирование", + logging_content: { + LogConnOpenClose: + "Журналировать начало и конец сессий (IMAP/SMTP)", + }, + migration: "Миграция с/на другой сервера", + migration_content: { + MigrationMode: "Включить режим миграции с другого сервера", + }, + save: "Сохранить настройки", + }, + settings_db: { + Type: "Тип БД параметров", + ConnParams: { + Host: "Адрес сервера", + Port: "Порт сервера", + Db: "Имя базы данных", + User: "Имя пользователя", + Pass: "Пароль", + MaxConn: "Максимальное количество одновременных подключений", + }, + PathParams: { + DatabaseDir: "Путь до каталога с БД параметров", + }, + save: "Сохранить настройки", + change: "Сменить тип БД и сохранить настройки", + check: "Проверить соединение", + check_error: "Проверка соединения завершилась с ошибкой: ", + check_success: "Проверка соединения успешно завершена", + }, + smtp_queue: { + settings: { + Type: "Тип очереди", + ConnParams: { + Host: "Адрес сервера", + Port: "Порт сервера", + Db: "Имя базы данных", + User: "Имя пользователя", + Pass: "Пароль", + MaxConn: "Максимальное количество одновременных подключений", + MaxQueueItems: "Количество обрабатываемых писем за проход", + }, + PathParams: { + DatabaseDir: "Путь до каталога с файлами Sqlite", + }, + save: "Сохранить настройки", + change: "Сменить тип очереди и сохранить настройки", + check: "Проверить соединение", + check_error: "Проверка соединения завершилась с ошибкой: ", + check_success: "Проверка соединения успешно завершена", + }, + manage: { + total: "Всего писем", + new: "Новые письма", + resend: "Ожидающие повторную отправку", + + clear_filtered: "Удалить найденные", + process_filtered: "Обработать найденные", + clear_all: "Удалить все", + delete_awaiting_resend: "Удалить все ожидающие повтора", + delete_awaiting_resend_filter: + "Удалить найденные ожидающие повтора", + process_awaiting_resend: "Обработать все ожидающие повтора", + + process_now: "Обработать немедленно", + delete: "Удалить", + column_sender: "Отправитель", + column_receiver: "Получатель", + column_added: "Добавлено в очередь", + column_will_resend: "Будет обработано", + column_will_resend_now: "Сейчас", + ok: "ОК", + cancel: "Отмена", + search: "Найти письмо", + }, + }, + license: { + no_install: "Лицензия не установлена", + accept: "Принять соглашение", + title: "Информация о лицензии", + id: "Идентификатор лицензии", + edition: "Редакция Tegu", + valid_till: "Действие лицензии по времени", + valid_forever: "Не ограничено", + max_mailbox_count: "Максимальное количество почтовых ящиков", + send_report: "Отправлять отчет", + send_report_no: "Нет", + customer_name: "Наименование покупателя", + customer_type: "Тип покупателя", + customer_data: "Данные покупателя", + show_eula: "Показать лицензионное соглашение", + load: "Загрузить файл лицензии", + fiz_type: "Физ. лицо", + ur_type: "Юр. лицо", + }, + calendars: { + freebusy: "Доступ к Free/Busy по умолчанию", + showfrom: "Не отображать события старше N недель", + showto: "Не отображать события новее N недель", + localpart: + "Локальная часть (до {'@'}) адреса отправителя оповещений", + success: "Настройки сохранены", + save: "Сохранить настройки", + }, + }, + security: { + blocked_ips: { + unblock: "Разблокировать", + unblock_all: "Разблокировать все", + search: "Найти IP", + unblock_found: "Разблокировать найденные", + ip: "IP", + }, + bw_list_email: { + delete: "Удалить", + delete_all: "Удалить все", + delete_found: "Удалить найденные", + email: "Email", + add_email: "Добавить email в список", + add: "Добавить", + add_email_placeholder: "Email", + search: "Найти email", + }, + bw_list_ip: { + delete: "Удалить", + delete_all: "Удалить все", + delete_found: "Удалить найденные", + ip: "IP", + add_ip: "Добавить IP в список", + add: "Добавить", + add_ip_placeholder: "IP", + search: "Найти IP", + }, + }, + domains: { + add: { + Domain: "Новый домен", + Type: "Тип хранилища", + create: "Добавить домен", + success: "Домен добавлен", + }, + mailstorage: { + mailboxes: { + search: "Найти почтовый ящик", + storage_filter: "Все хранилища", + clear_recovery_all: "Очистить все RECOVERY", + clear_recovery_found: "Очистить найденные RECOVERY", + delete_all: "Удалить все почтовые ящики", + delete_found: "Удалить найденные почтовые ящики", + delete: "Удалить", + clear_recovery: "Очистить RECOVERY", + change_storage: "Сменить хранилище", + change_storage_for: "Сменить хранилище для ", + change: "Сменить", + archive: "Заблокировать", + unarchive: "Разблокировать", + in_archive: "Ящик заблокирован", + deleted: "Ящик удалён", + export: "Выгрузка", + ok: "OK", + cancel: "Отмена", + col_email: "Email ящика", + col_msg_count: "Кол-во писем", + col_size: "Размер ящика", + col_quota: "Квота", + col_quota_used: "Использовано", + col_recovery_size: "Размер RECOVERY", + col_table_prefix: "Префикс таблиц ящика", + col_table_access_key: "Хранилище", + col_actions: "Действия", + rename: "Переименовать", + rename_exists: "Такой ящик уже существует", + }, + export: { + title: "Выгрузка почтового ящика", + catalog: "Каталог выгрузки", + hostname: "Хост выгрузки", + start_export: "Начать выгрузку", + success: "Выгрузка завершена. Длительность: ", + }, + settings: { + panel_connect: "Настройки подключения", + panel_multi: "Мульти-хранилище", + panel_additional: "Дополнительные настройки", + + multi_storage: { + conns_nums: "подключений", + col_access_key: "Уникальный ключ подключения", + col_hostport: "Адрес:порт", + mailbox_distribution_pattern: "Паттерн распределения ящиков", + add_connect: "Добавить подключение", + edit_access_key: "Редактировать ключ подключения", + save: "Сохранить", + edit_connect: "Редактировать подключение", + save_connect: "Сохранить", + delete_action: "Удалить", + edit_action: "Редактировать", + }, + + Type: "Тип хранилища", + Host: "Адрес сервера", + Port: "Порт сервера", + MboxesDb: "Имя базы данных", + User: "Имя пользователя", + Pass: "Пароль", + MaxConn: "Максимальное количество одновременных подключений", + MailDirRoot: "Корневой каталог почтовых ящиков", + IMAPDefaultFolders: { + Archive: "Архивная папка", + Drafts: "Папка черновиков", + Junk: "Папка спама", + Sent: "Папка отправленных", + Trash: "Папка корзины", + SharedRoot: "Корневая папка общих папок", + Recovery: "Папка восстановления", + }, + SmartHost: "Смартхост", + SmartHostFormat: `user:pass{'@'}host:port или host:port`, + RecoveryEnabled: "Включить папку восстановления", + DefaultUserQuota: "Квота по умолчанию, МБ", + TrashAdditionalQuota: "Дополнительная квота для корзины, МБ", + QuotaNotifyThreshold: "Уведомление после заполнения ящика, %", + + change: "Сменить тип хранилища и сохранить настройки", + save: "Сохранить настройки", + save_success: "Настройки сохранены", + check: "Проверить соединение", + check_error: "Проверка соединения завершилась с ошибкой: ", + check_success: "Проверка соединения успешно завершена", + }, + }, + userdb: { + add: { + Name: "Название", + Type: "Тип провайдера", + create: "Добавить провайдер", + success: "Провайдер добавлен", + }, + users: { + col_name: "Пользователь", + col_email: "Email", + add: "Добавить пользователя", + edit: "Редактировать", + delete: "Удалить", + ok: "OK", + cancel: "Отмена", + add_modal: { + display_name: "Полное имя", + email: "Email", + alt_emails: "Дополнительные адреса email", + quota: "Квота", + password: "Пароль", + password_again: "Повтор пароля", + cancel: "Отмена", + save: "Сохранить", + }, + }, + redirects: { + col_name: "Пользователь", + col_email: "Email", + add: "Добавить перенаправление", + edit: "Редактировать", + delete: "Удалить", + ok: "OK", + cancel: "Отмена", + add_modal: { + name: "Название", + email: "Email", + destinations: "Email'ы назначения", + cancel: "Отмена", + save: "Сохранить", + }, + }, + groups: { + col_name: "Группа", + col_email: "Email", + col_users_count: "Кол-во участников", + col_group_count: "Кол-во групп", + add: "Добавить группу", + edit: "Редактировать", + members: "Участники", + delete: "Удалить", + ok: "OK", + cancel: "Отмена", + add_modal: { + name: "Name", + email: "Email", + alt_emails: "Дополнительные адреса email", + cancel: "Отмена", + save: "Сохранить", + }, + }, + settings: { + Name: "Название провайдера", + UseInGal: "Использовать источник в Глобальной адресной книге ", + Dir: "Путь до каталога БД пользователей", + MasterUsersGroup: "Название группы мастер-пользователей", + CacheTTL: "TTL кэша (секунды)", + + ConnectionGroup: "Подключения", + ConnectURIs: "Строки подключения LDAP (по одной на строку)", + ConnectBindDN: "BindDN", + ConnectPassword: "Пароль", + ConnectBaseDN: "Base DN", + ConnectTLSMinVer: + "Минимальная версия TLS для исходящих соединений", + + UserGroup: "Пользователи", + UserObjectclass: "objectClass for user", + UserMailAttr: "Attr for mailbox e-mail", + UserQuotaAttr: "Attr for mailbox quota (value in MB)", + MemberofAttr: "User memberOf attr", + UserAddSearchFilter: "Additional user search filter", + + GroupsGroup: "Группы", + EmailGroups: "Use groups", + GroupObjectclass: "objectClass for group", + GroupNameAttr: "Attr for group name", + GroupMailAttr: "Attr for group email", + GroupMemberAttr: "Attr for group members", + GroupMemberDn: "Group member attr contains DN", + UserRDNAttr: "Attr for user RDN", + GroupAddSearchFilter: "Additional group search filter", + + RedirectGroup: "Aliases (перенаправления)", + EmailRedirect: "Use mailbox alias (redirect list)", + AliasObjectclass: "objectClass for alias", + AliasMailAttr: "Attr for alias email", + AliasRedirectAttr: "Attr for email redirect to", + + AltEmailGroup: "Дополнительные emails", + EmailAlternate: "Use mailbox alternative email", + AlternateMailAttr: "Attr for mailbox alternative email", + + MasterGroup: "Мастер-пользователи", + MasterUserGroupNameAttr: "Attr for group name of master-users", + MasterUserGroup: "Group name of master-users", + + GALGroup: "Глобальная адресная книга (GAL)", + GALCacheTTL: "GAL Cache TTL (minutes)", + GALObjectsFilter: "GAL objects filter", + + GALUserGroup: "Пользователи", + GALUserNameAttr: "GAL attr for user name", + GALUserEmailAttr: "GAL attr for user email", + GALUserAltEmailAttr: "GAL attr for alternative user email", + GALUserPhoneAttr: "GAL attr for user phone", + GALUserPhotoAttr: "GAL attr for user photo", + GALUserBirthdayAttr: "GAL attr for user birthday", + GALUserAddressAttr: "GAL attr for user address", + GALUserOrganizationAttr: "GAL attr for user organization", + GALUserRoleAttr: "GAL attr for user role", + + GALGroupsGroup: "Группы", + GALGroupNameAttr: "GAL attr for group name", + GALGroupEmailAttr: "GAL attr for group email", + + GALAliasesGroup: "Aliases", + GALAliasNameAttr: "GAL attr for alias name", + GALAliasEmailAttr: "GAL attr for alias email", + + change: "Сменить тип провайдера и сохранить настройки", + save: "Сохранить настройки", + save_success: "Настройки сохранены", + check: "Проверить соединение", + check_email: "Email для проверки", + check_error: "Проверка соединения завершилась с ошибкой: ", + check_success: "Проверка соединения успешно завершена", + }, + }, + cidr_access: { + pools: { + col_name: "Имя", + delete: "Удалить", + delete_found: "Удалить найденные", + delete_all: "Удалить все", + properties: "Свойства", + update_pool: "Обновить пул доступа", + add_pool: "Добавить пул доступа", + add_name: "Имя", + add_ips: "Список CIDR", + add_ips_placeholder: + "Один IP на строку (127.0.0.1 или 127.0.0.1/16)", + ok: "ОК", + cancel: "Отмена", + search: "Поиск пула доступа", + }, + + policy: { + enabled: "Включить ограничение доступа по CIDR", + col_name: "Группа", + col_count: "Активные пулы доступа", + delete: "Удалить", + delete_found: "Удалить найденные", + delete_all: "Удалить все", + properties: "Настроить доступ", + add_policy: "Добавить политику доступа для группы", + select_group: "Выберите группу", + update_policy: "Обновить политику доступа для ", + ok: "ОК", + cancel: "Отмена", + search: "Найти группу", + }, + }, + resources: { + offices: { + col_name: "Название", + col_timezone: "Часовой пояс", + add_office: "Добавить офис", + edit_office: "Редактировать офис", + create_success: "Офис создан", + update_success: "Офис обновлен", + delete_success: "Офис удален", + }, + categories: { + col_name: "Название", + col_office_bind: "Привязка к офису", + col_script: "Скрипт", + add_category: "Добавить категорию", + edit_category: "Редактировать категорию", + create_success: "Категория создана", + update_success: "Категория обновлена", + delete_success: "Категория удалена", + }, + resources: { + col_name: "Название", + col_category: "Категория", + col_script: "Скрипт", + col_office: "Офис", + col_show_time_as: "Показывать время как", + time_busy: "Занятое", + time_free: "Свободное", + add_resource: "Добавить ресурс", + edit_resource: "Редактировать ресурс", + check_script: "Проверить скрипт", + check_script_good: "Ошибок не найдено", + any_category: "Любая категория", + any_office: "Любой офис", + create_success: "Ресурс создан", + update_success: "Ресурс обновлен", + delete_success: "Ресурс удален", + }, + }, + dkim: { + title: "TXT-запись для зоны DNS", + delete: "Удалить", + delete_success: "DKIM удален", + selector: "Селектор", + key_size: "Размер ключа в битах", + create: "Создать DKIM", + success: "DKIM создан", + }, + migration: { + enabled: "Включить режим миграций для этого домена", + virtual_domain: "Виртуальный домен", + other_servers: + "Другие серверы домена (хост:порт - по одному на строку)", + local_emails: "Адреса локальных ящиков (по одному на строку)", + save: "Сохранить настройки", + success: "Настройки сохранены", + }, + mails_perm_deletion: { + filter: "Фильтр писем", + found: "Писем найдено", + find: "Найти письма", + delete: "Удалить найденные письма: ", + delete_text: "Письма будут безвозвратно удалены", + success: "Письма были безвозвратно удалены", + ok: "Удалить", + cancel: "Отмена", + }, + }, + }, + user: { + profile: { + mailbox: { + title: "Почтовый ящик", + user: "Email", + size: "Размер", + count: "Кол-во писем", + }, + imap: { + title: "IMAP", + server: "Server", + port: "Port", + encryption: "Шифрование", + auth: "Проверка подлинности", + auth_text: "Простой пароль / Логин", + auth_login: "Логин/Имя пользователя", + }, + smtp: { + title: "SMTP", + server: "Server", + port: "Port", + encryption: "Шифрование", + auth: "Проверка подлинности", + auth_text: "Простой пароль / Логин", + auth_login: "Логин/Имя пользователя", + }, + dav: { + title: "DAV сервисы", + books: "Строка подключения адресных книг", + calendars: "Строка подключения календарей", + login: "Логин/Имя пользователя", + }, + }, + recovery: { + show: "Отображать папку восстановления", + save: "Сохранить настройки", + success: "Настройки сохранены", + }, + mailbox_shared_access: { + search: "Поиск", + col_name: "Доступ для", + type_email: "Пользователи", + type_email_placeholder: "Email", + type_email_add: "Дать доступ пользователю", + type_group_add: "Дать доступ группе", + add: "Дать доступ", + type_group: "Группы", + delete: "Удалить", + delete_found: "Удалить найденные", + delete_all: "Удалить все", + ok: "ОК", + cancel: "Отмена", + }, + address_books: { + with_access: { + col_name: "Название", + col_owner: "Владелец", + col_permission: "Доступ", + search: "Найти адресные книги", + }, + }, + calendars: { + with_access: { + col_name: "Название", + col_owner: "Владелец", + col_permission: "Доступ", + search: "Найти календари", + }, + share_free_time: { + timezone: "Часовой пояс", + work_days: "Рабочие дни", + work_days_names: { + monday: "Понедельник", + tuesday: "Вторник", + wednesday: "Среда", + thursday: "Четверг", + friday: "Пятница", + saturday: "Суббота", + sunday: "Воскресенье", + }, + work_hours: "Рабочие часы", + time_between_events: "Перерыв между событиями", + two_month_restriction: + "Делиться свободным временем не больше 2ух месяцев", + gen_link: "Сгенерировать новую ссылку доступа", + gen_link_success: "Ссылка обновлена", + }, + events_planner: { + my_events: { + search: "Найти событие", + col_name: "Название", + col_start: "Начало", + col_finish: "Конец", + col_participants: "Кол-во участников", + status_under_approval: "На согласовании", + status_approval_done: "Согласование завершено", + new_event: "Новое событие", + approval_with_ft: "Участники, указавшие свободное время", + approval_without_ft: "Участники, не указавшие свободное время", + }, + script_error_notify: { + title: "Ошибка выполнения скрипта", + resource_name: "Название ресурса", + error: "Ошибка", + output: "Вывод скрипта", + script: "Текст скрипта", + }, + new_edit: { + subject: "Название", + subject_placeholder: "Название события", + message: "Сообщение", + message_placeholder: "Пригласительное сообщение", + participants: "Участники (по одному на строку)", + include_creator: "Добавить меня в качестве участника", + first_avaliable: "Первый свободный", + mandatory: "Обязательные email`ы", + optional: "Опциональные email`ы", + duration: "Длительность", + duration_type: { + mins: "минута", + hours: "час", + days: "день", + weeks: "неделя", + months: "месяц", + }, + resources: "Ресурсы", + start: "Время начала", + time_not_selected: "Время не выбрано", + find_time: { + title: "Выбрать свободное время", + start_search: "Начать поиск", + search_from: "Искать от", + depth: "Глубина поиска", + selected_day: "Выбранный день", + selected_time: "Выбранное время", + not_found: "Свободное время не найдено", + depth_values: { + day: "День", + week: "Неделя", + month: "Месяц", + }, + select_and_create_button: "Выбрать время и создать событие", + select_and_update_button: "Выбрать время и обновить событие", + choose_time_button: "Отправить на согласование времени", + choose_time_desc_part_1: + "В участниках присутствуют внешние пользователи. Доступна возможность отправить событие на согласование и собрать информацию о свободном времени.", + choose_time_desc_part_2: + "Внешние участники без информации о свободном времени: ", + choose_time_desc_part_3: + "Для всех внешних участников есть информация о свободном времени", + choose_time_text_1: + "Отправить запрос на согласование времени следующим участникам:", + choose_time_text_2: + "Каждый участник должен ответить на запрос в течение этого времени:", + choose_time_text_3: + "Вы получите уведомление после полного сбора свободного времени от всех участников, либо по истечению времени выше.", + choose_time_interval: "Время ожидания", + choose_time_and_create_button: + "Отправить на согласование времени и создать событие", + choose_time_and_update_button: + "Отправить на согласование времени и обновить событие", + }, + reset_warning: + "Время события было сброшено. Выполните поиск свободного времени ещё раз", + update_button: "Обновить событие", + update_success: "Событие обновлено", + create_success: "Событие создано", + }, + }, + }, + }, + common: { + rules: { + col_enabled: "Включено", + col_name: "Название", + col_action: "Порядок", + add_rule: "Добавить правило", + save_rule: "Сохранить правило", + edit_rule: "Редактировать правило", + delete_rule: "Удалить правило", + ok: "ОК", + cancel: "Отмена", + edit_name: "Название", + edit_conditions: "Условия", + edit_conditions_all: "Все", + edit_conditions_any: "Любые", + edit_actions: "Действия", + add_condition: "Добавить условие", + add_action: "Добавить действие", + delete: "Удалить", + + incoming: { + conditions: { + op_equal: "равно", + op_less: "меньше", + op_greater: "больше", + op_not_equal: "не равно", + op_starts: "начинается с", + op_ends: "заканчивается на", + op_contains: "содержит", + op_not_contains: "не содержит", + op_greater_or_equal: "больше или равно", + op_less_or_equal: "меньше или равно", + + date: "Дата", + to: "Кому", + from: "От кого", + header_to: "Заголовок 'Кому'", + header_from: "Заголовок 'От кого'", + subject: "Тема", + copy_recipient: "Получатель копии", + size: "Размер", + spam_score: "Кол-во очков спама", + body: "Тело письма", + all: "Все письма", + }, + actions: { + to_folder: "Положить в папку", + copy_to_folder: "Копировать в папку", + mark_as_seen: "Отметить как прочтенное", + mark_as_flagged: "Отметить флагом", + redirect_to: "Перенаправить на", + copy_to: "Отправить копию на", + reply_msg: "Ответить сообщением", + reject: "Отклонить", + stop: "Остановить обработку правил", + }, + }, + outgoing: { + conditions: { + op_contains: "содержит", + op_not_contains: "не содержит", + op_equal: "равно", + op_not_equal: "не равно", + op_starts: "начинается с", + op_ends: "заканчивается на", + + from: "От кого", + to: "Кому", + from_group: "Группа отправителя", + to_group: "Группа получателя", + body: "Тело письма", + subject: "Тема", + all: "Все письма", + }, + actions: { + transform_from_address: "Преобразовать адрес отправителя", + transform_to_address: "Преобразовать адрес получателя", + transform_from_address_and_header: + "Преобразовать адрес отправителя и заголовок 'From'", + transform_to_address_and_header: + "Преобразовать адрес получателя и заголовок 'To'", + copy_to: "Добавить копию сообщения", + premoderation: "Отправить на премодерацию", + send_via_smart_host: "Отправить через смарт-хост", + add_text_to_start: "Добавить текст в начало тела письма", + add_text_to_end: "Добавить текст в конец тела письма", + + reject_external: "Запретить доставку внешним пользователям", + reject_external_count: + "Запретить доставку больше N писем внешним пользователям в день", + reject_internal_count: + "Запретить доставку больше N писем внутренним пользователям в день", + reject_groups: "Запретить доставку группе", + reject_in_group: "Запретить доставку участникам группы", + reject_any: "Запретить доставку", + allow_external: "Разрешить доставку внешним пользователям", + allow_groups: "Разрешить доставку группе", + allow_in_group: "Разрешить доставку участникам группы", + allow_any: "Разрешить доставку", + send_response: + "Уведомить отправителя сообщением при срабатывании правила", + send_response_default: + "Ваше сообщение было изменено или заблокировано почтовым сервисом.", + add_text_default: "Текст для добавления", + }, + }, + address: { + conditions: { + op_contains: "содержит", + op_not_contains: "не содержит", + op_equal: "равно", + op_not_equal: "не равно", + op_starts: "начинается с", + op_ends: "заканчивается на", + + from: "От кого", + to: "Кому", + from_group: "Группа отправителя", + to_group: "Группа получателя", + all: "Все письма", + }, + actions: { + transform_from_address: "Преобразовать адрес отправителя", + transform_to_address: "Преобразовать адрес получателя", + }, + }, + }, + shared_folders: { + root_folder: "Корневая папка", + col_folder: "Название", + col_owner: "Владелец", + + edit_access: "Доступы", + delete: "Удалить", + delete_found: "Удалить найденные", + delete_all: "Удалить все", + add_folder: "Добавить папку", + add_name: "Название", + ok: "ОК", + cancel: "Отмена", + search: "Поиск в ", + + access_search: "Поиск", + access_col_name: "Доступ для", + access_type_email: "Пользователи", + access_type_email_placeholder: "Email", + access_type_email_add: "Дать доступ пользователю", + access_type_group_add: "Дать доступ группе", + access_add: "Дать доступ", + access_type_group: "Группы", + }, + shared_address_books: { + col_name: "Название", + edit_access: "Доступы", + delete: "Удалить", + delete_found: "Удалить найденные", + delete_all: "Удалить все", + properties: "Свойства", + update_book: "Обновить адресную книгу", + add_book: "Добавить адресную книгу", + add_name: "Название", + ok: "ОК", + cancel: "Отмена", + search: "Найти адресные книги", + + access_search: "Поиск", + access_col_name: "Доступ для", + access_col_permissions: "Доступ", + access_perm_all: "Полный доступ", + access_perm_read: "Только чтение", + access_type_email: "Пользователи", + access_type_email_placeholder: "Email", + access_type_email_add: "Дать доступ пользователю", + access_type_group_add: "Дать доступ группе", + access_add: "Дать доступ", + access_type_group: "Группы", + }, + shared_calendars: { + col_name: "Название", + edit_access: "Доступы", + edit_cal_access: "Доступы", + delete: "Удалить", + delete_found: "Удалить найденные", + delete_all: "Удалить все", + properties: "Свойства", + update_calendar: "Обновить календарь", + add_calendar: "Добавить календарь", + add_name: "Название", + add_freebusy: + "Предоставлять информацию о занятом времени (Free/Busy)", + add_showfrom: "Не отображать события старше N недель", + add_showto: "Не отображать события новее N недель", + add_color: "Цвет", + ok: "ОК", + cancel: "Отмена", + search: "Найти календари", + + access_search: "Поиск", + access_col_name: "Доступ для", + access_col_permissions: "Доступ", + access_perm_all: "Полный доступ", + access_perm_read: "Только чтение", + access_type_email: "Пользователи", + access_type_email_placeholder: "Email", + access_type_email_add: "Дать доступ пользователю", + access_type_group_add: "Дать доступ группе", + access_add: "Дать доступ", + access_type_group: "Группы", + + add_success: "Доступ выдан", + update_success: "Доступ обновлен", + remove_success: "Доступ удален", + }, + }, + }, + }, +}; diff --git a/frontend/src/main.ts b/frontend/src/main.ts index f9754fe..05c81d9 100644 --- a/frontend/src/main.ts +++ b/frontend/src/main.ts @@ -1,5 +1,49 @@ -import {createApp} from 'vue' -import App from './App.vue' -import './style.css'; +import "./assets/main.css"; -createApp(App).mount('#app') +import { createApp, nextTick } from "vue"; +import { createPinia } from "pinia"; +import i18n from "@/locale"; +import piniaPluginPersistedState from "pinia-plugin-persistedstate"; + +import App from "./App.vue"; +import router from "@/router"; + +const app = createApp(App); + +const pinia = createPinia(); +pinia.use(piniaPluginPersistedState); + +app.use(pinia); +app.use(i18n); +app.use(router); + +app.use({ + install(Vue) { + Vue.mixin({ + mounted() { + this.disableAutoComplete(); + }, + + methods: { + disableAutoComplete() { + let elements = document.querySelectorAll('[autocomplete="off"]'); + + if (!elements) { + return; + } + + elements.forEach((element) => { + element.setAttribute("readonly", "readonly"); + nextTick(() => { + setTimeout(() => { + element.removeAttribute("readonly"); + }, 100); + }); + }); + }, + }, + }); + }, +}); + +app.mount("#app"); diff --git a/frontend/src/router/consts.ts b/frontend/src/router/consts.ts new file mode 100644 index 0000000..5557166 --- /dev/null +++ b/frontend/src/router/consts.ts @@ -0,0 +1,98 @@ +export const RouteLogin = "/"; + +export const RouteShared = "/sh"; +export const TokenPlaceholder = ":token"; +export const RouteSharedFreeTime = `/sh/ft/${TokenPlaceholder}`; +export const RouteEventsExternalApproval = `/sh/ev/ap/${TokenPlaceholder}`; + +export const RouteAdmin = "/admin"; +export const RouteAdminDashboard = "/admin/dashboard"; + +export const RouteAdminSettings = "/admin/settings"; +export const RouteAdminSettingsMain = "/admin/settings/main"; +export const RouteAdminSettingsSMTPQueue = "/admin/settings/smtp_queue"; +export const RouteAdminSettingsSMTPQueueSettings = + "/admin/settings/smtp_queue/settings"; +export const RouteAdminSettingsSMTPQueueManage = + "/admin/settings/smtp_queue/manage"; +export const RouteAdminSettingsSettingsDB = "/admin/settings/settings_db"; +export const RouteAdminSettingsAddressChange = "/admin/settings/address_change"; +export const RouteAdminSettingsCalendars = "/admin/settings/calendars"; +export const RouteAdminSettingsLicense = "/admin/settings/license"; + +export const RouteAdminSecurity = "/admin/security"; +export const RouteAdminSecurityBlockedIps = "/admin/security/blocked_ips"; +export const RouteAdminSecurityWhiteList = "/admin/security/white_list"; +export const RouteAdminSecurityWhiteListIp = "/admin/security/white_list/ip"; +export const RouteAdminSecurityWhiteListEmail = + "/admin/security/white_list/email"; +export const RouteAdminSecurityBlackList = "/admin/security/black_list"; +export const RouteAdminSecurityBlackListIp = "/admin/security/black_list/ip"; +export const RouteAdminSecurityBlackListEmail = + "/admin/security/black_list/email"; + +export const RouteAdminDomains = "/admin/domains"; +export const DomainPlaceholder = ":domain"; +export const UserdbPlaceholder = ":sid"; +export const RouteAdminDomainsAdd = `/admin/domains/add`; +export const RouteAdminDomainsDomain = `/admin/domains/${DomainPlaceholder}`; +export const RouteAdminDomainsDomainMailStorage = `/admin/domains/${DomainPlaceholder}/mailstorage`; +export const RouteAdminDomainsDomainMailStorageMailboxes = `/admin/domains/${DomainPlaceholder}/mailstorage/mailboxes`; +export const MailboxPlaceholder = ":mailbox"; +export const RouteAdminDomainsDomainMailStorageMailboxesExport = `/admin/domains/${DomainPlaceholder}/mailstorage/mailboxes/${MailboxPlaceholder}/export`; +export const RouteAdminDomainsDomainMailStorageSettings = `/admin/domains/${DomainPlaceholder}/mailstorage/settings`; +export const RouteAdminDomainsDomainUserDB = `/admin/domains/${DomainPlaceholder}/userdb`; +export const RouteAdminDomainsDomainUserDBAdd = `/admin/domains/${DomainPlaceholder}/userdb/add`; +export const RouteAdminDomainsDomainUserDBProvider = `/admin/domains/${DomainPlaceholder}/userdb/${UserdbPlaceholder}`; +export const RouteAdminDomainsDomainUserDBProviderUsers = `/admin/domains/${DomainPlaceholder}/userdb/${UserdbPlaceholder}/users`; +export const RouteAdminDomainsDomainUserDBProviderGroups = `/admin/domains/${DomainPlaceholder}/userdb/${UserdbPlaceholder}/groups`; +export const RouteAdminDomainsDomainUserDBProviderRedirects = `/admin/domains/${DomainPlaceholder}/userdb/${UserdbPlaceholder}/redirects`; +export const RouteAdminDomainsDomainUserDBProviderSettings = `/admin/domains/${DomainPlaceholder}/userdb/${UserdbPlaceholder}/settings`; +export const RouteAdminDomainsDomainUserDBProviderOther = `/admin/domains/${DomainPlaceholder}/userdb/${UserdbPlaceholder}/other`; +export const RouteAdminDomainsDomainSharedFolders = `/admin/domains/${DomainPlaceholder}/shared_folders`; +export const RouteAdminDomainsDomainAddressBooks = `/admin/domains/${DomainPlaceholder}/address_books`; +export const RouteAdminDomainsDomainCalendars = `/admin/domains/${DomainPlaceholder}/calendars`; + +export const RouteAdminDomainsDomainResources = `/admin/domains/${DomainPlaceholder}/resources`; +export const RouteAdminDomainsDomainResourcesList = `/admin/domains/${DomainPlaceholder}/resources/list`; +export const RouteAdminDomainsDomainResourcesOffices = `/admin/domains/${DomainPlaceholder}/resources/offices`; +export const RouteAdminDomainsDomainResourcesCategories = `/admin/domains/${DomainPlaceholder}/resources/categories`; + +export const RouteAdminDomainsDomainIncRules = `/admin/domains/${DomainPlaceholder}/incoming_rules`; +export const RouteAdminDomainsDomainOutRules = `/admin/domains/${DomainPlaceholder}/outgoing_rules`; +export const RouteAdminDomainsDomainDKIM = `/admin/domains/${DomainPlaceholder}/dkim`; +export const RouteAdminDomainsDomainMigration = `/admin/domains/${DomainPlaceholder}/migration`; +export const RouteAdminDomainsDomainCIDRAccess = `/admin/domains/${DomainPlaceholder}/cidr_access`; +export const RouteAdminDomainsDomainCIDRAccessPools = `/admin/domains/${DomainPlaceholder}/cidr_access/pools`; +export const RouteAdminDomainsDomainCIDRAccessPolicy = `/admin/domains/${DomainPlaceholder}/cidr_access/policy`; +export const RouteAdminDomainsDomainOther = `/admin/domains/${DomainPlaceholder}/other`; +export const RouteAdminDomainsDomainOtherMailsPermDeletion = `/admin/domains/${DomainPlaceholder}/other/mails_perm_deletion`; + +export const RouteUser = "/user"; +export const RouteUserProfile = "/user/profile"; +export const RouteUserRules = "/user/rules"; +export const RouteUserRecovery = "/user/recovery"; +export const RouteUserMailboxSharedAccess = "/user/mailbox_shared_access"; +export const RouteUserSharedFolders = "/user/shared_folders"; + +export const RouteUserAddressBooks = "/user/address_books"; +export const RouteUserAddressBooksMy = "/user/address_books/my_books"; +export const RouteUserAddressBooksAvaliableToMe = + "/user/address_books/avaliable_to_me"; + +export const RouteUserCalendars = "/user/calendars"; +export const RouteUserCalendarsMy = "/user/calendars/my_calendars"; +export const RouteUserCalendarsAvaliableToMe = + "/user/calendars/avaliable_to_me"; +export const RouteUserCalendarsShareFreeTime = + "/user/calendars/share_free_time"; + +export const RouteUserCalendarsEventsPlanner = "/user/calendars/events_planner"; +export const RouteUserCalendarsEventsPlannerList = + "/user/calendars/events_planner/my_events"; +export const RouteUserCalendarsEventsPlannerNew = + "/user/calendars/events_planner/new"; + +export const EventIdPlaceholder = ":event_id"; + +export const RouteUserCalendarsEventsPlannerEdit = `/user/calendars/events_planner/${EventIdPlaceholder}/edit`; diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts new file mode 100644 index 0000000..63f2b90 --- /dev/null +++ b/frontend/src/router/index.ts @@ -0,0 +1,105 @@ +import { + createRouter, + createWebHistory, + type RouteRecordRaw, +} from "vue-router"; +import { pipeline } from "@/router/middleware/pipeline"; +import { useAuthStore } from "@/stores/auth"; +import { + RouteAdmin, + RouteAdminDashboard, + RouteLogin, + RouteShared, + RouteUser, + RouteUserProfile, +} from "./consts"; +import routes from "@/router/routes"; +import { nextTick } from "vue"; +import i18n from "@/locale"; +import { useReturnToPageStore } from "@/stores/returnToPage"; + +const router = createRouter({ + history: createWebHistory(import.meta.env.BASE_URL), + routes: routes as RouteRecordRaw[], +}); + +router.beforeEach((to, from, next) => { + let path = to.path; + if (!to) { + path = location.pathname; + } + + if (!path.startsWith(RouteShared)) { + if (to.name !== RouteLogin) { + if (!useAuthStore().authed) { + useReturnToPageStore().setPath(path, to.query); + return next({ name: RouteLogin }); + } + if (useAuthStore().isAdmin && !to.path.startsWith(RouteAdmin)) { + return next({ name: RouteAdminDashboard }); + } + if (!useAuthStore().isAdmin && !to.path.startsWith(RouteUser)) { + return next({ name: RouteUserProfile }); + } + } + } + + if (!to.meta.middleware) { + return next(); + } + const middleware = Array.isArray(to.meta.middleware) + ? to.meta.middleware + : [to.meta.middleware]; + + const context = { + to, + from, + next, + }; + + return middleware[0](pipeline(context, middleware, 1), context); +}); + +router.afterEach((to, from) => { + // Use next tick to handle router history correctly + // see: https://github.com/vuejs/vue-router/issues/914#issuecomment-384477609 + nextTick(() => { + let title = to.meta.title as string; + if (!title) { + if (to.path.startsWith("/admin")) { + title = i18n.global.t("admin.title"); + } else if (to.path.startsWith("/user")) { + if (useAuthStore().username) { + title = useAuthStore().username; + } else { + title = i18n.global.t("user.title"); + } + } + } + + if (title) { + title = title + " - " + i18n.global.t("tegu"); + } + document.title = title || "Tegu"; + }); + + if (to.hash === "#refresh") { + router.replace({ hash: "" }).then(() => { + router.go(0); + }); + return; + } + + if (to.query.redirect) { + let redirect = to.query.redirect as string; + let parts = redirect.split("?"); + router.push(parts[0]); + + useReturnToPageStore().setPath( + parts[0], + Object.fromEntries(new URLSearchParams(parts[1])) + ); + } +}); + +export default router; diff --git a/frontend/src/router/middleware/log.ts b/frontend/src/router/middleware/log.ts new file mode 100644 index 0000000..652e243 --- /dev/null +++ b/frontend/src/router/middleware/log.ts @@ -0,0 +1,7 @@ +import { useAuthStore } from "@/stores/auth"; + +export const log = (next: any, context: any) => { + console.log("go to " + context.to.path); + + return next(); +}; diff --git a/frontend/src/router/middleware/pipeline.ts b/frontend/src/router/middleware/pipeline.ts new file mode 100644 index 0000000..4c0865b --- /dev/null +++ b/frontend/src/router/middleware/pipeline.ts @@ -0,0 +1,13 @@ +export const pipeline = (context: any, middleware: any, index: any) => { + const nextMiddleware = middleware[index]; + + if (!nextMiddleware) { + return context.next; + } + + return () => { + const nextPipeline = pipeline(context, middleware, index + 1); + + nextMiddleware(nextPipeline, context); + }; +}; diff --git a/frontend/src/router/routes.ts b/frontend/src/router/routes.ts new file mode 100644 index 0000000..a8e9f6a --- /dev/null +++ b/frontend/src/router/routes.ts @@ -0,0 +1,275 @@ +import Login from "@/views/Login.vue"; +import SharedFreeTime from "@/views/shared/FreeTime.vue"; +import Admin from "@/views/Admin.vue"; +import User from "@/views/User.vue"; +import PageNotFound from "@/components/PageNotFound.vue"; +import NotImplemented from "@/components/NotImplemented.vue"; +import Main from "@/components/admin/settings/Main.vue"; +import License from "@/components/admin/settings/License.vue"; +import SettingsDB from "@/components/admin/settings/SettingsDB.vue"; +import Add from "@/components/admin/domains/Add.vue"; +import DKIM from "@/components/admin/domains/DKIM.vue"; +import MailsPermDeletion from "@/components/admin/domains/MailsPermDeletion.vue"; +import Migration from "@/components/admin/domains/Migration.vue"; +import QueueSettings from "@/components/admin/settings/smtp_queue/Settings.vue"; +import BlockedIPs from "@/components/admin/security/BlockedIPs.vue"; +import WhiteListEmail from "@/components/admin/security/white_list/Email.vue"; +import WhiteListIP from "@/components/admin/security/white_list/IP.vue"; +import BlackListEmail from "@/components/admin/security/black_list/Email.vue"; +import BlackListIP from "@/components/admin/security/black_list/IP.vue"; +import QueueManage from "@/components/admin/settings/smtp_queue/Manage.vue"; +import MailStorageSettings from "@/components/admin/domains/mailstorage/Settings.vue"; +import MailStorageMailboxes from "@/components/admin/domains/mailstorage/Mailboxes.vue"; +import CIDRAccessPools from "@/components/admin/domains/cidr_access/Pools.vue"; +import CIDRAccessPolicy from "@/components/admin/domains/cidr_access/Policy.vue"; +import UserdbSettings from "@/components/admin/domains/userdb/Settings.vue"; +import UserdbUsers from "@/components/admin/domains/userdb/Users.vue"; +import UserdbGroups from "@/components/admin/domains/userdb/Groups.vue"; +import UserdbRedirects from "@/components/admin/domains/userdb/Redirects.vue"; +import UserDBAdd from "@/components/admin/domains/userdb/Add.vue"; +import Dashboard from "@/components/admin/Dashboard.vue"; +import Profile from "@/components/user/Profile.vue"; +import AdminSharedFolders from "@/components/admin/domains/SharedFolders.vue"; +import AdminAddressBooks from "@/components/admin/domains/SharedAddressBooks.vue"; +import IncomingRules from "@/components/admin/domains/IncomingRules.vue"; +import OutgoingRules from "@/components/admin/domains/OutgoingRules.vue"; +import AddressRules from "@/components/admin/settings/AddressRules.vue"; +import UserIncomingRules from "@/components/user/IncomingRules.vue"; +import CalendarsSettings from "@/components/admin/settings/Calendars.vue"; +import AdminCalendarsShared from "@/components/admin/domains/SharedCalendars.vue"; +import AdminResourcesList from "@/components/admin/domains/resources/Resources.vue"; +import AdminResourcesOffices from "@/components/admin/domains/resources/Offices.vue"; +import AdminResourcesCategories from "@/components/admin/domains/resources/Categories.vue"; + +import UserSharedFolders from "@/components/user/SharedFolders.vue"; +import UserMailboxSharedAccess from "@/components/user/MailboxSharedAccess.vue"; +import UserAddressBooksMy from "@/components/user/AddressBooks/MyBooks.vue"; +import UserAddressBooksWithAccess from "@/components/user/AddressBooks/AvaliableToMe.vue"; +import UserCalendarsMy from "@/components/user/Calendars/MyCalendars.vue"; +import UserCalendarsWithAccess from "@/components/user/Calendars/AvaliableToMe.vue"; +import UserCalendarsShareFreeTime from "@/components/user/Calendars/ShareFreeTime.vue"; +import UserEventsPlannerList from "@/components/user/Calendars/EventsPlanner/List.vue"; +import UserEventsPlannerNewOrEdit from "@/components/user/Calendars/EventsPlanner/NewOrEdit.vue"; +import RecoveryFolder from "@/components/user/RecoveryFolder.vue"; +import { + RouteAdmin, + RouteAdminDashboard, + RouteAdminDomains, + RouteAdminDomainsAdd, + RouteAdminDomainsDomainAddressBooks, + RouteAdminDomainsDomainCalendars, + RouteAdminDomainsDomainDKIM, + RouteAdminDomainsDomainIncRules, + RouteAdminDomainsDomainMailStorage, + RouteAdminDomainsDomainMailStorageMailboxes, + RouteAdminDomainsDomainMailStorageSettings, + RouteAdminDomainsDomainOutRules, + RouteAdminDomainsDomainSharedFolders, + RouteAdminDomainsDomainUserDB, + RouteAdminDomainsDomainUserDBAdd, + RouteAdminDomainsDomainUserDBProvider, + RouteAdminDomainsDomainUserDBProviderUsers, + RouteAdminDomainsDomainUserDBProviderSettings, + RouteAdminSecurity, + RouteAdminSecurityBlockedIps, + RouteAdminSettings, + RouteAdminSettingsAddressChange, + RouteAdminSettingsLicense, + RouteAdminSettingsMain, + RouteAdminSettingsSMTPQueue, + RouteAdminSettingsSMTPQueueManage, + RouteAdminSettingsSMTPQueueSettings, + RouteAdminSettingsSettingsDB, + RouteLogin, + RouteUser, + RouteUserProfile, + RouteAdminDomainsDomain, + RouteAdminSecurityWhiteList, + RouteAdminSecurityBlackList, + RouteAdminSecurityWhiteListIp, + RouteAdminSecurityWhiteListEmail, + RouteAdminSecurityBlackListIp, + RouteAdminSecurityBlackListEmail, + RouteAdminDomainsDomainMigration, + RouteAdminDomainsDomainUserDBProviderGroups, + RouteAdminDomainsDomainUserDBProviderRedirects, + RouteUserRules, + RouteUserRecovery, + RouteUserSharedFolders, + RouteUserCalendars, + RouteUserAddressBooks, + RouteUserAddressBooksMy, + RouteUserAddressBooksAvaliableToMe, + RouteUserCalendarsMy, + RouteUserCalendarsAvaliableToMe, + RouteAdminSettingsCalendars, + RouteUserMailboxSharedAccess, + RouteAdminDomainsDomainCIDRAccess, + RouteAdminDomainsDomainCIDRAccessPools, + RouteAdminDomainsDomainCIDRAccessPolicy, + RouteAdminDomainsDomainOther, + RouteAdminDomainsDomainOtherMailsPermDeletion, + RouteUserCalendarsShareFreeTime, + RouteSharedFreeTime, + RouteUserCalendarsEventsPlanner, + RouteUserCalendarsEventsPlannerList, + RouteUserCalendarsEventsPlannerNew, + RouteUserCalendarsEventsPlannerEdit, + RouteAdminDomainsDomainResources, + RouteAdminDomainsDomainResourcesList, + RouteAdminDomainsDomainResourcesCategories, + RouteAdminDomainsDomainResourcesOffices, + RouteEventsExternalApproval as RouteEventsExternalApproval, + RouteShared, +} from "./consts"; +import i18n from "@/locale"; +import { useAuthStore } from "@/stores/auth"; +import EventsExternalApproval from "@/views/shared/EventsExternalApproval.vue"; + +function route( + path: string, + component?: any, + children?: any[], + title?: string +) { + return { + path: path, + name: path, + component, + children, + meta: { + title, + }, + }; +} + +const routes = [ + route(RouteLogin, Login, undefined, i18n.global.t("login.title")), + route(RouteShared, undefined, [ + route( + RouteSharedFreeTime, + SharedFreeTime, + undefined, + i18n.global.t("shared.free_time.title") + ), + route( + RouteEventsExternalApproval, + EventsExternalApproval, + undefined, + i18n.global.t("shared.events_external_approval.title") + ), + ]), + + route( + RouteAdmin, + Admin, + [ + route(RouteAdminDashboard, Dashboard), + route(RouteAdminSettings, undefined, [ + route(RouteAdminSettingsMain, Main), + route(RouteAdminSettingsSMTPQueue, undefined, [ + route(RouteAdminSettingsSMTPQueueManage, QueueManage), + route(RouteAdminSettingsSMTPQueueSettings, QueueSettings), + ]), + route(RouteAdminSettingsSettingsDB, SettingsDB), + route(RouteAdminSettingsAddressChange, AddressRules), + route(RouteAdminSettingsLicense, License), + route(RouteAdminSettingsCalendars, CalendarsSettings), + ]), + route(RouteAdminSecurity, undefined, [ + route(RouteAdminSecurityBlockedIps, BlockedIPs), + route(RouteAdminSecurityWhiteList, undefined, [ + route(RouteAdminSecurityWhiteListIp, WhiteListIP), + route(RouteAdminSecurityWhiteListEmail, WhiteListEmail), + ]), + route(RouteAdminSecurityBlackList, undefined, [ + route(RouteAdminSecurityBlackListIp, BlackListIP), + route(RouteAdminSecurityBlackListEmail, BlackListEmail), + ]), + ]), + route(RouteAdminDomains, undefined, [ + route(RouteAdminDomainsAdd, Add), + route(RouteAdminDomainsDomain, undefined, [ + route(RouteAdminDomainsDomainMailStorage, undefined, [ + route( + RouteAdminDomainsDomainMailStorageMailboxes, + MailStorageMailboxes + ), + route( + RouteAdminDomainsDomainMailStorageSettings, + MailStorageSettings + ), + ]), + route(RouteAdminDomainsDomainUserDB, undefined, [ + route(RouteAdminDomainsDomainUserDBAdd, UserDBAdd), + route(RouteAdminDomainsDomainUserDBProvider, undefined, [ + route(RouteAdminDomainsDomainUserDBProviderUsers, UserdbUsers), + route(RouteAdminDomainsDomainUserDBProviderGroups, UserdbGroups), + route( + RouteAdminDomainsDomainUserDBProviderRedirects, + UserdbRedirects + ), + route( + RouteAdminDomainsDomainUserDBProviderSettings, + UserdbSettings + ), + ]), + ]), + ]), + route(RouteAdminDomainsDomainSharedFolders, AdminSharedFolders), + route(RouteAdminDomainsDomainAddressBooks, AdminAddressBooks), + route(RouteAdminDomainsDomainCalendars, AdminCalendarsShared), + route(RouteAdminDomainsDomainResources, undefined, [ + route(RouteAdminDomainsDomainResourcesList, AdminResourcesList), + route( + RouteAdminDomainsDomainResourcesCategories, + AdminResourcesCategories + ), + route(RouteAdminDomainsDomainResourcesOffices, AdminResourcesOffices), + ]), + route(RouteAdminDomainsDomainIncRules, IncomingRules), + route(RouteAdminDomainsDomainOutRules, OutgoingRules), + + route(RouteAdminDomainsDomainCIDRAccess, undefined, [ + route(RouteAdminDomainsDomainCIDRAccessPools, CIDRAccessPools), + route(RouteAdminDomainsDomainCIDRAccessPolicy, CIDRAccessPolicy), + ]), + + route(RouteAdminDomainsDomainDKIM, DKIM), + route(RouteAdminDomainsDomainMigration, Migration), + route(RouteAdminDomainsDomainOther, undefined, [ + route( + RouteAdminDomainsDomainOtherMailsPermDeletion, + MailsPermDeletion + ), + ]), + ]), + ], + i18n.global.t("admin.title") + ), + route(RouteUser, User, [ + route(RouteUserProfile, Profile), + route(RouteUserRules, UserIncomingRules), + route(RouteUserRecovery, RecoveryFolder), + route(RouteUserSharedFolders, UserSharedFolders), + route(RouteUserMailboxSharedAccess, UserMailboxSharedAccess), + route(RouteUserCalendars, undefined, [ + route(RouteUserCalendarsMy, UserCalendarsMy), + route(RouteUserCalendarsAvaliableToMe, UserCalendarsWithAccess), + route(RouteUserCalendarsShareFreeTime, UserCalendarsShareFreeTime), + ]), + route(RouteUserAddressBooks, undefined, [ + route(RouteUserAddressBooksMy, UserAddressBooksMy), + route(RouteUserAddressBooksAvaliableToMe, UserAddressBooksWithAccess), + ]), + route(RouteUserCalendarsEventsPlanner, undefined, [ + route(RouteUserCalendarsEventsPlannerList, UserEventsPlannerList), + route(RouteUserCalendarsEventsPlannerNew, UserEventsPlannerNewOrEdit), + route(RouteUserCalendarsEventsPlannerEdit, UserEventsPlannerNewOrEdit), + ]), + ]), + + { path: "/:pathMatch(.*)*", component: PageNotFound }, +]; + +export default routes; diff --git a/frontend/src/stores/auth.ts b/frontend/src/stores/auth.ts new file mode 100644 index 0000000..6fa9e51 --- /dev/null +++ b/frontend/src/stores/auth.ts @@ -0,0 +1,28 @@ +import { defineStore } from "pinia"; + +export const useAuthStore = defineStore({ + id: "auth", + state: () => ({ + authed: false, + username: "", + isAdmin: false, + token: "", + }), + + actions: { + setAuth(username: string, isAdmin: boolean) { + this.$patch({ + authed: true, + username, + isAdmin, + token: "", + }); + }, + resetAuth() { + this.$reset(); + }, + }, + persist: { + storage: sessionStorage, + }, +}); diff --git a/frontend/src/stores/returnToPage.ts b/frontend/src/stores/returnToPage.ts new file mode 100644 index 0000000..747d655 --- /dev/null +++ b/frontend/src/stores/returnToPage.ts @@ -0,0 +1,33 @@ +import { defineStore } from "pinia"; + +export const useReturnToPageStore = defineStore({ + id: "returnToPage", + state: () => ({ + path: "", + query: null, + }), + + actions: { + setPath(path: string, query: any) { + if (this.path === "") { + this.$patch({ + path: path, + query: query, + }); + } + }, + + getPath() { + const path = this.path.slice(); + const query = this.query; + this.$reset(); + return { + path: path, + query: query, + }; + }, + }, + persist: { + storage: sessionStorage, + }, +}); diff --git a/frontend/src/style.css b/frontend/src/style.css deleted file mode 100644 index 3940d6c..0000000 --- a/frontend/src/style.css +++ /dev/null @@ -1,26 +0,0 @@ -html { - background-color: rgba(27, 38, 54, 1); - text-align: center; - color: white; -} - -body { - margin: 0; - color: white; - font-family: "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", - "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", - sans-serif; -} - -@font-face { - font-family: "Nunito"; - font-style: normal; - font-weight: 400; - src: local(""), - url("assets/fonts/nunito-v16-latin-regular.woff2") format("woff2"); -} - -#app { - height: 100vh; - text-align: center; -} diff --git a/frontend/src/views/Admin.vue b/frontend/src/views/Admin.vue new file mode 100644 index 0000000..d3a73c3 --- /dev/null +++ b/frontend/src/views/Admin.vue @@ -0,0 +1,1546 @@ + + + + + diff --git a/frontend/src/views/Login.vue b/frontend/src/views/Login.vue new file mode 100644 index 0000000..9e12957 --- /dev/null +++ b/frontend/src/views/Login.vue @@ -0,0 +1,168 @@ + + + + + diff --git a/frontend/src/views/User.vue b/frontend/src/views/User.vue new file mode 100644 index 0000000..e9508b4 --- /dev/null +++ b/frontend/src/views/User.vue @@ -0,0 +1,445 @@ + + + + + diff --git a/frontend/src/views/shared/EventsExternalApproval.vue b/frontend/src/views/shared/EventsExternalApproval.vue new file mode 100644 index 0000000..b467c15 --- /dev/null +++ b/frontend/src/views/shared/EventsExternalApproval.vue @@ -0,0 +1,271 @@ + + + + diff --git a/frontend/src/views/shared/FreeTime.vue b/frontend/src/views/shared/FreeTime.vue new file mode 100644 index 0000000..d6ef074 --- /dev/null +++ b/frontend/src/views/shared/FreeTime.vue @@ -0,0 +1,265 @@ + + + + diff --git a/frontend/src/vite-env.d.ts b/frontend/src/vite-env.d.ts deleted file mode 100644 index dcfaef4..0000000 --- a/frontend/src/vite-env.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -/// - -declare module '*.vue' { - import type {DefineComponent} from 'vue' - const component: DefineComponent<{}, {}, any> - export default component -} diff --git a/frontend/tsconfig.app.json b/frontend/tsconfig.app.json new file mode 100644 index 0000000..e14c754 --- /dev/null +++ b/frontend/tsconfig.app.json @@ -0,0 +1,14 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], + "exclude": ["src/**/__tests__/*"], + "compilerOptions": { + "composite": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + } +} diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index 3cc844d..66b5e57 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -1,30 +1,11 @@ { - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "moduleResolution": "Node", - "strict": true, - "jsx": "preserve", - "sourceMap": true, - "resolveJsonModule": true, - "isolatedModules": true, - "esModuleInterop": true, - "lib": [ - "ESNext", - "DOM" - ], - "skipLibCheck": true - }, - "include": [ - "src/**/*.ts", - "src/**/*.d.ts", - "src/**/*.tsx", - "src/**/*.vue" - ], + "files": [], "references": [ { "path": "./tsconfig.node.json" + }, + { + "path": "./tsconfig.app.json" } ] } diff --git a/frontend/tsconfig.node.json b/frontend/tsconfig.node.json index b8afcc8..f094063 100644 --- a/frontend/tsconfig.node.json +++ b/frontend/tsconfig.node.json @@ -1,11 +1,19 @@ { + "extends": "@tsconfig/node20/tsconfig.json", + "include": [ + "vite.config.*", + "vitest.config.*", + "cypress.config.*", + "nightwatch.conf.*", + "playwright.config.*" + ], "compilerOptions": { "composite": true, + "noEmit": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "module": "ESNext", - "moduleResolution": "Node", - "allowSyntheticDefaultImports": true - }, - "include": [ - "vite.config.ts" - ] + "moduleResolution": "Bundler", + "types": ["node"] + } } diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index a30c338..998f6fa 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -1,7 +1,15 @@ -import {defineConfig} from 'vite' -import vue from '@vitejs/plugin-vue' +import { fileURLToPath, URL } from "node:url"; + +import { defineConfig } from "vite"; +import vue from "@vitejs/plugin-vue"; // https://vitejs.dev/config/ export default defineConfig({ - plugins: [vue()] -}) + // base: 'http://somehost', + plugins: [vue()], + resolve: { + alias: { + "@": fileURLToPath(new URL("./src", import.meta.url)), + }, + }, +}); diff --git a/go.mod b/go.mod index 7cf8fa4..2c6d8e5 100644 --- a/go.mod +++ b/go.mod @@ -2,15 +2,20 @@ module myproject go 1.23 -require github.com/wailsapp/wails/v2 v2.10.1 +require ( + github.com/gorilla/sessions v1.4.0 + github.com/labstack/echo/v4 v4.13.3 + github.com/wailsapp/wails/v2 v2.10.1 + gitlab.com/revoluterra-dev/common/helpers v1.27.8 +) require ( github.com/bep/debounce v1.2.1 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/google/uuid v1.6.0 // indirect + github.com/gorilla/securecookie v1.1.2 // indirect github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect - github.com/labstack/echo/v4 v4.13.3 // indirect github.com/labstack/gommon v0.4.2 // indirect github.com/leaanthony/go-ansi-parser v1.6.1 // indirect github.com/leaanthony/gosod v1.0.4 // indirect @@ -31,6 +36,7 @@ require ( golang.org/x/net v0.35.0 // indirect golang.org/x/sys v0.30.0 // indirect golang.org/x/text v0.22.0 // indirect + golang.org/x/time v0.8.0 // indirect ) // replace github.com/wailsapp/wails/v2 v2.10.1 => /home/kirill/go/pkg/mod diff --git a/go.sum b/go.sum index 0ad6722..5388d22 100644 --- a/go.sum +++ b/go.sum @@ -6,8 +6,14 @@ github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= +github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= +github.com/gorilla/sessions v1.4.0 h1:kpIYOp/oi6MG/p5PgxApU8srsSw9tuFbt46Lt7auzqQ= +github.com/gorilla/sessions v1.4.0/go.mod h1:FLWm50oby91+hl7p/wRxDth9bWSuk0qVL2emc7lT5ik= github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck= github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs= github.com/labstack/echo/v4 v4.13.3 h1:pwhpCPrTl5qry5HRdM5FwdXnhXSLSY+WE+YQSeCaafY= @@ -57,6 +63,8 @@ github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhw github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o= github.com/wailsapp/wails/v2 v2.10.1 h1:QWHvWMXII2nI/nXz77gpPG8P3ehl6zKe+u4su5BWIns= github.com/wailsapp/wails/v2 v2.10.1/go.mod h1:zrebnFV6MQf9kx8HI4iAv63vsR5v67oS7GTEZ7Pz1TY= +gitlab.com/revoluterra-dev/common/helpers v1.27.8 h1:1eqDCSKV99bcoa2UYpEkZX55h78ZB/ZkyuMlDJMT1ak= +gitlab.com/revoluterra-dev/common/helpers v1.27.8/go.mod h1:PHXaECK2VGIGorGsYpeQjFPE9aOrwOhp1E760j+xGMg= golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -74,6 +82,8 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= +golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg= +golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/handlers.go b/handlers.go new file mode 100644 index 0000000..d908ef9 --- /dev/null +++ b/handlers.go @@ -0,0 +1,20 @@ +package main + +import ( + "myproject/tools" + + "github.com/labstack/echo/v4" +) + +func RegisterApi(e *echo.Group) { + e.POST("/login", login) + e.GET("/check", check) +} + +func check(c echo.Context) error { + return tools.ServeData(c, true) +} + +func login(c echo.Context) error { + return tools.ServeErrorMsg(c, "Успешная попытка логина") +} diff --git a/main.go b/main.go index fd19faa..f0a8304 100644 --- a/main.go +++ b/main.go @@ -1,11 +1,17 @@ package main import ( + "context" "embed" + "fmt" + "net" + "net/http" + "time" "github.com/wailsapp/wails/v2" "github.com/wailsapp/wails/v2/pkg/options" "github.com/wailsapp/wails/v2/pkg/options/assetserver" + "gitlab.com/revoluterra-dev/common/helpers/trace" ) //go:embed all:frontend/dist @@ -15,15 +21,25 @@ func main() { // Create an instance of the app structure app := NewApp() + echo := NewEcho(context.Background(), nil) + backendGroup := echo.Group("/backend") + + RegisterApi(backendGroup.Group("")) + + go StartServer(context.Background(), + 8888, + echo, + func() {}) + // Create application with options err := wails.Run(&options.App{ - Title: "myproject", + Title: "Timon", Width: 1024, Height: 768, AssetServer: &assetserver.Options{ Assets: assets, }, - BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1}, + BackgroundColour: options.NewRGB(255, 255, 255), OnStartup: app.startup, Bind: []interface{}{ app, @@ -34,3 +50,29 @@ func main() { println("Error:", err.Error()) } } + +func StartServer(ctx context.Context, port int64, router http.Handler, doneCallback func()) { + srv := &http.Server{ + Addr: fmt.Sprintf(":%d", port), + Handler: router, + BaseContext: func(net.Listener) context.Context { return ctx }, + } + + go func() { + var err error + + err = srv.ListenAndServe() + + if err != nil && !trace.Is(err, http.ErrServerClosed) { + println(fmt.Sprintf("listen failed: %s\n", err)) + } + doneCallback() + }() + + <-ctx.Done() + ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) + defer cancel() + if err := srv.Shutdown(ctx); err != nil { + println(fmt.Sprintf("service shutdown failed: %s\n", err)) + } +} diff --git a/tools/auth.go b/tools/auth.go new file mode 100644 index 0000000..a9e2157 --- /dev/null +++ b/tools/auth.go @@ -0,0 +1,30 @@ +package tools + +import ( + "context" + + "github.com/labstack/echo/v4" +) + +const ( + UserCtxKey = "user" + LpCtxKey = "lp" + DomainCtxKey = "domain" + RootCtxKey = "rootCtx" +) + +func GetUser(c echo.Context) string { + return c.Get(UserCtxKey).(string) +} + +func GetDomain(c echo.Context) string { + return c.Get(DomainCtxKey).(string) +} + +func GetLp(c echo.Context) string { + return c.Get(LpCtxKey).(string) +} + +func GetRootCtx(c echo.Context) context.Context { + return c.Get(RootCtxKey).(context.Context) +} diff --git a/tools/consts.go b/tools/consts.go new file mode 100644 index 0000000..49a433a --- /dev/null +++ b/tools/consts.go @@ -0,0 +1,12 @@ +package tools + +const ( + // PageSize = 20 + + UserNameSessionKey = `TeguUserName` + SessionName = `teguCtlSession` +) + +const ( + LicMgrPluginName = `licenseMisc` +) diff --git a/tools/responses.go b/tools/responses.go new file mode 100644 index 0000000..796bbdc --- /dev/null +++ b/tools/responses.go @@ -0,0 +1,130 @@ +package tools + +import ( + "net/http" + + "github.com/labstack/echo/v4" + "gitlab.com/revoluterra-dev/common/helpers/trace" +) + +type Response struct { + Error string `json:"error"` + Result interface{} `json:"result"` + Total int64 `json:"total"` +} + +// // Serve422 generates 422 (wrong entity) error to response json. +func ServeError(c echo.Context, err error) error { + return c.JSON( + http.StatusUnprocessableEntity, + Response{ + Error: trace.UnTrace(err).Error(), + Result: []struct{}{}, + }, + ) +} +func ServeErrorMsg(c echo.Context, errorMessage string) error { + return c.JSON( + http.StatusUnprocessableEntity, + Response{ + Error: errorMessage, + Result: []struct{}{}, + }, + ) +} + +// Serve404 generates 404 (not found) error to response json. +func Serve404(c echo.Context) error { + return c.JSON( + http.StatusNotFound, + Response{ + Error: http.StatusText(http.StatusNotFound), + Result: []struct{}{}, + }, + ) +} + +func Serve405(c echo.Context) error { + return c.JSON( + http.StatusMethodNotAllowed, + Response{ + Error: http.StatusText(http.StatusMethodNotAllowed), + Result: []struct{}{}, + }, + ) +} + +// Serve404 generates 401 (not found) error to response json. +func Serve401(c echo.Context) error { + return c.JSON( + http.StatusUnauthorized, + Response{ + Error: http.StatusText(http.StatusUnauthorized), + Result: []struct{}{}, + }, + ) +} + +func Serve403(c echo.Context) error { + return c.JSON( + http.StatusForbidden, + Response{ + Error: http.StatusText(http.StatusForbidden), + Result: []struct{}{}, + }, + ) +} + +func Serve429(c echo.Context) error { + return c.JSON( + http.StatusTooManyRequests, + Response{ + Error: http.StatusText(http.StatusTooManyRequests), + Result: []struct{}{}, + }, + ) +} + +// Serve500 generates 500 (internal error) error to response json. +func Serve500(c echo.Context) error { + return c.JSON( + http.StatusInternalServerError, + Response{ + Error: http.StatusText(http.StatusInternalServerError), + Result: []struct{}{}, + }, + ) +} + +func Serve503(c echo.Context) error { + return c.JSON( + http.StatusServiceUnavailable, + Response{ + Error: "Server is restarting", + Result: []struct{}{}, + }, + ) +} + +func ServeData(c echo.Context, data interface{}, total ...int64) error { + var t int64 + if len(total) > 0 { + t = total[0] + } + return c.JSON( + http.StatusOK, + Response{ + Result: data, + Total: t, + }, + ) +} + +// func usePath(e *echo.Echo, path string) string { +// e.OPTIONS(path, noContent) +// return path +// } + +// func noContent(c echo.Context) error { +// return c.NoContent(200) +// }