From b96624a25189dc89447c4818200d8d93a62d2c98 Mon Sep 17 00:00:00 2001 From: ryan Date: Mon, 8 Jun 2026 19:13:44 +0800 Subject: [PATCH] =?UTF-8?q?=E6=A8=A1=E6=9D=BF=E7=B3=BB=E7=BB=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/docs.go | 459 ++++++++++++++++++ docs/swagger.json | 459 ++++++++++++++++++ docs/swagger.yaml | 287 +++++++++++ .../components/common/settings/security.tsx | 7 +- .../components/common/settings/templates.tsx | 374 ++++++++++++++ frontend/lib/services/admin/admin.service.ts | 40 ++ frontend/lib/services/admin/types.ts | 40 ++ internal/apps/admin/template/errs.go | 27 ++ internal/apps/admin/template/routers.go | 246 ++++++++++ internal/apps/admin/template/routers_test.go | 255 ++++++++++ internal/apps/user/controllers.go | 26 +- internal/db/migrator/migrator.go | 55 +++ internal/model/templates.go | 119 +++++ internal/router/router.go | 12 + internal/testhelper/test_helper.go | 1 + 15 files changed, 2400 insertions(+), 7 deletions(-) create mode 100644 frontend/components/common/settings/templates.tsx create mode 100644 internal/apps/admin/template/errs.go create mode 100644 internal/apps/admin/template/routers.go create mode 100644 internal/apps/admin/template/routers_test.go create mode 100644 internal/model/templates.go diff --git a/docs/docs.go b/docs/docs.go index a5ef2d26..6acf8328 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -1346,6 +1346,367 @@ const docTemplate = `{ } } }, + "/api/v1/admin/templates": { + "get": { + "security": [ + { + "SessionCookie": [] + } + ], + "description": "返回所有通知模板列表,需要管理员权限", + "produces": [ + "application/json" + ], + "tags": [ + "admin" + ], + "summary": "获取模板列表", + "responses": { + "200": { + "description": "模板列表", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/util.ResponseAny" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/model.Template" + } + } + } + } + ] + } + }, + "401": { + "description": "未登录", + "schema": { + "$ref": "#/definitions/util.ResponseAny" + } + }, + "403": { + "description": "无管理员权限", + "schema": { + "$ref": "#/definitions/util.ResponseAny" + } + }, + "500": { + "description": "内部错误", + "schema": { + "$ref": "#/definitions/util.ResponseAny" + } + } + } + }, + "post": { + "security": [ + { + "SessionCookie": [] + } + ], + "description": "创建一条新的自定义通知模板,模板标识符(Key)不可重复,需要管理员权限", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "admin" + ], + "summary": "创建模板", + "parameters": [ + { + "description": "创建请求参数", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/template.CreateTemplateRequest" + } + } + ], + "responses": { + "200": { + "description": "创建成功", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/util.ResponseAny" + }, + { + "type": "object", + "properties": { + "data": { + "type": "string" + } + } + } + ] + } + }, + "400": { + "description": "参数错误或模板标识符已存在", + "schema": { + "$ref": "#/definitions/util.ResponseAny" + } + }, + "401": { + "description": "未登录", + "schema": { + "$ref": "#/definitions/util.ResponseAny" + } + }, + "403": { + "description": "无管理员权限", + "schema": { + "$ref": "#/definitions/util.ResponseAny" + } + }, + "500": { + "description": "内部错误", + "schema": { + "$ref": "#/definitions/util.ResponseAny" + } + } + } + } + }, + "/api/v1/admin/templates/{key}": { + "get": { + "security": [ + { + "SessionCookie": [] + } + ], + "description": "根据模板标识符获取对应的模板详情,需要管理员权限", + "produces": [ + "application/json" + ], + "tags": [ + "admin" + ], + "summary": "获取单个模板", + "parameters": [ + { + "type": "string", + "description": "模板标识符", + "name": "key", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "模板详情", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/util.ResponseAny" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/model.Template" + } + } + } + ] + } + }, + "401": { + "description": "未登录", + "schema": { + "$ref": "#/definitions/util.ResponseAny" + } + }, + "403": { + "description": "无管理员权限", + "schema": { + "$ref": "#/definitions/util.ResponseAny" + } + }, + "404": { + "description": "模板不存在", + "schema": { + "$ref": "#/definitions/util.ResponseAny" + } + }, + "500": { + "description": "内部错误", + "schema": { + "$ref": "#/definitions/util.ResponseAny" + } + } + } + }, + "put": { + "security": [ + { + "SessionCookie": [] + } + ], + "description": "根据模板标识符更新对应的模板内容,需要管理员权限", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "admin" + ], + "summary": "更新模板", + "parameters": [ + { + "type": "string", + "description": "模板标识符", + "name": "key", + "in": "path", + "required": true + }, + { + "description": "更新请求参数", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/template.UpdateTemplateRequest" + } + } + ], + "responses": { + "200": { + "description": "更新成功", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/util.ResponseAny" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/model.Template" + } + } + } + ] + } + }, + "400": { + "description": "参数错误", + "schema": { + "$ref": "#/definitions/util.ResponseAny" + } + }, + "401": { + "description": "未登录", + "schema": { + "$ref": "#/definitions/util.ResponseAny" + } + }, + "403": { + "description": "无管理员权限", + "schema": { + "$ref": "#/definitions/util.ResponseAny" + } + }, + "404": { + "description": "模板不存在", + "schema": { + "$ref": "#/definitions/util.ResponseAny" + } + }, + "500": { + "description": "内部错误", + "schema": { + "$ref": "#/definitions/util.ResponseAny" + } + } + } + }, + "delete": { + "security": [ + { + "SessionCookie": [] + } + ], + "description": "根据模板标识符删除对应模板,系统预置模板不可删除,需要管理员权限", + "produces": [ + "application/json" + ], + "tags": [ + "admin" + ], + "summary": "删除模板", + "parameters": [ + { + "type": "string", + "description": "模板标识符", + "name": "key", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "删除成功", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/util.ResponseAny" + }, + { + "type": "object", + "properties": { + "data": { + "type": "string" + } + } + } + ] + } + }, + "400": { + "description": "不可删除系统模板", + "schema": { + "$ref": "#/definitions/util.ResponseAny" + } + }, + "401": { + "description": "未登录", + "schema": { + "$ref": "#/definitions/util.ResponseAny" + } + }, + "403": { + "description": "无管理员权限", + "schema": { + "$ref": "#/definitions/util.ResponseAny" + } + }, + "404": { + "description": "模板不存在", + "schema": { + "$ref": "#/definitions/util.ResponseAny" + } + }, + "500": { + "description": "内部错误", + "schema": { + "$ref": "#/definitions/util.ResponseAny" + } + } + } + } + }, "/api/v1/admin/users": { "get": { "security": [ @@ -3205,6 +3566,41 @@ const docTemplate = `{ "TaskExecutionStatusFailed" ] }, + "model.Template": { + "type": "object", + "properties": { + "content": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "description": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "is_system": { + "type": "boolean" + }, + "key": { + "type": "string" + }, + "name": { + "type": "string" + }, + "subject": { + "type": "string" + }, + "type": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + } + }, "model.Upload": { "type": "object", "properties": { @@ -3677,6 +4073,69 @@ const docTemplate = `{ } } }, + "template.CreateTemplateRequest": { + "type": "object", + "required": [ + "content", + "key", + "name", + "type" + ], + "properties": { + "content": { + "type": "string" + }, + "description": { + "type": "string", + "maxLength": 255 + }, + "key": { + "type": "string", + "maxLength": 80 + }, + "name": { + "type": "string", + "maxLength": 100 + }, + "subject": { + "type": "string", + "maxLength": 255 + }, + "type": { + "type": "string", + "maxLength": 20 + } + } + }, + "template.UpdateTemplateRequest": { + "type": "object", + "required": [ + "content", + "name", + "type" + ], + "properties": { + "content": { + "type": "string" + }, + "description": { + "type": "string", + "maxLength": 255 + }, + "name": { + "type": "string", + "maxLength": 100 + }, + "subject": { + "type": "string", + "maxLength": 255 + }, + "type": { + "type": "string", + "maxLength": 20 + } + } + }, "upload.batchDownloadRequest": { "type": "object", "required": [ diff --git a/docs/swagger.json b/docs/swagger.json index 8ed89a58..1d10e6f1 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -1339,6 +1339,367 @@ } } }, + "/api/v1/admin/templates": { + "get": { + "security": [ + { + "SessionCookie": [] + } + ], + "description": "返回所有通知模板列表,需要管理员权限", + "produces": [ + "application/json" + ], + "tags": [ + "admin" + ], + "summary": "获取模板列表", + "responses": { + "200": { + "description": "模板列表", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/util.ResponseAny" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/model.Template" + } + } + } + } + ] + } + }, + "401": { + "description": "未登录", + "schema": { + "$ref": "#/definitions/util.ResponseAny" + } + }, + "403": { + "description": "无管理员权限", + "schema": { + "$ref": "#/definitions/util.ResponseAny" + } + }, + "500": { + "description": "内部错误", + "schema": { + "$ref": "#/definitions/util.ResponseAny" + } + } + } + }, + "post": { + "security": [ + { + "SessionCookie": [] + } + ], + "description": "创建一条新的自定义通知模板,模板标识符(Key)不可重复,需要管理员权限", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "admin" + ], + "summary": "创建模板", + "parameters": [ + { + "description": "创建请求参数", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/template.CreateTemplateRequest" + } + } + ], + "responses": { + "200": { + "description": "创建成功", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/util.ResponseAny" + }, + { + "type": "object", + "properties": { + "data": { + "type": "string" + } + } + } + ] + } + }, + "400": { + "description": "参数错误或模板标识符已存在", + "schema": { + "$ref": "#/definitions/util.ResponseAny" + } + }, + "401": { + "description": "未登录", + "schema": { + "$ref": "#/definitions/util.ResponseAny" + } + }, + "403": { + "description": "无管理员权限", + "schema": { + "$ref": "#/definitions/util.ResponseAny" + } + }, + "500": { + "description": "内部错误", + "schema": { + "$ref": "#/definitions/util.ResponseAny" + } + } + } + } + }, + "/api/v1/admin/templates/{key}": { + "get": { + "security": [ + { + "SessionCookie": [] + } + ], + "description": "根据模板标识符获取对应的模板详情,需要管理员权限", + "produces": [ + "application/json" + ], + "tags": [ + "admin" + ], + "summary": "获取单个模板", + "parameters": [ + { + "type": "string", + "description": "模板标识符", + "name": "key", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "模板详情", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/util.ResponseAny" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/model.Template" + } + } + } + ] + } + }, + "401": { + "description": "未登录", + "schema": { + "$ref": "#/definitions/util.ResponseAny" + } + }, + "403": { + "description": "无管理员权限", + "schema": { + "$ref": "#/definitions/util.ResponseAny" + } + }, + "404": { + "description": "模板不存在", + "schema": { + "$ref": "#/definitions/util.ResponseAny" + } + }, + "500": { + "description": "内部错误", + "schema": { + "$ref": "#/definitions/util.ResponseAny" + } + } + } + }, + "put": { + "security": [ + { + "SessionCookie": [] + } + ], + "description": "根据模板标识符更新对应的模板内容,需要管理员权限", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "admin" + ], + "summary": "更新模板", + "parameters": [ + { + "type": "string", + "description": "模板标识符", + "name": "key", + "in": "path", + "required": true + }, + { + "description": "更新请求参数", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/template.UpdateTemplateRequest" + } + } + ], + "responses": { + "200": { + "description": "更新成功", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/util.ResponseAny" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/model.Template" + } + } + } + ] + } + }, + "400": { + "description": "参数错误", + "schema": { + "$ref": "#/definitions/util.ResponseAny" + } + }, + "401": { + "description": "未登录", + "schema": { + "$ref": "#/definitions/util.ResponseAny" + } + }, + "403": { + "description": "无管理员权限", + "schema": { + "$ref": "#/definitions/util.ResponseAny" + } + }, + "404": { + "description": "模板不存在", + "schema": { + "$ref": "#/definitions/util.ResponseAny" + } + }, + "500": { + "description": "内部错误", + "schema": { + "$ref": "#/definitions/util.ResponseAny" + } + } + } + }, + "delete": { + "security": [ + { + "SessionCookie": [] + } + ], + "description": "根据模板标识符删除对应模板,系统预置模板不可删除,需要管理员权限", + "produces": [ + "application/json" + ], + "tags": [ + "admin" + ], + "summary": "删除模板", + "parameters": [ + { + "type": "string", + "description": "模板标识符", + "name": "key", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "删除成功", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/util.ResponseAny" + }, + { + "type": "object", + "properties": { + "data": { + "type": "string" + } + } + } + ] + } + }, + "400": { + "description": "不可删除系统模板", + "schema": { + "$ref": "#/definitions/util.ResponseAny" + } + }, + "401": { + "description": "未登录", + "schema": { + "$ref": "#/definitions/util.ResponseAny" + } + }, + "403": { + "description": "无管理员权限", + "schema": { + "$ref": "#/definitions/util.ResponseAny" + } + }, + "404": { + "description": "模板不存在", + "schema": { + "$ref": "#/definitions/util.ResponseAny" + } + }, + "500": { + "description": "内部错误", + "schema": { + "$ref": "#/definitions/util.ResponseAny" + } + } + } + } + }, "/api/v1/admin/users": { "get": { "security": [ @@ -3198,6 +3559,41 @@ "TaskExecutionStatusFailed" ] }, + "model.Template": { + "type": "object", + "properties": { + "content": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "description": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "is_system": { + "type": "boolean" + }, + "key": { + "type": "string" + }, + "name": { + "type": "string" + }, + "subject": { + "type": "string" + }, + "type": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + } + }, "model.Upload": { "type": "object", "properties": { @@ -3670,6 +4066,69 @@ } } }, + "template.CreateTemplateRequest": { + "type": "object", + "required": [ + "content", + "key", + "name", + "type" + ], + "properties": { + "content": { + "type": "string" + }, + "description": { + "type": "string", + "maxLength": 255 + }, + "key": { + "type": "string", + "maxLength": 80 + }, + "name": { + "type": "string", + "maxLength": 100 + }, + "subject": { + "type": "string", + "maxLength": 255 + }, + "type": { + "type": "string", + "maxLength": 20 + } + } + }, + "template.UpdateTemplateRequest": { + "type": "object", + "required": [ + "content", + "name", + "type" + ], + "properties": { + "content": { + "type": "string" + }, + "description": { + "type": "string", + "maxLength": 255 + }, + "name": { + "type": "string", + "maxLength": 100 + }, + "subject": { + "type": "string", + "maxLength": 255 + }, + "type": { + "type": "string", + "maxLength": 20 + } + } + }, "upload.batchDownloadRequest": { "type": "object", "required": [ diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 02ca7ff0..e01ab3e5 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -224,6 +224,29 @@ definitions: - TaskExecutionStatusRunning - TaskExecutionStatusSucceeded - TaskExecutionStatusFailed + model.Template: + properties: + content: + type: string + created_at: + type: string + description: + type: string + id: + type: integer + is_system: + type: boolean + key: + type: string + name: + type: string + subject: + type: string + type: + type: string + updated_at: + type: string + type: object model.Upload: properties: created_at: @@ -547,6 +570,52 @@ definitions: description: 类型:string, text, number type: string type: object + template.CreateTemplateRequest: + properties: + content: + type: string + description: + maxLength: 255 + type: string + key: + maxLength: 80 + type: string + name: + maxLength: 100 + type: string + subject: + maxLength: 255 + type: string + type: + maxLength: 20 + type: string + required: + - content + - key + - name + - type + type: object + template.UpdateTemplateRequest: + properties: + content: + type: string + description: + maxLength: 255 + type: string + name: + maxLength: 100 + type: string + subject: + maxLength: 255 + type: string + type: + maxLength: 20 + type: string + required: + - content + - name + - type + type: object upload.batchDownloadRequest: properties: ids: @@ -1495,6 +1564,224 @@ paths: summary: 获取支持的任务类型 tags: - admin + /api/v1/admin/templates: + get: + description: 返回所有通知模板列表,需要管理员权限 + produces: + - application/json + responses: + "200": + description: 模板列表 + schema: + allOf: + - $ref: '#/definitions/util.ResponseAny' + - properties: + data: + items: + $ref: '#/definitions/model.Template' + type: array + type: object + "401": + description: 未登录 + schema: + $ref: '#/definitions/util.ResponseAny' + "403": + description: 无管理员权限 + schema: + $ref: '#/definitions/util.ResponseAny' + "500": + description: 内部错误 + schema: + $ref: '#/definitions/util.ResponseAny' + security: + - SessionCookie: [] + summary: 获取模板列表 + tags: + - admin + post: + consumes: + - application/json + description: 创建一条新的自定义通知模板,模板标识符(Key)不可重复,需要管理员权限 + parameters: + - description: 创建请求参数 + in: body + name: request + required: true + schema: + $ref: '#/definitions/template.CreateTemplateRequest' + produces: + - application/json + responses: + "200": + description: 创建成功 + schema: + allOf: + - $ref: '#/definitions/util.ResponseAny' + - properties: + data: + type: string + type: object + "400": + description: 参数错误或模板标识符已存在 + schema: + $ref: '#/definitions/util.ResponseAny' + "401": + description: 未登录 + schema: + $ref: '#/definitions/util.ResponseAny' + "403": + description: 无管理员权限 + schema: + $ref: '#/definitions/util.ResponseAny' + "500": + description: 内部错误 + schema: + $ref: '#/definitions/util.ResponseAny' + security: + - SessionCookie: [] + summary: 创建模板 + tags: + - admin + /api/v1/admin/templates/{key}: + delete: + description: 根据模板标识符删除对应模板,系统预置模板不可删除,需要管理员权限 + parameters: + - description: 模板标识符 + in: path + name: key + required: true + type: string + produces: + - application/json + responses: + "200": + description: 删除成功 + schema: + allOf: + - $ref: '#/definitions/util.ResponseAny' + - properties: + data: + type: string + type: object + "400": + description: 不可删除系统模板 + schema: + $ref: '#/definitions/util.ResponseAny' + "401": + description: 未登录 + schema: + $ref: '#/definitions/util.ResponseAny' + "403": + description: 无管理员权限 + schema: + $ref: '#/definitions/util.ResponseAny' + "404": + description: 模板不存在 + schema: + $ref: '#/definitions/util.ResponseAny' + "500": + description: 内部错误 + schema: + $ref: '#/definitions/util.ResponseAny' + security: + - SessionCookie: [] + summary: 删除模板 + tags: + - admin + get: + description: 根据模板标识符获取对应的模板详情,需要管理员权限 + parameters: + - description: 模板标识符 + in: path + name: key + required: true + type: string + produces: + - application/json + responses: + "200": + description: 模板详情 + schema: + allOf: + - $ref: '#/definitions/util.ResponseAny' + - properties: + data: + $ref: '#/definitions/model.Template' + type: object + "401": + description: 未登录 + schema: + $ref: '#/definitions/util.ResponseAny' + "403": + description: 无管理员权限 + schema: + $ref: '#/definitions/util.ResponseAny' + "404": + description: 模板不存在 + schema: + $ref: '#/definitions/util.ResponseAny' + "500": + description: 内部错误 + schema: + $ref: '#/definitions/util.ResponseAny' + security: + - SessionCookie: [] + summary: 获取单个模板 + tags: + - admin + put: + consumes: + - application/json + description: 根据模板标识符更新对应的模板内容,需要管理员权限 + parameters: + - description: 模板标识符 + in: path + name: key + required: true + type: string + - description: 更新请求参数 + in: body + name: request + required: true + schema: + $ref: '#/definitions/template.UpdateTemplateRequest' + produces: + - application/json + responses: + "200": + description: 更新成功 + schema: + allOf: + - $ref: '#/definitions/util.ResponseAny' + - properties: + data: + $ref: '#/definitions/model.Template' + type: object + "400": + description: 参数错误 + schema: + $ref: '#/definitions/util.ResponseAny' + "401": + description: 未登录 + schema: + $ref: '#/definitions/util.ResponseAny' + "403": + description: 无管理员权限 + schema: + $ref: '#/definitions/util.ResponseAny' + "404": + description: 模板不存在 + schema: + $ref: '#/definitions/util.ResponseAny' + "500": + description: 内部错误 + schema: + $ref: '#/definitions/util.ResponseAny' + security: + - SessionCookie: [] + summary: 更新模板 + tags: + - admin /api/v1/admin/users: get: description: 分页返回用户列表,支持按用户 ID 和用户名筛选,需要管理员权限 diff --git a/frontend/components/common/settings/security.tsx b/frontend/components/common/settings/security.tsx index 2d59f0b5..a9b42a11 100644 --- a/frontend/components/common/settings/security.tsx +++ b/frontend/components/common/settings/security.tsx @@ -30,6 +30,7 @@ import {Label} from "@/components/ui/label" import {Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle} from "@/components/ui/dialog" import {useAuth} from "@/components/providers/auth-provider" import {AuthSourceModal} from "@/components/common/settings/auth-source-modal" +import {TemplatesManager} from "@/components/common/settings/templates" import {AdminService, apiConfig} from "@/lib/services" import type {AuthSource, SystemConfig} from "@/lib/services/admin" import {toast} from "sonner" @@ -74,8 +75,6 @@ const SECURITY_KEYS = [ }, ] as const -type SecurityKey = (typeof SECURITY_KEYS)[number]["key"] - function systemConfigMap(configs: SystemConfig[]) { return configs.reduce>((accumulator, config) => { accumulator[config.key] = config @@ -671,7 +670,9 @@ export function SecurityMain() { - + + +
{/* 通用设置 */} diff --git a/frontend/components/common/settings/templates.tsx b/frontend/components/common/settings/templates.tsx new file mode 100644 index 00000000..edfe3d16 --- /dev/null +++ b/frontend/components/common/settings/templates.tsx @@ -0,0 +1,374 @@ +"use client" + +import {useState} from "react" +import {useMutation, useQuery, useQueryClient} from "@tanstack/react-query" +import {FileText, Loader2, Pencil, Plus, Trash2} from "lucide-react" + +import {Button} from "@/components/ui/button" +import {Card, CardContent, CardDescription, CardHeader, CardTitle} from "@/components/ui/card" +import {Input} from "@/components/ui/input" +import {Label} from "@/components/ui/label" +import {Textarea} from "@/components/ui/textarea" +import {Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle} from "@/components/ui/dialog" +import {AdminService} from "@/lib/services" +import type {Template} from "@/lib/services/admin/types" +import {toast} from "sonner" + +export function TemplatesManager() { + const queryClient = useQueryClient() + const [modalOpen, setModalOpen] = useState(false) + const [selectedTemplate, setSelectedTemplate] = useState