From 922db289fee5d6244b97aa4ecc8b3e7af98c6809 Mon Sep 17 00:00:00 2001 From: aXenDeveloper Date: Wed, 25 Jun 2025 21:09:03 +0200 Subject: [PATCH 1/2] feat: Add more info dialog for log in debug panel --- apps/web/migrations/0001_thick_thor.sql | 6 + apps/web/migrations/meta/0001_snapshot.json | 1446 +++++++++++++++++ apps/web/migrations/meta/_journal.json | 7 + .../(vitnode-blog)/blog/categories/page.tsx | 2 +- .../(vitnode-blog)/blog/posts/page.tsx | 2 +- .../(vitnode-core)/core/debug/page.tsx | 14 +- apps/web/src/locales/@vitnode/core/en.json | 26 +- .../vitnode/src/api/lib/logger-middleware.ts | 20 +- .../modules/admin/debug/routes/logs.route.ts | 23 + .../api/modules/users/routes/test.route.ts | 4 +- .../vitnode/src/app_admin/core/debug/page.tsx | 14 +- packages/vitnode/src/components/ui/dialog.tsx | 2 +- packages/vitnode/src/database/logs.ts | 10 + packages/vitnode/src/locales/en.json | 26 +- .../system-logs/actions/more/content.tsx | 213 +++ .../debug/system-logs/actions/more/more.tsx | 69 + .../debug/system-logs/badges/badge-status.tsx | 17 + .../system-logs/badges/badge-type-log.tsx | 30 + .../system-logs-view.tsx} | 67 +- .../src/app_admin/blog/categories/page.tsx | 2 +- .../blog/src/app_admin/blog/posts/page.tsx | 2 +- .../actions}/delete/delete-action.tsx | 0 .../actions}/delete/mutation-api.ts | 0 .../actions}/edit-action.tsx | 2 +- .../{ => table}/categories-admin-view.tsx | 4 +- .../actions}/delete/delete-action.tsx | 0 .../actions}/delete/mutation-api.ts | 0 .../actions}/edit-action.tsx | 2 +- .../posts/{ => table}/posts-admin-view.tsx | 4 +- 29 files changed, 1944 insertions(+), 70 deletions(-) create mode 100644 apps/web/migrations/0001_thick_thor.sql create mode 100644 apps/web/migrations/meta/0001_snapshot.json create mode 100644 packages/vitnode/src/views/admin/views/core/debug/system-logs/actions/more/content.tsx create mode 100644 packages/vitnode/src/views/admin/views/core/debug/system-logs/actions/more/more.tsx create mode 100644 packages/vitnode/src/views/admin/views/core/debug/system-logs/badges/badge-status.tsx create mode 100644 packages/vitnode/src/views/admin/views/core/debug/system-logs/badges/badge-type-log.tsx rename packages/vitnode/src/views/admin/views/core/debug/{debug-admin-view.tsx => system-logs/system-logs-view.tsx} (62%) rename plugins/blog/src/views/admin/categories/{row-actions => table/actions}/delete/delete-action.tsx (100%) rename plugins/blog/src/views/admin/categories/{row-actions => table/actions}/delete/mutation-api.ts (100%) rename plugins/blog/src/views/admin/categories/{row-actions => table/actions}/edit-action.tsx (96%) rename plugins/blog/src/views/admin/categories/{ => table}/categories-admin-view.tsx (93%) rename plugins/blog/src/views/admin/posts/{row-actions => table/actions}/delete/delete-action.tsx (100%) rename plugins/blog/src/views/admin/posts/{row-actions => table/actions}/delete/mutation-api.ts (100%) rename plugins/blog/src/views/admin/posts/{row-actions => table/actions}/edit-action.tsx (96%) rename plugins/blog/src/views/admin/posts/{ => table}/posts-admin-view.tsx (93%) diff --git a/apps/web/migrations/0001_thick_thor.sql b/apps/web/migrations/0001_thick_thor.sql new file mode 100644 index 000000000..9bd467bd6 --- /dev/null +++ b/apps/web/migrations/0001_thick_thor.sql @@ -0,0 +1,6 @@ +ALTER TABLE "core_logs" ADD COLUMN "method" varchar(10) DEFAULT 'GET' NOT NULL;--> statement-breakpoint +ALTER TABLE "core_logs" ADD COLUMN "path" text DEFAULT 'localhost' NOT NULL;--> statement-breakpoint +ALTER TABLE "core_logs" ADD COLUMN "userAgent" text;--> statement-breakpoint +ALTER TABLE "core_logs" ADD COLUMN "statusCode" integer DEFAULT 500 NOT NULL;--> statement-breakpoint +ALTER TABLE "core_logs" ADD COLUMN "userId" bigint;--> statement-breakpoint +ALTER TABLE "core_logs" ADD CONSTRAINT "core_logs_userId_core_users_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."core_users"("id") ON DELETE set null ON UPDATE cascade; \ No newline at end of file diff --git a/apps/web/migrations/meta/0001_snapshot.json b/apps/web/migrations/meta/0001_snapshot.json new file mode 100644 index 000000000..ba74c370a --- /dev/null +++ b/apps/web/migrations/meta/0001_snapshot.json @@ -0,0 +1,1446 @@ +{ + "id": "5efac58e-292d-4cd6-865d-9e5d15b893a0", + "prevId": "960a9871-cd4a-4144-bc0a-af0717f397a7", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.core_admin_permissions": { + "name": "core_admin_permissions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "roleId": { + "name": "roleId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "userId": { + "name": "userId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "protected": { + "name": "protected", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": { + "core_admin_permissions_role_id_idx": { + "name": "core_admin_permissions_role_id_idx", + "columns": [ + { + "expression": "roleId", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "core_admin_permissions_user_id_idx": { + "name": "core_admin_permissions_user_id_idx", + "columns": [ + { + "expression": "userId", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "core_admin_permissions_roleId_core_roles_id_fk": { + "name": "core_admin_permissions_roleId_core_roles_id_fk", + "tableFrom": "core_admin_permissions", + "tableTo": "core_roles", + "columnsFrom": [ + "roleId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "core_admin_permissions_userId_core_users_id_fk": { + "name": "core_admin_permissions_userId_core_users_id_fk", + "tableFrom": "core_admin_permissions", + "tableTo": "core_users", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": true + }, + "public.core_admin_sessions": { + "name": "core_admin_sessions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "token": { + "name": "token", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "lastSeen": { + "name": "lastSeen", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "expiresAt": { + "name": "expiresAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "deviceId": { + "name": "deviceId", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "core_admin_sessions_token_idx": { + "name": "core_admin_sessions_token_idx", + "columns": [ + { + "expression": "token", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "core_admin_sessions_user_id_idx": { + "name": "core_admin_sessions_user_id_idx", + "columns": [ + { + "expression": "userId", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "core_admin_sessions_userId_core_users_id_fk": { + "name": "core_admin_sessions_userId_core_users_id_fk", + "tableFrom": "core_admin_sessions", + "tableTo": "core_users", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "core_admin_sessions_deviceId_core_sessions_known_devices_id_fk": { + "name": "core_admin_sessions_deviceId_core_sessions_known_devices_id_fk", + "tableFrom": "core_admin_sessions", + "tableTo": "core_sessions_known_devices", + "columnsFrom": [ + "deviceId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "core_admin_sessions_token_unique": { + "name": "core_admin_sessions_token_unique", + "nullsNotDistinct": false, + "columns": [ + "token" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": true + }, + "public.core_languages": { + "name": "core_languages", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "code": { + "name": "code", + "type": "varchar(32)", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "timezone": { + "name": "timezone", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "default": "'UTC'" + }, + "protected": { + "name": "protected", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "default": { + "name": "default", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "time24": { + "name": "time24", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": { + "core_languages_code_idx": { + "name": "core_languages_code_idx", + "columns": [ + { + "expression": "code", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "core_languages_name_idx": { + "name": "core_languages_name_idx", + "columns": [ + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "core_languages_code_unique": { + "name": "core_languages_code_unique", + "nullsNotDistinct": false, + "columns": [ + "code" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": true + }, + "public.core_languages_words": { + "name": "core_languages_words", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "languageCode": { + "name": "languageCode", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "pluginCode": { + "name": "pluginCode", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "itemId": { + "name": "itemId", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tableName": { + "name": "tableName", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "variable": { + "name": "variable", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "core_languages_words_lang_code_idx": { + "name": "core_languages_words_lang_code_idx", + "columns": [ + { + "expression": "languageCode", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "core_languages_words_languageCode_core_languages_code_fk": { + "name": "core_languages_words_languageCode_core_languages_code_fk", + "tableFrom": "core_languages_words", + "tableTo": "core_languages", + "columnsFrom": [ + "languageCode" + ], + "columnsTo": [ + "code" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": true + }, + "public.core_logs": { + "name": "core_logs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "pluginId": { + "name": "pluginId", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "coreLogsType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "ipAddress": { + "name": "ipAddress", + "type": "varchar(45)", + "primaryKey": false, + "notNull": true + }, + "method": { + "name": "method", + "type": "varchar(10)", + "primaryKey": false, + "notNull": true, + "default": "'GET'" + }, + "path": { + "name": "path", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'localhost'" + }, + "userAgent": { + "name": "userAgent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "statusCode": { + "name": "statusCode", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 500 + }, + "userId": { + "name": "userId", + "type": "bigint", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "core_logs_userId_core_users_id_fk": { + "name": "core_logs_userId_core_users_id_fk", + "tableFrom": "core_logs", + "tableTo": "core_users", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": true + }, + "public.core_moderators_permissions": { + "name": "core_moderators_permissions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "roleId": { + "name": "roleId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "userId": { + "name": "userId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "protected": { + "name": "protected", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": { + "core_moderators_permissions_role_id_idx": { + "name": "core_moderators_permissions_role_id_idx", + "columns": [ + { + "expression": "roleId", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "core_moderators_permissions_user_id_idx": { + "name": "core_moderators_permissions_user_id_idx", + "columns": [ + { + "expression": "userId", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "core_moderators_permissions_roleId_core_roles_id_fk": { + "name": "core_moderators_permissions_roleId_core_roles_id_fk", + "tableFrom": "core_moderators_permissions", + "tableTo": "core_roles", + "columnsFrom": [ + "roleId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "core_moderators_permissions_userId_core_users_id_fk": { + "name": "core_moderators_permissions_userId_core_users_id_fk", + "tableFrom": "core_moderators_permissions", + "tableTo": "core_users", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": true + }, + "public.core_roles": { + "name": "core_roles", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "protected": { + "name": "protected", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "default": { + "name": "default", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "root": { + "name": "root", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "guest": { + "name": "guest", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "color": { + "name": "color", + "type": "varchar(19)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": true + }, + "public.core_sessions": { + "name": "core_sessions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "token": { + "name": "token", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "expiresAt": { + "name": "expiresAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "deviceId": { + "name": "deviceId", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "core_sessions_user_id_idx": { + "name": "core_sessions_user_id_idx", + "columns": [ + { + "expression": "userId", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "core_sessions_userId_core_users_id_fk": { + "name": "core_sessions_userId_core_users_id_fk", + "tableFrom": "core_sessions", + "tableTo": "core_users", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "core_sessions_deviceId_core_sessions_known_devices_id_fk": { + "name": "core_sessions_deviceId_core_sessions_known_devices_id_fk", + "tableFrom": "core_sessions", + "tableTo": "core_sessions_known_devices", + "columnsFrom": [ + "deviceId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "core_sessions_token_unique": { + "name": "core_sessions_token_unique", + "nullsNotDistinct": false, + "columns": [ + "token" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": true + }, + "public.core_sessions_known_devices": { + "name": "core_sessions_known_devices", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "publicId": { + "name": "publicId", + "type": "varchar(32)", + "primaryKey": false, + "notNull": true + }, + "ipAddress": { + "name": "ipAddress", + "type": "varchar(40)", + "primaryKey": false, + "notNull": true + }, + "userAgent": { + "name": "userAgent", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "lastSeen": { + "name": "lastSeen", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "core_sessions_known_devices_ip_address_idx": { + "name": "core_sessions_known_devices_ip_address_idx", + "columns": [ + { + "expression": "ipAddress", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "core_sessions_known_devices_publicId_unique": { + "name": "core_sessions_known_devices_publicId_unique", + "nullsNotDistinct": false, + "columns": [ + "publicId" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": true + }, + "public.core_users": { + "name": "core_users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "nameCode": { + "name": "nameCode", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "newsletter": { + "name": "newsletter", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "avatarColor": { + "name": "avatarColor", + "type": "varchar(6)", + "primaryKey": false, + "notNull": true + }, + "emailVerified": { + "name": "emailVerified", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "roleId": { + "name": "roleId", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "birthday": { + "name": "birthday", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "ipAddress": { + "name": "ipAddress", + "type": "varchar(40)", + "primaryKey": false, + "notNull": true + }, + "language": { + "name": "language", + "type": "varchar(32)", + "primaryKey": false, + "notNull": true, + "default": "'en'" + } + }, + "indexes": { + "core_users_name_code_idx": { + "name": "core_users_name_code_idx", + "columns": [ + { + "expression": "nameCode", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "core_users_name_idx": { + "name": "core_users_name_idx", + "columns": [ + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "core_users_email_idx": { + "name": "core_users_email_idx", + "columns": [ + { + "expression": "email", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "core_users_roleId_core_roles_id_fk": { + "name": "core_users_roleId_core_roles_id_fk", + "tableFrom": "core_users", + "tableTo": "core_roles", + "columnsFrom": [ + "roleId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "core_users_language_core_languages_code_fk": { + "name": "core_users_language_core_languages_code_fk", + "tableFrom": "core_users", + "tableTo": "core_languages", + "columnsFrom": [ + "language" + ], + "columnsTo": [ + "code" + ], + "onDelete": "set default", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "core_users_nameCode_unique": { + "name": "core_users_nameCode_unique", + "nullsNotDistinct": false, + "columns": [ + "nameCode" + ] + }, + "core_users_name_unique": { + "name": "core_users_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + }, + "core_users_email_unique": { + "name": "core_users_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": true + }, + "public.core_users_confirm_emails": { + "name": "core_users_confirm_emails", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "core_users_confirm_emails_userId_core_users_id_fk": { + "name": "core_users_confirm_emails_userId_core_users_id_fk", + "tableFrom": "core_users_confirm_emails", + "tableTo": "core_users", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "core_users_confirm_emails_token_unique": { + "name": "core_users_confirm_emails_token_unique", + "nullsNotDistinct": false, + "columns": [ + "token" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": true + }, + "public.core_users_forgot_password": { + "name": "core_users_forgot_password", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true + }, + "ip_address": { + "name": "ip_address", + "type": "varchar(40)", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "expiresAt": { + "name": "expiresAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "core_users_forgot_password_userId_core_users_id_fk": { + "name": "core_users_forgot_password_userId_core_users_id_fk", + "tableFrom": "core_users_forgot_password", + "tableTo": "core_users", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "core_users_forgot_password_userId_unique": { + "name": "core_users_forgot_password_userId_unique", + "nullsNotDistinct": false, + "columns": [ + "userId" + ] + }, + "core_users_forgot_password_token_unique": { + "name": "core_users_forgot_password_token_unique", + "nullsNotDistinct": false, + "columns": [ + "token" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": true + }, + "public.core_users_sso": { + "name": "core_users_sso", + "schema": "", + "columns": { + "userId": { + "name": "userId", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "providerId": { + "name": "providerId", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "providerAccountId": { + "name": "providerAccountId", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "core_users_sso_user_id_idx": { + "name": "core_users_sso_user_id_idx", + "columns": [ + { + "expression": "userId", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "core_users_sso_userId_core_users_id_fk": { + "name": "core_users_sso_userId_core_users_id_fk", + "tableFrom": "core_users_sso", + "tableTo": "core_users", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": true + }, + "public.blog_categories": { + "name": "blog_categories", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "title": { + "name": "title", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "titleSeo": { + "name": "titleSeo", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "default": "''" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "blog_categories_titleSeo_unique": { + "name": "blog_categories_titleSeo_unique", + "nullsNotDistinct": false, + "columns": [ + "titleSeo" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": true + }, + "public.blog_posts": { + "name": "blog_posts", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "title": { + "name": "title", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "titleSeo": { + "name": "titleSeo", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "categoryId": { + "name": "categoryId", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "blog_posts_categoryId_blog_categories_id_fk": { + "name": "blog_posts_categoryId_blog_categories_id_fk", + "tableFrom": "blog_posts", + "tableTo": "blog_categories", + "columnsFrom": [ + "categoryId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "blog_posts_titleSeo_unique": { + "name": "blog_posts_titleSeo_unique", + "nullsNotDistinct": false, + "columns": [ + "titleSeo" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": true + } + }, + "enums": { + "public.coreLogsType": { + "name": "coreLogsType", + "schema": "public", + "values": [ + "warn", + "error", + "debug" + ] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/apps/web/migrations/meta/_journal.json b/apps/web/migrations/meta/_journal.json index 26c27fd9e..f4c39d31e 100644 --- a/apps/web/migrations/meta/_journal.json +++ b/apps/web/migrations/meta/_journal.json @@ -8,6 +8,13 @@ "when": 1750691750823, "tag": "0000_stormy_ronan", "breakpoints": true + }, + { + "idx": 1, + "version": "7", + "when": 1750876038988, + "tag": "0001_thick_thor", + "breakpoints": true } ] } \ No newline at end of file diff --git a/apps/web/src/app/[locale]/admin/(auth)/(plugins)/(vitnode-blog)/blog/categories/page.tsx b/apps/web/src/app/[locale]/admin/(auth)/(plugins)/(vitnode-blog)/blog/categories/page.tsx index dcc322a09..2f157905c 100644 --- a/apps/web/src/app/[locale]/admin/(auth)/(plugins)/(vitnode-blog)/blog/categories/page.tsx +++ b/apps/web/src/app/[locale]/admin/(auth)/(plugins)/(vitnode-blog)/blog/categories/page.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { ActionsCategoriesAdmin } from '@vitnode/blog/views/admin/categories/actions/actions'; const CategoriesAdminView = React.lazy(async () => - import('@vitnode/blog/views/admin/categories/categories-admin-view').then(mod => ({ + import('@vitnode/blog/views/admin/categories/table/categories-admin-view').then(mod => ({ default: mod.CategoriesAdminView, })), ); diff --git a/apps/web/src/app/[locale]/admin/(auth)/(plugins)/(vitnode-blog)/blog/posts/page.tsx b/apps/web/src/app/[locale]/admin/(auth)/(plugins)/(vitnode-blog)/blog/posts/page.tsx index 7f45c40e9..effb141df 100644 --- a/apps/web/src/app/[locale]/admin/(auth)/(plugins)/(vitnode-blog)/blog/posts/page.tsx +++ b/apps/web/src/app/[locale]/admin/(auth)/(plugins)/(vitnode-blog)/blog/posts/page.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { ActionsPostsAdmin } from '@vitnode/blog/views/admin/posts/actions/actions'; const PostsAdminView = React.lazy(async () => - import('@vitnode/blog/views/admin/posts/posts-admin-view').then(mod => ({ + import('@vitnode/blog/views/admin/posts/table/posts-admin-view').then(mod => ({ default: mod.PostsAdminView, })), ); diff --git a/apps/web/src/app/[locale]/admin/(auth)/(plugins)/(vitnode-core)/core/debug/page.tsx b/apps/web/src/app/[locale]/admin/(auth)/(plugins)/(vitnode-core)/core/debug/page.tsx index cfda4a29a..fa290ce5b 100644 --- a/apps/web/src/app/[locale]/admin/(auth)/(plugins)/(vitnode-core)/core/debug/page.tsx +++ b/apps/web/src/app/[locale]/admin/(auth)/(plugins)/(vitnode-core)/core/debug/page.tsx @@ -6,10 +6,12 @@ import { DataTableSkeleton } from '@vitnode/core/components/table/data-table'; import { HeaderContent } from '@vitnode/core/components/ui/header-content'; import { ClearCacheAction } from '@vitnode/core/views/admin/views/core/debug/actions/clear-cache/clear-cache'; -const DebugAdminView = React.lazy(async () => - import('@vitnode/core/views/admin/views/core/debug/debug-admin-view').then(module => ({ - default: module.DebugAdminView, - })), +const SystemLogsView = React.lazy(async () => + import('@vitnode/core/views/admin/views/core/debug/system-logs/system-logs-view').then( + module => ({ + default: module.SystemLogsView, + }), + ), ); export const generateMetadata = async () => { @@ -22,7 +24,7 @@ export const generateMetadata = async () => { }; export default async function Page( - props: React.ComponentProps, + props: React.ComponentProps, ) { const t = await getTranslations('admin.debug'); @@ -35,7 +37,7 @@ export default async function Page( }> - + diff --git a/apps/web/src/locales/@vitnode/core/en.json b/apps/web/src/locales/@vitnode/core/en.json index a3b9c9560..a9e3936d6 100644 --- a/apps/web/src/locales/@vitnode/core/en.json +++ b/apps/web/src/locales/@vitnode/core/en.json @@ -173,7 +173,6 @@ }, "logs": { "title": "System Logs", - "id": "ID", "created_at": "Created At", "plugin": "Plugin", "content": "Content", @@ -182,6 +181,31 @@ "warn": "Warning", "error": "Error", "debug": "Debug" + }, + "status_code": "Status Code", + "more": { + "title": "More Details", + "desc": "Log ID: ", + "log_overview": { + "title": "Log Overview", + "log_type": "Log Type", + "status_code": "Status Code", + "log_id": "Log ID", + "created_at": "Created At", + "plugin": "Plugin", + "user": "User" + }, + "request_information": { + "title": "Request Information", + "ip_address": "IP Address", + "request_method": "Request Method", + "request_url": "Request URL", + "user_agent": "User Agent" + }, + "log_content": { + "title": "Log Content", + "full_log": "Full Log Message" + } } } } diff --git a/packages/vitnode/src/api/lib/logger-middleware.ts b/packages/vitnode/src/api/lib/logger-middleware.ts index 929c0e2a9..aca6190b9 100644 --- a/packages/vitnode/src/api/lib/logger-middleware.ts +++ b/packages/vitnode/src/api/lib/logger-middleware.ts @@ -14,12 +14,20 @@ export const loggerMiddleware = (c: Context): LoggerMiddlewareType => { const pluginId = c.get('plugin')?.id ?? 'core'; const ipAddress = c.get('ipAddress'); - await c.get('db').insert(core_logs).values({ - pluginId, - type, - content, - ipAddress, - }); + await c + .get('db') + .insert(core_logs) + .values({ + pluginId, + type, + content, + ipAddress, + method: c.req.method.toUpperCase(), + path: c.req.path, + userAgent: c.req.header('User-Agent'), + statusCode: c.res.status, + userId: c.get('user')?.id, + }); const loggers: Record void> = { debug: msg => diff --git a/packages/vitnode/src/api/modules/admin/debug/routes/logs.route.ts b/packages/vitnode/src/api/modules/admin/debug/routes/logs.route.ts index a9d10cdab..591a768bc 100644 --- a/packages/vitnode/src/api/modules/admin/debug/routes/logs.route.ts +++ b/packages/vitnode/src/api/modules/admin/debug/routes/logs.route.ts @@ -1,8 +1,10 @@ +import { eq } from 'drizzle-orm'; import { z } from 'zod'; import { CONFIG_PLUGIN } from '@/config'; import { core_logs, coreLogsType } from '@/database/logs'; +import { core_users } from '../../../../../database/users'; import { buildRoute } from '../../../../lib/route'; import { withPagination, @@ -35,6 +37,17 @@ export const logsDebugAdminRoute = buildRoute({ content: z.string(), createdAt: z.date(), ipAddress: z.string(), + method: z.string(), + path: z.string(), + userAgent: z.string().nullable(), + statusCode: z.number(), + user: z + .object({ + id: z.number(), + name: z.string(), + nameCode: z.string(), + }) + .nullable(), }), ), pageInfo: zodPaginationPageInfo, @@ -62,8 +75,18 @@ export const logsDebugAdminRoute = buildRoute({ content: core_logs.content, createdAt: core_logs.createdAt, ipAddress: core_logs.ipAddress, + method: core_logs.method, + path: core_logs.path, + userAgent: core_logs.userAgent, + statusCode: core_logs.statusCode, + user: { + id: core_users.id, + name: core_users.name, + nameCode: core_users.nameCode, + }, }) .from(core_logs) + .leftJoin(core_users, eq(core_users.id, core_logs.userId)) .where(where) .orderBy(orderBy) .limit(limit), diff --git a/packages/vitnode/src/api/modules/users/routes/test.route.ts b/packages/vitnode/src/api/modules/users/routes/test.route.ts index 817ac56aa..ffb60135d 100644 --- a/packages/vitnode/src/api/modules/users/routes/test.route.ts +++ b/packages/vitnode/src/api/modules/users/routes/test.route.ts @@ -8,7 +8,7 @@ import { CONFIG_PLUGIN } from '@/config'; export const testRoute = buildRoute({ ...CONFIG_PLUGIN, route: { - method: 'get', + method: 'post', description: 'Test route', path: '/test', responses: { @@ -39,7 +39,7 @@ export const testRoute = buildRoute({ // throw new Error('Test error'); - // c.get('log').warn('This is a test warn log'); + c.get('log').warn('This is a test warn log'); return c.text('test'); }, diff --git a/packages/vitnode/src/app_admin/core/debug/page.tsx b/packages/vitnode/src/app_admin/core/debug/page.tsx index 1447ad4fa..519f5a32f 100644 --- a/packages/vitnode/src/app_admin/core/debug/page.tsx +++ b/packages/vitnode/src/app_admin/core/debug/page.tsx @@ -6,10 +6,12 @@ import { DataTableSkeleton } from '@/components/table/data-table'; import { HeaderContent } from '@/components/ui/header-content'; import { ClearCacheAction } from '@/views/admin/views/core/debug/actions/clear-cache/clear-cache'; -const DebugAdminView = React.lazy(async () => - import('@/views/admin/views/core/debug/debug-admin-view').then(module => ({ - default: module.DebugAdminView, - })), +const SystemLogsView = React.lazy(async () => + import('@/views/admin/views/core/debug/system-logs/system-logs-view').then( + module => ({ + default: module.SystemLogsView, + }), + ), ); export const generateMetadata = async () => { @@ -22,7 +24,7 @@ export const generateMetadata = async () => { }; export default async function Page( - props: React.ComponentProps, + props: React.ComponentProps, ) { const t = await getTranslations('admin.debug'); @@ -35,7 +37,7 @@ export default async function Page( }> - + diff --git a/packages/vitnode/src/components/ui/dialog.tsx b/packages/vitnode/src/components/ui/dialog.tsx index e56ea2992..722989377 100644 --- a/packages/vitnode/src/components/ui/dialog.tsx +++ b/packages/vitnode/src/components/ui/dialog.tsx @@ -165,7 +165,7 @@ function DialogContent({ ({ content: t.text().notNull(), createdAt: t.timestamp().notNull().defaultNow(), ipAddress: t.varchar({ length: 45 }).notNull(), + method: t.varchar({ length: 10 }).notNull().default('GET'), + path: t.text().notNull().default('localhost'), + userAgent: t.text(), + statusCode: t.integer().notNull().default(500), + userId: t.bigint({ mode: 'number' }).references(() => core_users.id, { + onDelete: 'set null', + onUpdate: 'cascade', + }), })).enableRLS(); diff --git a/packages/vitnode/src/locales/en.json b/packages/vitnode/src/locales/en.json index a3b9c9560..a9e3936d6 100644 --- a/packages/vitnode/src/locales/en.json +++ b/packages/vitnode/src/locales/en.json @@ -173,7 +173,6 @@ }, "logs": { "title": "System Logs", - "id": "ID", "created_at": "Created At", "plugin": "Plugin", "content": "Content", @@ -182,6 +181,31 @@ "warn": "Warning", "error": "Error", "debug": "Debug" + }, + "status_code": "Status Code", + "more": { + "title": "More Details", + "desc": "Log ID: ", + "log_overview": { + "title": "Log Overview", + "log_type": "Log Type", + "status_code": "Status Code", + "log_id": "Log ID", + "created_at": "Created At", + "plugin": "Plugin", + "user": "User" + }, + "request_information": { + "title": "Request Information", + "ip_address": "IP Address", + "request_method": "Request Method", + "request_url": "Request URL", + "user_agent": "User Agent" + }, + "log_content": { + "title": "Log Content", + "full_log": "Full Log Message" + } } } } diff --git a/packages/vitnode/src/views/admin/views/core/debug/system-logs/actions/more/content.tsx b/packages/vitnode/src/views/admin/views/core/debug/system-logs/actions/more/content.tsx new file mode 100644 index 000000000..8f44d0458 --- /dev/null +++ b/packages/vitnode/src/views/admin/views/core/debug/system-logs/actions/more/content.tsx @@ -0,0 +1,213 @@ +import { + CalendarIcon, + GlobeIcon, + HashIcon, + PlugIcon, + ServerIcon, + UserIcon, +} from 'lucide-react'; +import { useTranslations } from 'next-intl'; + +import { DateFormat } from '@/components/date-format'; +import { Badge } from '@/components/ui/badge'; +import { Card, CardContent, 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 { Link } from '@/lib/navigation'; + +import type { getSystemLogsData } from '../../system-logs-view'; + +import { BadgeStatus } from '../../badges/badge-status'; +import { BadgeTypeLog } from '../../badges/badge-type-log'; + +export const ContentMoreActionSystemLogs = ({ + content, + ipAddress, + pluginId, + createdAt, + type, + id, + method, + path, + userAgent, + statusCode, + user, +}: Awaited>['edges'][number]) => { + const t = useTranslations('admin.debug.logs.more'); + + return ( +
+ + + + + {t('log_overview.title')} + + + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ +
+ +
+
+
+ + +
+ {user && ( +
+ + + {user.name} (#{user.id}) + +
+ )} +
+
+
+ + + + + + {t('request_information.title')} + + + +
+
+ + +
+
+ +
+ + {method} + +
+
+
+ +
+ + +
+ + {userAgent && ( +
+ +