From 9ae67fd303c4a35de18c145d22ba3d543a0d3297 Mon Sep 17 00:00:00 2001 From: kimatata <117462761+kimatata@users.noreply.github.com> Date: Sun, 20 Jul 2025 10:59:57 +0900 Subject: [PATCH] fix: eslint warnings (#252) --- backend/config/config.js | 1 - backend/middleware/auth.js | 3 +- backend/middleware/verifyEditable.js | 2 +- .../migrations/20240201220834-create-users.js | 2 +- .../20240204090345-create-projects.js | 2 +- .../20240212022145-create-folders.js | 2 +- .../migrations/20240212082050-create-runs.js | 2 +- .../migrations/20240212084228-create-cases.js | 2 +- .../migrations/20240229095914-create-steps.js | 2 +- .../20240229100158-create-cases-steps.js | 2 +- .../20240316200815-create-attachments.js | 2 +- ...20240316201158-create-cases-attachments.js | 2 +- .../20240407182431-create-runs-cases.js | 2 +- .../20240529221509-create-members.js | 2 +- .../migrations/20240930124156-rename_table.js | 4 +- backend/models/index.js | 2 +- backend/routes/cases/delete.js | 2 +- backend/routes/cases/edit.js | 4 +- backend/routes/cases/index.js | 2 +- backend/routes/cases/indexByProjectId.js | 2 +- backend/routes/cases/new.js | 3 +- backend/routes/cases/show.js | 2 +- backend/routes/folders/delete.js | 2 +- backend/routes/folders/edit.js | 2 +- backend/routes/folders/index.js | 2 +- backend/routes/folders/new.js | 3 +- backend/routes/home/index.js | 2 +- backend/routes/members/check.js | 2 +- backend/routes/members/delete.js | 2 +- backend/routes/members/edit.js | 2 +- backend/routes/members/index.js | 2 +- backend/routes/members/new.js | 2 +- backend/routes/projects/delete.js | 2 +- backend/routes/projects/edit.js | 2 +- backend/routes/projects/new.js | 2 +- backend/routes/projects/show.js | 2 +- backend/routes/runcases/edit.js | 2 +- backend/routes/runcases/index.js | 2 +- backend/routes/runs/delete.js | 2 +- backend/routes/runs/edit.js | 2 +- backend/routes/runs/index.js | 2 +- backend/routes/runs/new.js | 3 +- backend/routes/runs/show.js | 2 +- backend/routes/steps/edit.js | 2 +- backend/routes/users/find.js | 2 +- backend/routes/users/index.js | 2 +- backend/routes/users/search.js | 2 +- backend/routes/users/signin.js | 2 +- backend/routes/users/signup.js | 4 +- backend/routes/users/update.mjs | 2 +- backend/routes/users/update.test.js | 4 +- backend/seeders/seed.js | 6 +- combined_server.js | 2 +- frontend/components/ProjectDialog.tsx | 3 +- frontend/components/ThemeSwitch.tsx | 6 +- frontend/components/UserAvatar.tsx | 2 +- frontend/src/app/[locale]/DropdownAccount.tsx | 2 +- .../src/app/[locale]/HeaderNavbarMenu.tsx | 9 +- .../src/app/[locale]/account/AccountPage.tsx | 17 +-- .../src/app/[locale]/account/authControl.ts | 9 +- .../src/app/[locale]/account/authPage.tsx | 7 +- frontend/src/app/[locale]/account/layout.tsx | 2 +- .../src/app/[locale]/account/signin/page.tsx | 4 +- .../src/app/[locale]/account/signup/page.tsx | 4 +- frontend/src/app/[locale]/admin/AdminPage.tsx | 14 +- .../src/app/[locale]/admin/UsersTable.tsx | 2 +- .../src/app/[locale]/health/HealthPage.tsx | 9 +- frontend/src/app/[locale]/layout.tsx | 8 +- .../app/[locale]/projects/ProjectsPage.tsx | 7 +- .../app/[locale]/projects/ProjectsTable.tsx | 64 +++++---- .../[projectId]/folders/FolderDialog.tsx | 3 +- .../[projectId]/folders/FoldersPane.tsx | 15 ++- .../folders/[folderId]/cases/CaseDialog.tsx | 3 +- .../folders/[folderId]/cases/CasesPane.tsx | 5 +- .../[folderId]/cases/TestCaseTable.tsx | 3 +- .../[folderId]/cases/[caseId]/CaseEditor.tsx | 13 +- .../cases/[caseId]/CaseStepsEditor.tsx | 2 +- .../cases/[caseId]/attachmentControl.ts | 13 +- .../[folderId]/cases/[caseId]/page.tsx | 4 +- .../[folderId]/cases/[caseId]/stepControl.ts | 5 +- .../[projectId]/folders/foldersControl.ts | 17 +-- .../projects/[projectId]/folders/layout.tsx | 2 +- .../projects/[projectId]/home/ProjectHome.tsx | 27 ++-- .../home/TestPriorityDonutChart.tsx | 5 +- .../home/TestProgressColumnChart.tsx | 3 +- .../[projectId]/home/TestTypesDonutChart.tsx | 5 +- .../projects/[projectId]/home/aggregate.ts | 8 +- .../projects/[projectId]/home/page.tsx | 4 +- .../[locale]/projects/[projectId]/layout.tsx | 4 +- .../[projectId]/members/AddMemberDialog.tsx | 10 +- .../[projectId]/members/CandidatesTable.tsx | 57 ++++---- .../[projectId]/members/MembersPage.tsx | 17 ++- .../[projectId]/members/MembersTable.tsx | 2 +- .../[projectId]/members/membersControl.ts | 17 +-- .../projects/[projectId]/members/page.tsx | 6 +- .../projects/[projectId]/runs/RunDialog.tsx | 3 +- .../projects/[projectId]/runs/RunsPage.tsx | 7 +- .../projects/[projectId]/runs/RunsTable.tsx | 7 +- .../[projectId]/runs/[runId]/RunEditor.tsx | 10 +- .../runs/[runId]/RunPregressDonutChart.tsx | 5 +- .../runs/[runId]/TestCaseDetailDialog.tsx | 7 +- .../runs/[runId]/TestCaseSelector.tsx | 9 +- .../[projectId]/runs/[runId]/page.tsx | 2 +- .../projects/[projectId]/runs/runsControl.ts | 37 +++--- .../[projectId]/settings/SettingsPage.tsx | 8 +- .../projects/[projectId]/settings/page.tsx | 6 +- frontend/src/app/[locale]/projects/layout.tsx | 2 +- frontend/src/app/[locale]/projects/page.tsx | 4 +- .../app/[locale]/projects/projectsControl.ts | 123 ------------------ frontend/src/i18n/request.ts | 2 +- frontend/utils/TokenProvider.tsx | 27 ++-- frontend/utils/caseControl.ts | 28 ++-- frontend/utils/errorHandler.ts | 10 ++ frontend/utils/formGuard.ts | 2 +- frontend/utils/projectsControl.ts | 73 ++++++----- frontend/utils/token.ts | 7 +- frontend/utils/usersControl.ts | 13 +- vitest.config.ts | 2 +- 118 files changed, 423 insertions(+), 511 deletions(-) delete mode 100644 frontend/src/app/[locale]/projects/projectsControl.ts create mode 100644 frontend/utils/errorHandler.ts diff --git a/backend/config/config.js b/backend/config/config.js index d514651..962fb95 100644 --- a/backend/config/config.js +++ b/backend/config/config.js @@ -1,5 +1,4 @@ const path = require('path'); - const databasePath = path.resolve(__dirname, '../database/database.sqlite'); module.exports = { diff --git a/backend/middleware/auth.js b/backend/middleware/auth.js index 04b5e8d..daf6e53 100644 --- a/backend/middleware/auth.js +++ b/backend/middleware/auth.js @@ -1,6 +1,6 @@ const jwt = require('jsonwebtoken'); -const { roles, defaultDangerKey } = require('../routes/users/authSettings'); const { DataTypes } = require('sequelize'); +const { roles, defaultDangerKey } = require('../routes/users/authSettings'); const defineUser = require('../models/users'); function authMiddleware(sequelize) { @@ -23,6 +23,7 @@ function authMiddleware(sequelize) { req.userId = decoded.userId; next(); } catch (error) { + console.error('Token verification failed:', error); res.status(401).json({ error: 'Invalid token' }); } } diff --git a/backend/middleware/verifyEditable.js b/backend/middleware/verifyEditable.js index 9e79921..af6120b 100644 --- a/backend/middleware/verifyEditable.js +++ b/backend/middleware/verifyEditable.js @@ -1,5 +1,5 @@ -const { memberRoles } = require('../routes/users/authSettings'); const { DataTypes } = require('sequelize'); +const { memberRoles } = require('../routes/users/authSettings'); const defineMember = require('../models/members'); const defineProject = require('../models/projects'); const defineFolder = require('../models/folders'); diff --git a/backend/migrations/20240201220834-create-users.js b/backend/migrations/20240201220834-create-users.js index 539bade..04e7d06 100644 --- a/backend/migrations/20240201220834-create-users.js +++ b/backend/migrations/20240201220834-create-users.js @@ -40,7 +40,7 @@ module.exports = { }); }, - down: async (queryInterface, Sequelize) => { + down: async (queryInterface) => { await queryInterface.dropTable('users'); }, }; diff --git a/backend/migrations/20240204090345-create-projects.js b/backend/migrations/20240204090345-create-projects.js index 4fbf7a9..1603d3a 100644 --- a/backend/migrations/20240204090345-create-projects.js +++ b/backend/migrations/20240204090345-create-projects.js @@ -42,7 +42,7 @@ module.exports = { }); }, - down: async (queryInterface, Sequelize) => { + down: async (queryInterface) => { await queryInterface.dropTable('projects'); }, }; diff --git a/backend/migrations/20240212022145-create-folders.js b/backend/migrations/20240212022145-create-folders.js index 01f60dc..64806ab 100644 --- a/backend/migrations/20240212022145-create-folders.js +++ b/backend/migrations/20240212022145-create-folders.js @@ -42,7 +42,7 @@ module.exports = { }); }, - async down(queryInterface, Sequelize) { + async down(queryInterface) { await queryInterface.dropTable('folders'); }, }; diff --git a/backend/migrations/20240212082050-create-runs.js b/backend/migrations/20240212082050-create-runs.js index dad3e1d..55e9fc0 100644 --- a/backend/migrations/20240212082050-create-runs.js +++ b/backend/migrations/20240212082050-create-runs.js @@ -46,7 +46,7 @@ module.exports = { }); }, - async down(queryInterface, Sequelize) { + async down(queryInterface) { await queryInterface.dropTable('runs'); }, }; diff --git a/backend/migrations/20240212084228-create-cases.js b/backend/migrations/20240212084228-create-cases.js index 5564161..4ae2213 100644 --- a/backend/migrations/20240212084228-create-cases.js +++ b/backend/migrations/20240212084228-create-cases.js @@ -66,7 +66,7 @@ module.exports = { }); }, - async down(queryInterface, Sequelize) { + async down(queryInterface) { await queryInterface.dropTable('cases'); }, }; diff --git a/backend/migrations/20240229095914-create-steps.js b/backend/migrations/20240229095914-create-steps.js index 5cb30e8..9662b15 100644 --- a/backend/migrations/20240229095914-create-steps.js +++ b/backend/migrations/20240229095914-create-steps.js @@ -28,7 +28,7 @@ module.exports = { }); }, - down: async (queryInterface, Sequelize) => { + down: async (queryInterface) => { await queryInterface.dropTable('steps'); }, }; diff --git a/backend/migrations/20240229100158-create-cases-steps.js b/backend/migrations/20240229100158-create-cases-steps.js index 28c17f9..ff66e7e 100644 --- a/backend/migrations/20240229100158-create-cases-steps.js +++ b/backend/migrations/20240229100158-create-cases-steps.js @@ -46,7 +46,7 @@ module.exports = { }); }, - down: async (queryInterface, Sequelize) => { + down: async (queryInterface) => { await queryInterface.dropTable('caseSteps'); }, }; diff --git a/backend/migrations/20240316200815-create-attachments.js b/backend/migrations/20240316200815-create-attachments.js index cbd51c0..bc2044e 100644 --- a/backend/migrations/20240316200815-create-attachments.js +++ b/backend/migrations/20240316200815-create-attachments.js @@ -32,7 +32,7 @@ module.exports = { }); }, - async down(queryInterface, Sequelize) { + async down(queryInterface) { await queryInterface.dropTable('attachments'); }, }; diff --git a/backend/migrations/20240316201158-create-cases-attachments.js b/backend/migrations/20240316201158-create-cases-attachments.js index edd4812..d7712c4 100644 --- a/backend/migrations/20240316201158-create-cases-attachments.js +++ b/backend/migrations/20240316201158-create-cases-attachments.js @@ -42,7 +42,7 @@ module.exports = { }); }, - down: async (queryInterface, Sequelize) => { + down: async (queryInterface) => { await queryInterface.dropTable('caseAttachments'); }, }; diff --git a/backend/migrations/20240407182431-create-runs-cases.js b/backend/migrations/20240407182431-create-runs-cases.js index 536fd47..dbc2d22 100644 --- a/backend/migrations/20240407182431-create-runs-cases.js +++ b/backend/migrations/20240407182431-create-runs-cases.js @@ -46,7 +46,7 @@ module.exports = { }); }, - down: async (queryInterface, Sequelize) => { + down: async (queryInterface) => { await queryInterface.dropTable('runCases'); }, }; diff --git a/backend/migrations/20240529221509-create-members.js b/backend/migrations/20240529221509-create-members.js index a28aff0..ed7576a 100644 --- a/backend/migrations/20240529221509-create-members.js +++ b/backend/migrations/20240529221509-create-members.js @@ -46,7 +46,7 @@ module.exports = { }); }, - down: async (queryInterface, Sequelize) => { + down: async (queryInterface) => { await queryInterface.dropTable('members'); }, }; diff --git a/backend/migrations/20240930124156-rename_table.js b/backend/migrations/20240930124156-rename_table.js index 2ba10b5..c8e572d 100644 --- a/backend/migrations/20240930124156-rename_table.js +++ b/backend/migrations/20240930124156-rename_table.js @@ -2,7 +2,7 @@ /** @type {import('sequelize-cli').Migration} */ module.exports = { - async up(queryInterface, Sequelize) { + async up(queryInterface) { /** * Add altering commands here. * @@ -15,7 +15,7 @@ module.exports = { await queryInterface.renameColumn('users', 'avatarPath', 'avatar_path'); }, - async down(queryInterface, Sequelize) { + async down() { /** * Add reverting commands here. * diff --git a/backend/models/index.js b/backend/models/index.js index e42d923..e57f031 100644 --- a/backend/models/index.js +++ b/backend/models/index.js @@ -2,8 +2,8 @@ const fs = require('fs'); const path = require('path'); -const Sequelize = require('sequelize'); const process = require('process'); +const Sequelize = require('sequelize'); const basename = path.basename(__filename); const env = process.env.NODE_ENV || 'development'; const config = require(__dirname + '/../config/config.json')[env]; diff --git a/backend/routes/cases/delete.js b/backend/routes/cases/delete.js index 8f6a4f5..62e880d 100644 --- a/backend/routes/cases/delete.js +++ b/backend/routes/cases/delete.js @@ -1,7 +1,7 @@ const express = require('express'); const router = express.Router(); -const defineCase = require('../../models/cases'); const { DataTypes } = require('sequelize'); +const defineCase = require('../../models/cases'); module.exports = function (sequelize) { const { verifySignedIn } = require('../../middleware/auth')(sequelize); diff --git a/backend/routes/cases/edit.js b/backend/routes/cases/edit.js index 6154445..bb5848c 100644 --- a/backend/routes/cases/edit.js +++ b/backend/routes/cases/edit.js @@ -1,14 +1,12 @@ const express = require('express'); const router = express.Router(); -const defineCase = require('../../models/cases'); -const defineStep = require('../../models/steps'); const { DataTypes } = require('sequelize'); +const defineCase = require('../../models/cases'); module.exports = function (sequelize) { const { verifySignedIn } = require('../../middleware/auth')(sequelize); const { verifyProjectDeveloperFromCaseId } = require('../../middleware/verifyEditable')(sequelize); const Case = defineCase(sequelize, DataTypes); - const Step = defineStep(sequelize, DataTypes); router.put('/:caseId', verifySignedIn, verifyProjectDeveloperFromCaseId, async (req, res) => { const caseId = req.params.caseId; diff --git a/backend/routes/cases/index.js b/backend/routes/cases/index.js index d2b0666..170cf1f 100644 --- a/backend/routes/cases/index.js +++ b/backend/routes/cases/index.js @@ -1,7 +1,7 @@ const express = require('express'); const router = express.Router(); -const defineCase = require('../../models/cases'); const { DataTypes } = require('sequelize'); +const defineCase = require('../../models/cases'); module.exports = function (sequelize) { const Case = defineCase(sequelize, DataTypes); diff --git a/backend/routes/cases/indexByProjectId.js b/backend/routes/cases/indexByProjectId.js index 35c56ec..4c99002 100644 --- a/backend/routes/cases/indexByProjectId.js +++ b/backend/routes/cases/indexByProjectId.js @@ -1,10 +1,10 @@ const express = require('express'); const router = express.Router(); +const { DataTypes } = require('sequelize'); const defineProject = require('../../models/projects'); const defineFolder = require('../../models/folders'); const defineCase = require('../../models/cases'); const defineRunCase = require('../../models/runCases'); -const { DataTypes } = require('sequelize'); module.exports = function (sequelize) { const Project = defineProject(sequelize, DataTypes); diff --git a/backend/routes/cases/new.js b/backend/routes/cases/new.js index 936b0c4..958f36f 100644 --- a/backend/routes/cases/new.js +++ b/backend/routes/cases/new.js @@ -1,7 +1,7 @@ const express = require('express'); const router = express.Router(); -const defineCase = require('../../models/cases'); const { DataTypes } = require('sequelize'); +const defineCase = require('../../models/cases'); const requiredFields = ['title', 'state', 'priority', 'type', 'automationStatus', 'template']; @@ -50,6 +50,7 @@ module.exports = function (sequelize) { res.json(newCase); } catch (error) { + console.error('Error creating new case:', error); res.status(500).json({ error: 'Internal server error' }); } }); diff --git a/backend/routes/cases/show.js b/backend/routes/cases/show.js index 4b936ad..a54ee05 100644 --- a/backend/routes/cases/show.js +++ b/backend/routes/cases/show.js @@ -1,9 +1,9 @@ const express = require('express'); const router = express.Router(); +const { DataTypes } = require('sequelize'); const defineCase = require('../../models/cases'); const defineStep = require('../../models/steps'); const defineAttachment = require('../../models/attachments'); -const { DataTypes } = require('sequelize'); module.exports = function (sequelize) { const Case = defineCase(sequelize, DataTypes); diff --git a/backend/routes/folders/delete.js b/backend/routes/folders/delete.js index 0085313..2eeb061 100644 --- a/backend/routes/folders/delete.js +++ b/backend/routes/folders/delete.js @@ -1,7 +1,7 @@ const express = require('express'); const router = express.Router(); -const defineFolder = require('../../models/folders'); const { DataTypes } = require('sequelize'); +const defineFolder = require('../../models/folders'); module.exports = function (sequelize) { const { verifySignedIn } = require('../../middleware/auth')(sequelize); diff --git a/backend/routes/folders/edit.js b/backend/routes/folders/edit.js index 8c2be86..d0472f2 100644 --- a/backend/routes/folders/edit.js +++ b/backend/routes/folders/edit.js @@ -1,7 +1,7 @@ const express = require('express'); const router = express.Router(); -const defineFolder = require('../../models/folders'); const { DataTypes } = require('sequelize'); +const defineFolder = require('../../models/folders'); module.exports = function (sequelize) { const { verifySignedIn } = require('../../middleware/auth')(sequelize); diff --git a/backend/routes/folders/index.js b/backend/routes/folders/index.js index 2c34bee..611796e 100644 --- a/backend/routes/folders/index.js +++ b/backend/routes/folders/index.js @@ -1,7 +1,7 @@ const express = require('express'); const router = express.Router(); -const defineFolder = require('../../models/folders'); const { DataTypes } = require('sequelize'); +const defineFolder = require('../../models/folders'); module.exports = function (sequelize) { const { verifySignedIn } = require('../../middleware/auth')(sequelize); diff --git a/backend/routes/folders/new.js b/backend/routes/folders/new.js index e068000..f184556 100644 --- a/backend/routes/folders/new.js +++ b/backend/routes/folders/new.js @@ -1,7 +1,7 @@ const express = require('express'); const router = express.Router(); -const defineFolder = require('../../models/folders'); const { DataTypes } = require('sequelize'); +const defineFolder = require('../../models/folders'); module.exports = function (sequelize) { const { verifySignedIn } = require('../../middleware/auth')(sequelize); @@ -25,6 +25,7 @@ module.exports = function (sequelize) { res.json(newFolder); } catch (error) { + console.error('Error creating new folder:', error); res.status(500).json({ error: 'Internal server error' }); } }); diff --git a/backend/routes/home/index.js b/backend/routes/home/index.js index a410a42..292d81e 100644 --- a/backend/routes/home/index.js +++ b/backend/routes/home/index.js @@ -1,11 +1,11 @@ const express = require('express'); const router = express.Router(); +const { DataTypes } = require('sequelize'); const defineProject = require('../../models/projects'); const defineFolder = require('../../models/folders'); const defineCase = require('../../models/cases'); const defineRun = require('../../models/runs'); const defineRunCase = require('../../models/runCases'); -const { DataTypes } = require('sequelize'); module.exports = function (sequelize) { const { verifySignedIn } = require('../../middleware/auth')(sequelize); diff --git a/backend/routes/members/check.js b/backend/routes/members/check.js index 598dd0c..f68ddd1 100644 --- a/backend/routes/members/check.js +++ b/backend/routes/members/check.js @@ -1,8 +1,8 @@ const express = require('express'); const router = express.Router(); +const { DataTypes } = require('sequelize'); const defineMember = require('../../models/members'); const defineProject = require('../../models/projects'); -const { DataTypes } = require('sequelize'); module.exports = function (sequelize) { const { verifySignedIn } = require('../../middleware/auth')(sequelize); diff --git a/backend/routes/members/delete.js b/backend/routes/members/delete.js index ec0208f..dc02283 100644 --- a/backend/routes/members/delete.js +++ b/backend/routes/members/delete.js @@ -1,7 +1,7 @@ const express = require('express'); const router = express.Router(); -const defineMember = require('../../models/members'); const { DataTypes } = require('sequelize'); +const defineMember = require('../../models/members'); module.exports = function (sequelize) { const { verifySignedIn } = require('../../middleware/auth')(sequelize); diff --git a/backend/routes/members/edit.js b/backend/routes/members/edit.js index c975270..6c7c64e 100644 --- a/backend/routes/members/edit.js +++ b/backend/routes/members/edit.js @@ -1,7 +1,7 @@ const express = require('express'); const router = express.Router(); -const defineMember = require('../../models/members'); const { DataTypes } = require('sequelize'); +const defineMember = require('../../models/members'); module.exports = function (sequelize) { const { verifySignedIn } = require('../../middleware/auth')(sequelize); diff --git a/backend/routes/members/index.js b/backend/routes/members/index.js index 902059b..415ebc1 100644 --- a/backend/routes/members/index.js +++ b/backend/routes/members/index.js @@ -1,8 +1,8 @@ const express = require('express'); const router = express.Router(); +const { DataTypes } = require('sequelize'); const defineUser = require('../../models/users'); const defineMember = require('../../models/members'); -const { DataTypes } = require('sequelize'); module.exports = function (sequelize) { const { verifySignedIn } = require('../../middleware/auth')(sequelize); diff --git a/backend/routes/members/new.js b/backend/routes/members/new.js index ade8aab..f82ca44 100644 --- a/backend/routes/members/new.js +++ b/backend/routes/members/new.js @@ -1,7 +1,7 @@ const express = require('express'); const router = express.Router(); -const defineMember = require('../../models/members'); const { DataTypes } = require('sequelize'); +const defineMember = require('../../models/members'); const { memberRoles } = require('../../routes/users/authSettings'); module.exports = function (sequelize) { diff --git a/backend/routes/projects/delete.js b/backend/routes/projects/delete.js index 47dadc6..40a1ab3 100644 --- a/backend/routes/projects/delete.js +++ b/backend/routes/projects/delete.js @@ -1,9 +1,9 @@ const express = require('express'); const router = express.Router(); +const { DataTypes } = require('sequelize'); const defineProject = require('../../models/projects'); const defineFolder = require('../../models/folders'); const defineRun = require('../../models/runs'); -const { DataTypes } = require('sequelize'); module.exports = function (sequelize) { const { verifySignedIn } = require('../../middleware/auth')(sequelize); diff --git a/backend/routes/projects/edit.js b/backend/routes/projects/edit.js index a90c65b..1130999 100644 --- a/backend/routes/projects/edit.js +++ b/backend/routes/projects/edit.js @@ -1,7 +1,7 @@ const express = require('express'); const router = express.Router(); -const defineProject = require('../../models/projects'); const { DataTypes } = require('sequelize'); +const defineProject = require('../../models/projects'); module.exports = function (sequelize) { const { verifySignedIn } = require('../../middleware/auth')(sequelize); diff --git a/backend/routes/projects/new.js b/backend/routes/projects/new.js index 74296fc..247ef54 100644 --- a/backend/routes/projects/new.js +++ b/backend/routes/projects/new.js @@ -1,7 +1,7 @@ const express = require('express'); const router = express.Router(); -const defineProject = require('../../models/projects'); const { DataTypes } = require('sequelize'); +const defineProject = require('../../models/projects'); module.exports = function (sequelize) { const { verifySignedIn } = require('../../middleware/auth')(sequelize); diff --git a/backend/routes/projects/show.js b/backend/routes/projects/show.js index 8594577..d83bf01 100644 --- a/backend/routes/projects/show.js +++ b/backend/routes/projects/show.js @@ -1,8 +1,8 @@ const express = require('express'); const router = express.Router(); +const { DataTypes } = require('sequelize'); const defineProject = require('../../models/projects'); const defineFolder = require('../../models/folders'); -const { DataTypes } = require('sequelize'); module.exports = function (sequelize) { const { verifySignedIn } = require('../../middleware/auth')(sequelize); diff --git a/backend/routes/runcases/edit.js b/backend/routes/runcases/edit.js index 6819418..962f42d 100644 --- a/backend/routes/runcases/edit.js +++ b/backend/routes/runcases/edit.js @@ -1,7 +1,7 @@ const express = require('express'); const router = express.Router(); -const defineRunCase = require('../../models/runCases'); const { DataTypes } = require('sequelize'); +const defineRunCase = require('../../models/runCases'); module.exports = function (sequelize) { const { verifySignedIn } = require('../../middleware/auth')(sequelize); diff --git a/backend/routes/runcases/index.js b/backend/routes/runcases/index.js index ba1dacc..7b17d2c 100644 --- a/backend/routes/runcases/index.js +++ b/backend/routes/runcases/index.js @@ -1,7 +1,7 @@ const express = require('express'); const router = express.Router(); -const defineRunCase = require('../../models/runCases'); const { DataTypes } = require('sequelize'); +const defineRunCase = require('../../models/runCases'); module.exports = function (sequelize) { const { verifySignedIn } = require('../../middleware/auth')(sequelize); diff --git a/backend/routes/runs/delete.js b/backend/routes/runs/delete.js index 3b32069..2bde53c 100644 --- a/backend/routes/runs/delete.js +++ b/backend/routes/runs/delete.js @@ -1,7 +1,7 @@ const express = require('express'); const router = express.Router(); -const defineRun = require('../../models/runs'); const { DataTypes } = require('sequelize'); +const defineRun = require('../../models/runs'); module.exports = function (sequelize) { const { verifySignedIn } = require('../../middleware/auth')(sequelize); diff --git a/backend/routes/runs/edit.js b/backend/routes/runs/edit.js index e921c3b..5f05b80 100644 --- a/backend/routes/runs/edit.js +++ b/backend/routes/runs/edit.js @@ -1,7 +1,7 @@ const express = require('express'); const router = express.Router(); -const defineRun = require('../../models/runs'); const { DataTypes } = require('sequelize'); +const defineRun = require('../../models/runs'); module.exports = function (sequelize) { const Run = defineRun(sequelize, DataTypes); diff --git a/backend/routes/runs/index.js b/backend/routes/runs/index.js index c77959c..1314912 100644 --- a/backend/routes/runs/index.js +++ b/backend/routes/runs/index.js @@ -1,7 +1,7 @@ const express = require('express'); const router = express.Router(); -const defineRun = require('../../models/runs'); const { DataTypes } = require('sequelize'); +const defineRun = require('../../models/runs'); module.exports = function (sequelize) { const { verifySignedIn } = require('../../middleware/auth')(sequelize); diff --git a/backend/routes/runs/new.js b/backend/routes/runs/new.js index 7c6655c..72731d0 100644 --- a/backend/routes/runs/new.js +++ b/backend/routes/runs/new.js @@ -1,7 +1,7 @@ const express = require('express'); const router = express.Router(); -const defineRun = require('../../models/runs'); const { DataTypes } = require('sequelize'); +const defineRun = require('../../models/runs'); module.exports = function (sequelize) { const { verifySignedIn } = require('../../middleware/auth')(sequelize); @@ -26,6 +26,7 @@ module.exports = function (sequelize) { res.json(newRun); } catch (error) { + console.error('Error creating new run:', error); res.status(500).json({ error: 'Internal server error' }); } }); diff --git a/backend/routes/runs/show.js b/backend/routes/runs/show.js index 2bf415c..c84b9e6 100644 --- a/backend/routes/runs/show.js +++ b/backend/routes/runs/show.js @@ -1,8 +1,8 @@ const express = require('express'); const router = express.Router(); +const { DataTypes, literal } = require('sequelize'); const defineRun = require('../../models/runs'); const defineRunCase = require('../../models/runCases'); -const { DataTypes, literal } = require('sequelize'); module.exports = function (sequelize) { const { verifySignedIn } = require('../../middleware/auth')(sequelize); diff --git a/backend/routes/steps/edit.js b/backend/routes/steps/edit.js index aa5a7a7..2fac1f7 100644 --- a/backend/routes/steps/edit.js +++ b/backend/routes/steps/edit.js @@ -1,8 +1,8 @@ const express = require('express'); const router = express.Router(); +const { DataTypes } = require('sequelize'); const defineStep = require('../../models/steps'); const defineCaseStep = require('../../models/caseSteps'); -const { DataTypes } = require('sequelize'); module.exports = function (sequelize) { const Step = defineStep(sequelize, DataTypes); diff --git a/backend/routes/users/find.js b/backend/routes/users/find.js index f404455..07897c2 100644 --- a/backend/routes/users/find.js +++ b/backend/routes/users/find.js @@ -1,7 +1,7 @@ const express = require('express'); const router = express.Router(); -const defineUser = require('../../models/users'); const { DataTypes } = require('sequelize'); +const defineUser = require('../../models/users'); module.exports = function (sequelize) { const { verifySignedIn } = require('../../middleware/auth')(sequelize); diff --git a/backend/routes/users/index.js b/backend/routes/users/index.js index 4f0fd95..fa2ab03 100644 --- a/backend/routes/users/index.js +++ b/backend/routes/users/index.js @@ -1,7 +1,7 @@ const express = require('express'); const router = express.Router(); -const defineUser = require('../../models/users'); const { DataTypes } = require('sequelize'); +const defineUser = require('../../models/users'); module.exports = function (sequelize) { const { verifySignedIn, verifyAdmin } = require('../../middleware/auth')(sequelize); diff --git a/backend/routes/users/search.js b/backend/routes/users/search.js index 84ba3f1..e8d9c84 100644 --- a/backend/routes/users/search.js +++ b/backend/routes/users/search.js @@ -1,8 +1,8 @@ const express = require('express'); const router = express.Router(); +const { DataTypes, Op } = require('sequelize'); const defineUser = require('../../models/users'); const defineMember = require('../../models/members'); -const { DataTypes, Op } = require('sequelize'); module.exports = function (sequelize) { const { verifySignedIn } = require('../../middleware/auth')(sequelize); diff --git a/backend/routes/users/signin.js b/backend/routes/users/signin.js index 3b740f4..69459b2 100644 --- a/backend/routes/users/signin.js +++ b/backend/routes/users/signin.js @@ -1,9 +1,9 @@ const express = require('express'); const router = express.Router(); -const defineUser = require('../../models/users'); const { DataTypes } = require('sequelize'); const bcrypt = require('bcrypt'); const jwt = require('jsonwebtoken'); +const defineUser = require('../../models/users'); const { defaultDangerKey } = require('./authSettings'); module.exports = function (sequelize) { diff --git a/backend/routes/users/signup.js b/backend/routes/users/signup.js index 8398f29..ee2fae1 100644 --- a/backend/routes/users/signup.js +++ b/backend/routes/users/signup.js @@ -1,10 +1,10 @@ const express = require('express'); const router = express.Router(); -const defineUser = require('../../models/users'); const { DataTypes } = require('sequelize'); -const { roles, defaultDangerKey } = require('./authSettings'); const bcrypt = require('bcrypt'); const jwt = require('jsonwebtoken'); +const defineUser = require('../../models/users'); +const { roles, defaultDangerKey } = require('./authSettings'); module.exports = function (sequelize) { const User = defineUser(sequelize, DataTypes); diff --git a/backend/routes/users/update.mjs b/backend/routes/users/update.mjs index 3c5be5a..d45f757 100644 --- a/backend/routes/users/update.mjs +++ b/backend/routes/users/update.mjs @@ -1,8 +1,8 @@ import express from 'express'; import { DataTypes } from 'sequelize'; import defineUser from '../../models/users.js'; -import { roles } from './authSettings.js'; import authMiddleware from '../../middleware/auth.js'; +import { roles } from './authSettings.js'; const router = express.Router(); export default function (sequelize) { diff --git a/backend/routes/users/update.test.js b/backend/routes/users/update.test.js index 447dfd2..1eaa514 100644 --- a/backend/routes/users/update.test.js +++ b/backend/routes/users/update.test.js @@ -1,8 +1,8 @@ import { describe, it, expect, vi, beforeEach } from 'vitest'; import request from 'supertest'; import express from 'express'; -import updateRoute from './update'; import { Sequelize } from 'sequelize'; +import updateRoute from './update'; import { roles } from './authSettings'; const adminRoleIndex = roles.findIndex((entry) => entry.uid === 'administrator'); @@ -28,7 +28,7 @@ const mockUser = { update: vi.fn(), }; vi.mock('../../models/users', () => ({ - default: (sequelize, DataTypes) => mockUser, + default: () => mockUser, })); // test diff --git a/backend/seeders/seed.js b/backend/seeders/seed.js index 83efa5c..674bfa3 100644 --- a/backend/seeders/seed.js +++ b/backend/seeders/seed.js @@ -3,7 +3,7 @@ const fs = require('fs'); const bcrypt = require('bcrypt'); module.exports = { - up: async (queryInterface, Sequelize) => { + up: async (queryInterface) => { const hashedPassword = await bcrypt.hash('password', 10); // Add projects table records @@ -696,7 +696,7 @@ module.exports = { ]); }, - down: async (queryInterface, Sequelize) => { - // do nothingg + down: async () => { + // do nothing }, }; diff --git a/combined_server.js b/combined_server.js index ea552a4..bfcca11 100644 --- a/combined_server.js +++ b/combined_server.js @@ -1,9 +1,9 @@ // Use express from backend node_modules -const express = require('./backend/node_modules/express'); const { createServer: createHttpServer } = require('http'); const path = require('path'); const fs = require('fs'); const { execSync } = require('child_process'); +const express = require('./backend/node_modules/express'); async function runMigrations() { try { diff --git a/frontend/components/ProjectDialog.tsx b/frontend/components/ProjectDialog.tsx index ac36642..01058a4 100644 --- a/frontend/components/ProjectDialog.tsx +++ b/frontend/components/ProjectDialog.tsx @@ -1,5 +1,4 @@ 'use client'; -import React from 'react'; import { useState, useEffect } from 'react'; import { Button, @@ -63,7 +62,7 @@ export default function ProjectDialog({ isOpen, editingProject, onCancel, onSubm setIsProjectPublic(true); } - }, [editingProject]); + }, [editingProject, projectDetail, projectName]); const clear = () => { setProjectName({ diff --git a/frontend/components/ThemeSwitch.tsx b/frontend/components/ThemeSwitch.tsx index edc0e48..dc48826 100644 --- a/frontend/components/ThemeSwitch.tsx +++ b/frontend/components/ThemeSwitch.tsx @@ -19,7 +19,11 @@ export const ThemeSwitch: FC = ({ className, classNames }) => const isSSR = useIsSSR(); const onChange = () => { - theme === 'light' ? setTheme('dark') : setTheme('light'); + if (theme === 'light') { + setTheme('dark'); + } else { + setTheme('light'); + } }; const { Component, slots, isSelected, getBaseProps, getInputProps, getWrapperProps } = useSwitch({ diff --git a/frontend/components/UserAvatar.tsx b/frontend/components/UserAvatar.tsx index efc2055..22204d9 100644 --- a/frontend/components/UserAvatar.tsx +++ b/frontend/components/UserAvatar.tsx @@ -10,7 +10,7 @@ export default function PublicityChip({ context }: Props) { return context.isSignedIn() ? ( diff --git a/frontend/src/app/[locale]/DropdownAccount.tsx b/frontend/src/app/[locale]/DropdownAccount.tsx index ec39883..23ab32a 100644 --- a/frontend/src/app/[locale]/DropdownAccount.tsx +++ b/frontend/src/app/[locale]/DropdownAccount.tsx @@ -78,7 +78,7 @@ export default function DropdownAccount({ messages, locale, onItemPress }: Props startContent={} endContent={} > - {context.isSignedIn() ? context.token!.user!.username : messages.signIn} + {context.isSignedIn() ? context.token?.user?.username : messages.signIn} {context.isSignedIn() ? ( diff --git a/frontend/src/app/[locale]/HeaderNavbarMenu.tsx b/frontend/src/app/[locale]/HeaderNavbarMenu.tsx index dc2f90b..202e55e 100644 --- a/frontend/src/app/[locale]/HeaderNavbarMenu.tsx +++ b/frontend/src/app/[locale]/HeaderNavbarMenu.tsx @@ -1,7 +1,5 @@ 'use client'; import { useState, useContext } from 'react'; -import { TokenContext } from '@/utils/TokenProvider'; -import { Link, useRouter } from '@/src/i18n/routing'; import { usePathname } from 'next/navigation'; import Image from 'next/image'; import { @@ -12,16 +10,17 @@ import { NavbarBrand, NavbarItem, Link as NextUiLink, - Chip, ListboxItem, Listbox, } from '@heroui/react'; import { ArrowRightFromLine, ArrowRightToLine, File, Globe, MoveUpRight, PenTool } from 'lucide-react'; +import DropdownAccount from './DropdownAccount'; +import DropdownLanguage from './DropdownLanguage'; import { ThemeSwitch } from '@/components/ThemeSwitch'; import { GithubIcon } from '@/components/icons'; import { locales } from '@/config/selection'; -import DropdownAccount from './DropdownAccount'; -import DropdownLanguage from './DropdownLanguage'; +import { Link, useRouter } from '@/src/i18n/routing'; +import { TokenContext } from '@/utils/TokenProvider'; import UserAvatar from '@/components/UserAvatar'; import { LocaleCodeType } from '@/types/locale'; import Config from '@/config/config'; diff --git a/frontend/src/app/[locale]/account/AccountPage.tsx b/frontend/src/app/[locale]/account/AccountPage.tsx index 6a5a5ff..9c7a693 100644 --- a/frontend/src/app/[locale]/account/AccountPage.tsx +++ b/frontend/src/app/[locale]/account/AccountPage.tsx @@ -1,14 +1,15 @@ 'use client'; import { useState, useEffect, useContext } from 'react'; -import { Link, NextUiLinkClasses } from '@/src/i18n/routing'; import { Button, Card, CardHeader, CardFooter } from '@heroui/react'; -import { TokenContext } from '@/utils/TokenProvider'; import Avatar from 'boring-avatars'; +import { ArrowRight } from 'lucide-react'; +import { Link, NextUiLinkClasses } from '@/src/i18n/routing'; +import { TokenContext } from '@/utils/TokenProvider'; import { fetchMyProjects } from '@/utils/projectsControl'; import { ProjectType } from '@/types/project'; import PublicityChip from '@/components/PublicityChip'; import { LocaleCodeType } from '@/types/locale'; -import { ArrowRight } from 'lucide-react'; +import { logError } from '@/utils/errorHandler'; type AccountPageMessages = { yourProjects: string; @@ -36,8 +37,8 @@ export default function AccountPage({ messages, locale }: Props) { try { const data = await fetchMyProjects(context.token.access_token); setMyProjects(data); - } catch (error: any) { - console.error('Error in effect:', error.message); + } catch (error: unknown) { + logError('Error fetching data:', error); } } @@ -53,13 +54,13 @@ export default function AccountPage({ messages, locale }: Props) {
-

{context.token!.user!.username}

-

{context.token!.user!.email}

+

{context.token?.user?.username}

+

{context.token?.user?.email}

diff --git a/frontend/src/app/[locale]/account/authControl.ts b/frontend/src/app/[locale]/account/authControl.ts index 530535a..f0d77df 100644 --- a/frontend/src/app/[locale]/account/authControl.ts +++ b/frontend/src/app/[locale]/account/authControl.ts @@ -1,6 +1,7 @@ import { UserType } from '@/types/user'; import Config from '@/config/config'; import { roles } from '@/config/selection'; +import { logError } from '@/utils/errorHandler'; const apiServer = Config.apiServer; async function signUp(newUser: UserType) { @@ -21,8 +22,8 @@ async function signUp(newUser: UserType) { } const token = await response.json(); return token; - } catch (error: any) { - console.error('Error sign up:', error); + } catch (error: unknown) { + logError('Error sign up:', error); throw error; } } @@ -45,8 +46,8 @@ async function signIn(signInUser: UserType) { } const token = await response.json(); return token; - } catch (error: any) { - console.error('Error sign in:', error); + } catch (error: unknown) { + logError('Error sign in:', error); throw error; } } diff --git a/frontend/src/app/[locale]/account/authPage.tsx b/frontend/src/app/[locale]/account/authPage.tsx index 34a8df5..5f6623e 100644 --- a/frontend/src/app/[locale]/account/authPage.tsx +++ b/frontend/src/app/[locale]/account/authPage.tsx @@ -1,13 +1,12 @@ 'use client'; -import React from 'react'; import { useState, useContext } from 'react'; import { Input, Button, Card, CardHeader, CardBody } from '@heroui/react'; -import { Link } from '@/src/i18n/routing'; import { ChevronRight, Eye, EyeOff } from 'lucide-react'; -import { UserType, AuthMessages } from '@/types/user'; -import { roles } from '@/config/selection'; import { signUp, signIn, signInAsGuest } from './authControl'; import { isValidEmail, isValidPassword } from './validate'; +import { Link } from '@/src/i18n/routing'; +import { UserType, AuthMessages } from '@/types/user'; +import { roles } from '@/config/selection'; import { TokenContext } from '@/utils/TokenProvider'; import { useRouter } from '@/src/i18n/routing'; import Config from '@/config/config'; diff --git a/frontend/src/app/[locale]/account/layout.tsx b/frontend/src/app/[locale]/account/layout.tsx index e03958b..c161c4e 100644 --- a/frontend/src/app/[locale]/account/layout.tsx +++ b/frontend/src/app/[locale]/account/layout.tsx @@ -1,5 +1,5 @@ -import { LocaleCodeType } from '@/types/locale'; import { getTranslations } from 'next-intl/server'; +import { LocaleCodeType } from '@/types/locale'; export async function generateMetadata({ params: { locale } }: { params: { locale: LocaleCodeType } }) { const t = await getTranslations({ locale, namespace: 'Auth' }); diff --git a/frontend/src/app/[locale]/account/signin/page.tsx b/frontend/src/app/[locale]/account/signin/page.tsx index 92da2f5..e5e8d06 100644 --- a/frontend/src/app/[locale]/account/signin/page.tsx +++ b/frontend/src/app/[locale]/account/signin/page.tsx @@ -1,7 +1,7 @@ -import { PageType } from '@/types/base'; -import AuthPage from '../authPage'; import { getTranslations } from 'next-intl/server'; import { useTranslations } from 'next-intl'; +import AuthPage from '../authPage'; +import { PageType } from '@/types/base'; import { LocaleCodeType } from '@/types/locale'; export async function generateMetadata({ params: { locale } }: { params: { locale: LocaleCodeType } }) { diff --git a/frontend/src/app/[locale]/account/signup/page.tsx b/frontend/src/app/[locale]/account/signup/page.tsx index eec62e2..9ef869c 100644 --- a/frontend/src/app/[locale]/account/signup/page.tsx +++ b/frontend/src/app/[locale]/account/signup/page.tsx @@ -1,7 +1,7 @@ -import { PageType } from '@/types/base'; -import AuthPage from '../authPage'; import { getTranslations } from 'next-intl/server'; import { useTranslations } from 'next-intl'; +import AuthPage from '../authPage'; +import { PageType } from '@/types/base'; import { LocaleCodeType } from '@/types/locale'; export async function generateMetadata({ params: { locale } }: { params: { locale: LocaleCodeType } }) { diff --git a/frontend/src/app/[locale]/admin/AdminPage.tsx b/frontend/src/app/[locale]/admin/AdminPage.tsx index a5d5ae7..1f04373 100644 --- a/frontend/src/app/[locale]/admin/AdminPage.tsx +++ b/frontend/src/app/[locale]/admin/AdminPage.tsx @@ -1,16 +1,16 @@ 'use client'; -import React from 'react'; import { useState, useEffect, useContext } from 'react'; +import { Button, addToast } from '@heroui/react'; +import UsersTable from './UsersTable'; import { UserType, AdminMessages } from '@/types/user'; import { TokenContext } from '@/utils/TokenProvider'; import { useRouter } from '@/src/i18n/routing'; -import UsersTable from './UsersTable'; import Config from '@/config/config'; import { LocaleCodeType } from '@/types/locale'; import { updateUserRole } from '@/utils/usersControl'; -import { Button, addToast } from '@heroui/react'; import { roles } from '@/config/selection'; import DeleteConfirmDialog from '@/components/DeleteConfirmDialog'; +import { logError } from '@/utils/errorHandler'; const apiServer = Config.apiServer; type Props = { @@ -36,8 +36,8 @@ async function fetchUsers(jwt: string) { } const data = await response.json(); return data; - } catch (error: any) { - console.error('Error fetching data:', error.message); + } catch (error: unknown) { + logError('Error fetching data:', error); } } @@ -66,8 +66,8 @@ export default function AdminPage({ messages, locale }: Props) { if (tokenContext.token.user) { setMyself(tokenContext.token.user); } - } catch (error: any) { - console.error('Error in effect:', error.message); + } catch (error: unknown) { + logError('Error fetching users:', error); } } diff --git a/frontend/src/app/[locale]/admin/UsersTable.tsx b/frontend/src/app/[locale]/admin/UsersTable.tsx index 2cec55d..ea50468 100644 --- a/frontend/src/app/[locale]/admin/UsersTable.tsx +++ b/frontend/src/app/[locale]/admin/UsersTable.tsx @@ -14,9 +14,9 @@ import { DropdownItem, } from '@heroui/react'; import { ChevronDown } from 'lucide-react'; +import Avatar from 'boring-avatars'; import { UserType, AdminMessages } from '@/types/user'; import { roles } from '@/config/selection'; -import Avatar from 'boring-avatars'; type Props = { users: UserType[]; diff --git a/frontend/src/app/[locale]/health/HealthPage.tsx b/frontend/src/app/[locale]/health/HealthPage.tsx index d97cc1e..8012d10 100644 --- a/frontend/src/app/[locale]/health/HealthPage.tsx +++ b/frontend/src/app/[locale]/health/HealthPage.tsx @@ -4,6 +4,7 @@ import { Table, TableBody, TableRow, TableHeader, TableCell, Chip, TableColumn } import { LocaleCodeType } from '@/types/locale'; import { HealthMessages } from '@/types/health'; import Config from '@/config/config'; +import { logError } from '@/utils/errorHandler'; const apiServer = Config.apiServer; type Props = { @@ -21,8 +22,8 @@ async function fetchHealth() { } const data = await response.json(); return data; - } catch (error: any) { - console.log('Error fetching health data:', error); + } catch (error: unknown) { + logError('Error fetching health data:', error); } } @@ -38,8 +39,8 @@ export default function HealthPage({ messages, locale }: Props) { const data = await fetchHealth(); setStatus(data.status); setIsFetching(false); - } catch (error: any) { - console.error('Error in effect:', error.message); + } catch (error: unknown) { + logError('Error in effect:', error); } } diff --git a/frontend/src/app/[locale]/layout.tsx b/frontend/src/app/[locale]/layout.tsx index 2512e37..cb1dcb8 100644 --- a/frontend/src/app/[locale]/layout.tsx +++ b/frontend/src/app/[locale]/layout.tsx @@ -1,12 +1,12 @@ import '@/styles/globals.css'; -import { fontSans } from '@/config/fonts'; -import { Providers } from './providers'; -import Header from './Header'; import clsx from 'clsx'; import { getTranslations } from 'next-intl/server'; import { useTranslations } from 'next-intl'; -import { LocaleCodeType } from '@/types/locale'; import { headers } from 'next/headers'; +import Header from './Header'; +import { Providers } from './providers'; +import { LocaleCodeType } from '@/types/locale'; +import { fontSans } from '@/config/fonts'; export async function generateMetadata({ params: { locale } }: { params: { locale: LocaleCodeType } }) { const headersList = headers(); diff --git a/frontend/src/app/[locale]/projects/ProjectsPage.tsx b/frontend/src/app/[locale]/projects/ProjectsPage.tsx index c85931f..1b367ad 100644 --- a/frontend/src/app/[locale]/projects/ProjectsPage.tsx +++ b/frontend/src/app/[locale]/projects/ProjectsPage.tsx @@ -2,12 +2,13 @@ import { useEffect, useState, useContext } from 'react'; import { Button } from '@heroui/react'; import { Plus } from 'lucide-react'; +import ProjectsTable from './ProjectsTable'; import { TokenContext } from '@/utils/TokenProvider'; import { ProjectDialogMessages, ProjectType, ProjectsMessages } from '@/types/project'; -import ProjectsTable from './ProjectsTable'; import ProjectDialog from '@/components/ProjectDialog'; import { fetchProjects, createProject } from '@/utils/projectsControl'; import { LocaleCodeType } from '@/types/locale'; +import { logError } from '@/utils/errorHandler'; export type Props = { messages: ProjectsMessages; @@ -27,8 +28,8 @@ export default function ProjectsPage({ messages, projectDialogMessages, locale } try { const data = await fetchProjects(context.token.access_token); setProjects(data); - } catch (error: any) { - console.error('Error in effect:', error.message); + } catch (error: unknown) { + logError('Error fetching data:', error); } } diff --git a/frontend/src/app/[locale]/projects/ProjectsTable.tsx b/frontend/src/app/[locale]/projects/ProjectsTable.tsx index 4dbeaa8..75e43d9 100644 --- a/frontend/src/app/[locale]/projects/ProjectsTable.tsx +++ b/frontend/src/app/[locale]/projects/ProjectsTable.tsx @@ -1,8 +1,8 @@ import { useState, useMemo, useCallback, ReactNode } from 'react'; import { Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, SortDescriptor } from '@heroui/react'; +import dayjs from 'dayjs'; import { Link, NextUiLinkClasses } from '@/src/i18n/routing'; import { ProjectType, ProjectsMessages } from '@/types/project'; -import dayjs from 'dayjs'; import PublicityChip from '@/components/PublicityChip'; import { LocaleCodeType } from '@/types/locale'; @@ -39,35 +39,43 @@ export default function ProjectsTable({ projects, messages, locale }: Props) { return text.length > maxLength ? text.slice(0, maxLength) + '...' : text; }; - const renderCell = useCallback((project: ProjectType, columnKey: string): ReactNode => { - const cellValue = project[columnKey as keyof ProjectType]; + const renderCell = useCallback( + (project: ProjectType, columnKey: string): ReactNode => { + const cellValue = project[columnKey as keyof ProjectType]; - switch (columnKey) { - case 'id': - return {cellValue as number}; - case 'isPublic': - return ( - - ); - case 'name': - const maxLength = 30; - const truncatedDetail = truncateText(project.detail, maxLength); - return ( -
- - {cellValue as string} - -
-
{truncatedDetail}
+ switch (columnKey) { + case 'id': + return {cellValue as number}; + case 'isPublic': + return ( + + ); + case 'name': { + const maxLength = 30; + const truncatedDetail = truncateText(project.detail, maxLength); + return ( +
+ + {cellValue as string} + +
+
{truncatedDetail}
+
-
- ); - case 'updatedAt': - return {dayjs(cellValue as number).format('YYYY/MM/DD HH:mm')}; - default: - return cellValue as string; - } - }, []); + ); + } + case 'updatedAt': + return {dayjs(cellValue as number).format('YYYY/MM/DD HH:mm')}; + default: + return cellValue as string; + } + }, + [locale, messages.private, messages.public] + ); const classNames = useMemo( () => ({ diff --git a/frontend/src/app/[locale]/projects/[projectId]/folders/FolderDialog.tsx b/frontend/src/app/[locale]/projects/[projectId]/folders/FolderDialog.tsx index 0fd1eb3..645cc27 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/folders/FolderDialog.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/folders/FolderDialog.tsx @@ -1,5 +1,4 @@ 'use client'; -import React from 'react'; import { useState, useEffect } from 'react'; import { Button, Input, Textarea, Modal, ModalContent, ModalHeader, ModalBody, ModalFooter } from '@heroui/react'; import { FolderType, FoldersMessages } from '@/types/folder'; @@ -47,7 +46,7 @@ export default function FolderDialog({ isOpen, editingFolder, onCancel, onSubmit text: '', }); } - }, [editingFolder]); + }, [editingFolder, folderDetail, folderName]); const clear = () => { setFolderName({ diff --git a/frontend/src/app/[locale]/projects/[projectId]/folders/FoldersPane.tsx b/frontend/src/app/[locale]/projects/[projectId]/folders/FoldersPane.tsx index 6331f04..c0ba0b9 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/folders/FoldersPane.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/folders/FoldersPane.tsx @@ -1,15 +1,16 @@ 'use client'; -import { FolderType, FoldersMessages } from '@/types/folder'; import { useState, useEffect, useContext } from 'react'; import { Button, Listbox, ListboxItem } from '@heroui/react'; import { Folder, Plus } from 'lucide-react'; +import FolderDialog from './FolderDialog'; +import FolderEditMenu from './FolderEditMenu'; +import { fetchFolders, createFolder, updateFolder, deleteFolder } from './foldersControl'; import { usePathname, useRouter } from '@/src/i18n/routing'; import { TokenContext } from '@/utils/TokenProvider'; import useGetCurrentIds from '@/utils/useGetCurrentIds'; -import FolderDialog from './FolderDialog'; -import FolderEditMenu from './FolderEditMenu'; import DeleteConfirmDialog from '@/components/DeleteConfirmDialog'; -import { fetchFolders, createFolder, updateFolder, deleteFolder } from './foldersControl'; +import { FolderType, FoldersMessages } from '@/types/folder'; +import { logError } from '@/utils/errorHandler'; type Props = { projectId: string; @@ -49,13 +50,13 @@ export default function FoldersPane({ projectId, messages, locale }: Props) { const smallestFolderId = Math.min(...folders.map((folder) => folder.id)); router.push(`/projects/${projectId}/folders/${smallestFolderId}/cases`, { locale: locale }); } - } catch (error: any) { - console.error('Error in effect:', error.message); + } catch (error: unknown) { + logError('Error fetching folders:', error); } } fetchDataEffect(); - }, [context, folderId]); + }, [context, folderId, locale, pathname, projectId, router]); const openDialogForCreate = () => { setIsFolderDialogOpen(true); diff --git a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/CaseDialog.tsx b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/CaseDialog.tsx index f68fa7f..e718d96 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/CaseDialog.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/CaseDialog.tsx @@ -1,6 +1,5 @@ 'use client'; -import React from 'react'; -import { useState, useEffect } from 'react'; +import { useState } from 'react'; import { Button, Input, Textarea, Modal, ModalContent, ModalHeader, ModalBody, ModalFooter } from '@heroui/react'; import { CasesMessages } from '@/types/case'; diff --git a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/CasesPane.tsx b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/CasesPane.tsx index 26558cf..dd06ccd 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/CasesPane.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/CasesPane.tsx @@ -8,6 +8,7 @@ import { CaseType, CasesMessages } from '@/types/case'; import DeleteConfirmDialog from '@/components/DeleteConfirmDialog'; import { PriorityMessages } from '@/types/priority'; import { LocaleCodeType } from '@/types/locale'; +import { logError } from '@/utils/errorHandler'; type Props = { projectId: string; @@ -30,8 +31,8 @@ export default function CasesPane({ projectId, folderId, messages, priorityMessa try { const data = await fetchCases(context.token.access_token, Number(folderId)); setCases(data); - } catch (error: any) { - console.error('Error in effect:', error.message); + } catch (error: unknown) { + logError('Error fetching cases:', error); } } diff --git a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/TestCaseTable.tsx b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/TestCaseTable.tsx index cd5242e..445c96c 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/TestCaseTable.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/TestCaseTable.tsx @@ -15,7 +15,7 @@ import { SortDescriptor, ButtonGroup, } from '@heroui/react'; -import { Plus, MoreVertical, Trash, Download, FileDown, ChevronDown, FileJson, FileSpreadsheet } from 'lucide-react'; +import { Plus, MoreVertical, Trash, FileDown, ChevronDown, FileJson, FileSpreadsheet } from 'lucide-react'; import { Link } from '@/src/i18n/routing'; import { CaseType, CasesMessages } from '@/types/case'; import { PriorityMessages } from '@/types/priority'; @@ -122,6 +122,7 @@ export default function TestCaseTable({ default: return cellValue as string; } + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const handleDeleteCases = () => { diff --git a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/CaseEditor.tsx b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/CaseEditor.tsx index 17049c1..13add8d 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/CaseEditor.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/CaseEditor.tsx @@ -1,19 +1,20 @@ 'use client'; import { useState, useEffect, useContext, ChangeEvent, DragEvent } from 'react'; import { Input, Textarea, Select, SelectItem, Button, Divider, Tooltip, addToast, Badge } from '@heroui/react'; -import { useRouter } from '@/src/i18n/routing'; import { Save, Plus, ArrowLeft, Circle } from 'lucide-react'; -import { priorities, testTypes, templates } from '@/config/selection'; import CaseStepsEditor from './CaseStepsEditor'; import CaseAttachmentsEditor from './CaseAttachmentsEditor'; -import { fetchCase, updateCase } from '@/utils/caseControl'; import { updateSteps } from './stepControl'; import { fetchCreateAttachments, fetchDownloadAttachment, fetchDeleteAttachment } from './attachmentControl'; +import { fetchCase, updateCase } from '@/utils/caseControl'; +import { priorities, testTypes, templates } from '@/config/selection'; +import { useRouter } from '@/src/i18n/routing'; import { TokenContext } from '@/utils/TokenProvider'; import { useFormGuard } from '@/utils/formGuard'; import { CaseType, AttachmentType, CaseMessages, StepType } from '@/types/case'; import { PriorityMessages } from '@/types/priority'; import { TestTypeMessages } from '@/types/testType'; +import { logError } from '@/utils/errorHandler'; const defaultTestCase = { id: 0, @@ -220,13 +221,13 @@ export default function CaseEditor({ step.editState = 'notChanged'; }); setTestCase(data); - } catch (error: any) { - console.error('Error in effect:', error.message); + } catch (error: unknown) { + logError('Error fetching case data', error); } } fetchDataEffect(); - }, [tokenContext]); + }, [caseId, tokenContext]); return ( <> diff --git a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/CaseStepsEditor.tsx b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/CaseStepsEditor.tsx index ff6602c..7216998 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/CaseStepsEditor.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/CaseStepsEditor.tsx @@ -1,6 +1,6 @@ import { Textarea, Button, Tooltip, Avatar } from '@heroui/react'; -import { CaseMessages, StepType } from '@/types/case'; import { Plus, Trash } from 'lucide-react'; +import { CaseMessages, StepType } from '@/types/case'; type Props = { isDisabled: boolean; diff --git a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/attachmentControl.ts b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/attachmentControl.ts index fe0cc6b..fdb4611 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/attachmentControl.ts +++ b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/attachmentControl.ts @@ -1,4 +1,5 @@ import Config from '@/config/config'; +import { logError } from '@/utils/errorHandler'; const apiServer = Config.apiServer; async function fetchDownloadAttachment(attachmentId: number, downloadFileName: string) { @@ -26,8 +27,8 @@ async function fetchDownloadAttachment(attachmentId: number, downloadFileName: s document.body.appendChild(link); link.click(); document.body.removeChild(link); - } catch (error: any) { - console.error('Error downloading file:', error); + } catch (error: unknown) { + logError('Error downloading attachment', error); throw error; } } @@ -51,8 +52,8 @@ async function fetchCreateAttachments(caseId: number, files: File[]) { const responseData = await response.json(); return responseData; - } catch (error: any) { - console.error('Error uploading files:', error); + } catch (error: unknown) { + logError('Error uploading files', error); } } @@ -71,8 +72,8 @@ async function fetchDeleteAttachment(attachmentId: number) { if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } - } catch (error: any) { - console.error('Error deleting file:', error); + } catch (error: unknown) { + logError('Error deleting file:', error); throw error; } } diff --git a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/page.tsx b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/page.tsx index 400faef..eabc7cd 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/page.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/page.tsx @@ -1,6 +1,6 @@ -import { PriorityMessages } from '@/types/priority'; -import CaseEditor from './CaseEditor'; import { useTranslations } from 'next-intl'; +import CaseEditor from './CaseEditor'; +import { PriorityMessages } from '@/types/priority'; import { TestTypeMessages } from '@/types/testType'; export default function Page({ diff --git a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/stepControl.ts b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/stepControl.ts index 38d15ab..ac7a1d6 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/stepControl.ts +++ b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/stepControl.ts @@ -1,5 +1,6 @@ import Config from '@/config/config'; import { StepType } from '@/types/case'; +import { logError } from '@/utils/errorHandler'; const apiServer = Config.apiServer; async function updateSteps(jwt: string, caseId: number, steps: StepType[]) { @@ -20,8 +21,8 @@ async function updateSteps(jwt: string, caseId: number, steps: StepType[]) { throw new Error(`HTTP error! Status: ${response.status}`); } return await response.json(); - } catch (error: any) { - console.error('Error deleting project:', error); + } catch (error: unknown) { + logError('Error updating steps', error); throw error; } } diff --git a/frontend/src/app/[locale]/projects/[projectId]/folders/foldersControl.ts b/frontend/src/app/[locale]/projects/[projectId]/folders/foldersControl.ts index f20f635..389bf6f 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/folders/foldersControl.ts +++ b/frontend/src/app/[locale]/projects/[projectId]/folders/foldersControl.ts @@ -1,4 +1,5 @@ import Config from '@/config/config'; +import { logError } from '@/utils/errorHandler'; const apiServer = Config.apiServer; /** @@ -21,8 +22,8 @@ async function fetchFolders(jwt: string, projectId: number) { const data = await response.json(); return data; - } catch (error: any) { - console.error('Error fetching data:', error.message); + } catch (error: unknown) { + logError('Error fetching data:', error); } } @@ -60,8 +61,8 @@ async function createFolder( } const data = await response.json(); return data; - } catch (error: any) { - console.error('Error creating new project:', error); + } catch (error: unknown) { + logError('Error creating new folder:', error); throw error; } } @@ -102,8 +103,8 @@ async function updateFolder( } const data = await response.json(); return data; - } catch (error: any) { - console.error('Error updating project:', error); + } catch (error: unknown) { + logError('Error updating folder:', error); throw error; } } @@ -127,8 +128,8 @@ async function deleteFolder(jwt: string, folderId: number) { if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } - } catch (error: any) { - console.error('Error deleting project:', error); + } catch (error: unknown) { + logError('Error deleting folder:', error); throw error; } } diff --git a/frontend/src/app/[locale]/projects/[projectId]/folders/layout.tsx b/frontend/src/app/[locale]/projects/[projectId]/folders/layout.tsx index 0a29384..a0f674f 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/folders/layout.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/folders/layout.tsx @@ -1,5 +1,5 @@ -import FoldersPane from './FoldersPane'; import { useTranslations } from 'next-intl'; +import FoldersPane from './FoldersPane'; export default function FoldersLayout({ children, diff --git a/frontend/src/app/[locale]/projects/[projectId]/home/ProjectHome.tsx b/frontend/src/app/[locale]/projects/[projectId]/home/ProjectHome.tsx index e6ada11..f3d21c0 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/home/ProjectHome.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/home/ProjectHome.tsx @@ -1,22 +1,23 @@ 'use client'; import { useState, useEffect, useContext } from 'react'; -import { title, subtitle } from '@/components/primitives'; import { Card, CardBody, Chip, Divider } from '@heroui/react'; import { Folder, Clipboard, FlaskConical } from 'lucide-react'; -import { ProgressSeriesType } from '@/types/run'; -import { HomeMessages } from './page'; -import { TokenContext } from '@/utils/TokenProvider'; -import { aggregateBasicInfo, aggregateTestPriority, aggregateTestType, aggregateProgress } from './aggregate'; -import Config from '@/config/config'; import { useTheme } from 'next-themes'; +import { aggregateBasicInfo, aggregateTestPriority, aggregateTestType, aggregateProgress } from './aggregate'; +import { HomeMessages } from './page'; import TestTypesChart from './TestTypesDonutChart'; import TestPriorityChart from './TestPriorityDonutChart'; import TestProgressBarChart from './TestProgressColumnChart'; +import Config from '@/config/config'; +import { TokenContext } from '@/utils/TokenProvider'; +import { ProgressSeriesType } from '@/types/run'; +import { title, subtitle } from '@/components/primitives'; import { TestRunCaseStatusMessages } from '@/types/status'; import { TestTypeMessages } from '@/types/testType'; import { PriorityMessages } from '@/types/priority'; import { ProjectType } from '@/types/project'; import { CasePriorityCountType, CaseTypeCountType } from '@/types/chart'; +import { logError } from '@/utils/errorHandler'; const apiServer = Config.apiServer; @@ -38,8 +39,8 @@ async function fetchProject(jwt: string, projectId: number) { } const data = await response.json(); return data; - } catch (error: any) { - console.error('Error fetching data:', error.message); + } catch (error: unknown) { + logError('Error fetching data:', error); } } @@ -59,7 +60,7 @@ export function ProjectHome({ priorityMessages, }: Props) { const context = useContext(TokenContext); - const { theme, setTheme } = useTheme(); + const { theme } = useTheme(); const [project, setProject] = useState({ id: 0, name: '', @@ -88,13 +89,13 @@ export function ProjectHome({ try { const data = await fetchProject(context.token.access_token, Number(projectId)); setProject(data); - } catch (error: any) { - console.error('Error in effect:', error.message); + } catch (error: unknown) { + logError('Error in effect:', error); } } fetchDataEffect(); - }, [context]); + }, [context, projectId]); useEffect(() => { async function aggregate() { @@ -118,7 +119,7 @@ export function ProjectHome({ } aggregate(); - }, [project]); + }, [project, testRunCaseStatusMessages]); return (
diff --git a/frontend/src/app/[locale]/projects/[projectId]/home/TestPriorityDonutChart.tsx b/frontend/src/app/[locale]/projects/[projectId]/home/TestPriorityDonutChart.tsx index 487e2de..4d2c2c9 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/home/TestPriorityDonutChart.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/home/TestPriorityDonutChart.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { useState, useEffect } from 'react'; import dynamic from 'next/dynamic'; import { priorities } from '@/config/selection'; @@ -34,7 +33,7 @@ export default function TestPriorityDonutChart({ priorityCounts, priorityMessage const colors = priorities.map((entry) => entry.chartColor); const legend = { labels: { - colors: priorities.map((entry) => { + colors: priorities.map(() => { if (theme === 'light') { return 'black'; } else { @@ -52,7 +51,7 @@ export default function TestPriorityDonutChart({ priorityCounts, priorityMessage }; updateChartDate(); - }, [priorityCounts, theme]); + }, [priorityCounts, priorityMessages, theme]); return ; } diff --git a/frontend/src/app/[locale]/projects/[projectId]/home/TestProgressColumnChart.tsx b/frontend/src/app/[locale]/projects/[projectId]/home/TestProgressColumnChart.tsx index 0f3581c..c01df80 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/home/TestProgressColumnChart.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/home/TestProgressColumnChart.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { useState, useEffect } from 'react'; import dynamic from 'next/dynamic'; import { ProgressSeriesType } from '@/types/run'; @@ -24,7 +23,7 @@ export default function TestProgressBarChart({ progressSeries, progressCategorie useEffect(() => { const updateChartDate = () => { if (progressSeries) { - const legendsLabelColors = testRunCaseStatus.map((itr) => { + const legendsLabelColors = testRunCaseStatus.map(() => { if (theme === 'light') { return 'black'; } else { diff --git a/frontend/src/app/[locale]/projects/[projectId]/home/TestTypesDonutChart.tsx b/frontend/src/app/[locale]/projects/[projectId]/home/TestTypesDonutChart.tsx index a324fc4..9ef7989 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/home/TestTypesDonutChart.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/home/TestTypesDonutChart.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { useState, useEffect } from 'react'; import dynamic from 'next/dynamic'; import { testTypes } from '@/config/selection'; @@ -33,7 +32,7 @@ export default function TestTypesDonutChart({ typesCounts, testTypeMessages, the const colors = testTypes.map((entry) => entry.chartColor); const legend = { labels: { - colors: testTypes.map((entry) => { + colors: testTypes.map(() => { if (theme === 'light') { return 'black'; } else { @@ -51,7 +50,7 @@ export default function TestTypesDonutChart({ typesCounts, testTypeMessages, the }; updateChartDate(); - }, [typesCounts, theme]); + }, [typesCounts, theme, testTypeMessages]); return ; } diff --git a/frontend/src/app/[locale]/projects/[projectId]/home/aggregate.ts b/frontend/src/app/[locale]/projects/[projectId]/home/aggregate.ts index ba771a1..4a8bfaf 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/home/aggregate.ts +++ b/frontend/src/app/[locale]/projects/[projectId]/home/aggregate.ts @@ -18,7 +18,7 @@ function aggregateBasicInfo(project: ProjectType) { function aggregateTestType(project: ProjectType): CaseTypeCountType[] { // count how many test cases are for each type - const typesCounts: number[] = testTypes.map((entry) => { + const typesCounts: number[] = testTypes.map(() => { return 0; }); project.Folders.forEach((folder) => { @@ -38,7 +38,7 @@ function aggregateTestType(project: ProjectType): CaseTypeCountType[] { function aggregateTestPriority(project: ProjectType) { // count how many test cases are for each priority - const priorityCounts: number[] = priorities.map((entry) => { + const priorityCounts: number[] = priorities.map(() => { return 0; }); project.Folders.forEach((folder) => { @@ -58,10 +58,10 @@ function aggregateTestPriority(project: ProjectType) { function aggregateProgress(project: ProjectType, testRunCaseStatusMessages: TestRunCaseStatusMessages) { type ChartSeries = { name: string; data: number[] }; - let series: ChartSeries[] = testRunCaseStatus.map((status) => { + const series: ChartSeries[] = testRunCaseStatus.map((status) => { return { name: testRunCaseStatusMessages[status.uid], data: [] }; }); - let categories: string[] = []; + const categories: string[] = []; project.Runs.forEach((run) => { if (!run.RunCases) { diff --git a/frontend/src/app/[locale]/projects/[projectId]/home/page.tsx b/frontend/src/app/[locale]/projects/[projectId]/home/page.tsx index f15bb83..e5f31b0 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/home/page.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/home/page.tsx @@ -1,7 +1,7 @@ -import { LocaleCodeType } from '@/types/locale'; -import { ProjectHome } from './ProjectHome'; import { getTranslations } from 'next-intl/server'; import { useTranslations } from 'next-intl'; +import { ProjectHome } from './ProjectHome'; +import { LocaleCodeType } from '@/types/locale'; import { PriorityMessages } from '@/types/priority'; import { TestTypeMessages } from '@/types/testType'; import { TestRunCaseStatusMessages } from '@/types/status'; diff --git a/frontend/src/app/[locale]/projects/[projectId]/layout.tsx b/frontend/src/app/[locale]/projects/[projectId]/layout.tsx index 8a25f2e..0fb1744 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/layout.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/layout.tsx @@ -1,6 +1,6 @@ -import { ProjectMessages } from '@/types/project'; -import Sidebar from './Sidebar'; import { useTranslations } from 'next-intl'; +import Sidebar from './Sidebar'; +import { ProjectMessages } from '@/types/project'; export default function SidebarLayout({ children, diff --git a/frontend/src/app/[locale]/projects/[projectId]/members/AddMemberDialog.tsx b/frontend/src/app/[locale]/projects/[projectId]/members/AddMemberDialog.tsx index 0d04f20..0a0bab0 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/members/AddMemberDialog.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/members/AddMemberDialog.tsx @@ -1,12 +1,12 @@ 'use client'; -import React from 'react'; import { useState, useEffect, useContext } from 'react'; import { Button, Input, Modal, ModalContent, ModalHeader, ModalBody, ModalFooter } from '@heroui/react'; +import CandidatesTable from './CandidatesTable'; import { TokenContext } from '@/utils/TokenProvider'; import { UserType } from '@/types/user'; import { searchUsers } from '@/utils/usersControl'; -import CandidatesTable from './CandidatesTable'; import { MembersMessages } from '@/types/member'; +import { logError } from '@/utils/errorHandler'; type Props = { isOpen: boolean; @@ -34,13 +34,13 @@ export default function AddMemberDialog({ isOpen, projectId, onCancel, onAddMemb try { const data = await searchUsers(context.token.access_token, Number(projectId), searchText); setCandidates(data); - } catch (error: any) { - console.error('Error in effect:', error.message); + } catch (error: unknown) { + logError('Error fetching data:', error); } } fetchDataEffect(); - }, [searchText]); + }, [context, projectId, searchText]); const handleExit = () => { setSearchText(''); diff --git a/frontend/src/app/[locale]/projects/[projectId]/members/CandidatesTable.tsx b/frontend/src/app/[locale]/projects/[projectId]/members/CandidatesTable.tsx index b247555..c7a9ec7 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/members/CandidatesTable.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/members/CandidatesTable.tsx @@ -1,7 +1,7 @@ import { useMemo, useCallback } from 'react'; import { Button, Table, TableHeader, TableColumn, TableBody, TableRow, TableCell } from '@heroui/react'; -import { UserType } from '@/types/user'; import Avatar from 'boring-avatars'; +import { UserType } from '@/types/user'; import { MembersMessages } from '@/types/member'; type Props = { @@ -18,33 +18,36 @@ export default function MembersTable({ candidates, onAddPress, messages }: Props { name: messages.add, uid: 'add', sortable: false }, ]; - const renderCell = useCallback((candidate: UserType, columnKey: string) => { - const cellValue = candidate[columnKey as keyof UserType]; + const renderCell = useCallback( + (candidate: UserType, columnKey: string) => { + const cellValue = candidate[columnKey as keyof UserType]; - switch (columnKey) { - case 'avatar': - return ( - - ); - case 'email': - return cellValue; - case 'username': - return cellValue; - case 'add': - return ( - - ); - default: - return cellValue; - } - }, []); + switch (columnKey) { + case 'avatar': + return ( + + ); + case 'email': + return cellValue; + case 'username': + return cellValue; + case 'add': + return ( + + ); + default: + return cellValue; + } + }, + [messages.add, onAddPress] + ); const classNames = useMemo( () => ({ diff --git a/frontend/src/app/[locale]/projects/[projectId]/members/MembersPage.tsx b/frontend/src/app/[locale]/projects/[projectId]/members/MembersPage.tsx index d46a864..4383e68 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/members/MembersPage.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/members/MembersPage.tsx @@ -1,23 +1,22 @@ 'use client'; -import React from 'react'; import { useState, useEffect, useContext } from 'react'; import { Button } from '@heroui/react'; import { Plus } from 'lucide-react'; -import { MemberType, UserType } from '@/types/user'; -import { MembersMessages } from '@/types/member'; -import { TokenContext } from '@/utils/TokenProvider'; import MembersTable from './MembersTable'; import AddMemberDialog from './AddMemberDialog'; import { fetchProjectMembers, addMember, deleteMember, updateMember } from './membersControl'; +import { MemberType, UserType } from '@/types/user'; +import { MembersMessages } from '@/types/member'; +import { TokenContext } from '@/utils/TokenProvider'; import DeleteConfirmDialog from '@/components/DeleteConfirmDialog'; +import { logError } from '@/utils/errorHandler'; type Props = { projectId: string; messages: MembersMessages; - locale: string; }; -export default function MembersPage({ projectId, messages, locale }: Props) { +export default function MembersPage({ projectId, messages }: Props) { const context = useContext(TokenContext); const [members, setMembers] = useState([]); const [isDialogOpen, setIsDialogOpen] = useState(false); @@ -31,13 +30,13 @@ export default function MembersPage({ projectId, messages, locale }: Props) { try { const data = await fetchProjectMembers(context.token.access_token, projectId); setMembers(data); - } catch (error: any) { - console.error('Error in effect:', error.message); + } catch (error: unknown) { + logError('Error fetching members:', error); } } fetchDataEffect(); - }, [context]); + }, [context, projectId]); const handleAddMember = async (userAdded: UserType) => { if (userAdded.id) { diff --git a/frontend/src/app/[locale]/projects/[projectId]/members/MembersTable.tsx b/frontend/src/app/[locale]/projects/[projectId]/members/MembersTable.tsx index f036ce9..ad046d7 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/members/MembersTable.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/members/MembersTable.tsx @@ -14,9 +14,9 @@ import { DropdownItem, } from '@heroui/react'; import { ChevronDown } from 'lucide-react'; +import Avatar from 'boring-avatars'; import { MemberType, UserType } from '@/types/user'; import { memberRoles } from '@/config/selection'; -import Avatar from 'boring-avatars'; import { MembersMessages } from '@/types/member'; type Props = { diff --git a/frontend/src/app/[locale]/projects/[projectId]/members/membersControl.ts b/frontend/src/app/[locale]/projects/[projectId]/members/membersControl.ts index c1f975f..216b1b4 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/members/membersControl.ts +++ b/frontend/src/app/[locale]/projects/[projectId]/members/membersControl.ts @@ -1,3 +1,4 @@ +import { logError } from '@/utils/errorHandler'; import Config from '@/config/config'; const apiServer = Config.apiServer; @@ -19,8 +20,8 @@ async function fetchProjectMembers(jwt: string, projectId: string) { } const data = await response.json(); return data; - } catch (error: any) { - console.error('Error fetching data:', error.message); + } catch (error: unknown) { + logError('Error fetching data:', error); } } @@ -42,8 +43,8 @@ async function addMember(jwt: string, userId: number, projectId: number) { } const data = await response.json(); return data; - } catch (error: any) { - console.error('Error fetching data:', error.message); + } catch (error: unknown) { + logError('Error fetching data:', error); } } @@ -63,8 +64,8 @@ async function deleteMember(jwt: string, userId: number, projectId: number) { if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } - } catch (error: any) { - console.error('Error fetching data:', error.message); + } catch (error: unknown) { + logError('Error fetching data:', error); } } @@ -86,8 +87,8 @@ async function updateMember(jwt: string, userId: number, projectId: number, role } const data = await response.json(); return data; - } catch (error: any) { - console.error('Error fetching data:', error.message); + } catch (error: unknown) { + logError('Error fetching data:', error); } } diff --git a/frontend/src/app/[locale]/projects/[projectId]/members/page.tsx b/frontend/src/app/[locale]/projects/[projectId]/members/page.tsx index 465daaa..9816f30 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/members/page.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/members/page.tsx @@ -1,7 +1,7 @@ -import { LocaleCodeType } from '@/types/locale'; -import MembersPage from './MembersPage'; import { getTranslations } from 'next-intl/server'; import { useTranslations } from 'next-intl'; +import MembersPage from './MembersPage'; +import { LocaleCodeType } from '@/types/locale'; export async function generateMetadata({ params: { locale } }: { params: { locale: LocaleCodeType } }) { const t = await getTranslations({ locale, namespace: 'Members' }); @@ -34,7 +34,7 @@ export default function Page({ params }: { params: { projectId: string; locale: return ( <> - + ); } diff --git a/frontend/src/app/[locale]/projects/[projectId]/runs/RunDialog.tsx b/frontend/src/app/[locale]/projects/[projectId]/runs/RunDialog.tsx index 46c096f..2d909ce 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/runs/RunDialog.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/runs/RunDialog.tsx @@ -1,5 +1,4 @@ 'use client'; -import React from 'react'; import { useState, useEffect } from 'react'; import { Button, Input, Textarea, Modal, ModalContent, ModalHeader, ModalBody, ModalFooter } from '@heroui/react'; import { RunType, RunsMessages } from '@/types/run'; @@ -47,7 +46,7 @@ export default function RunDialog({ isOpen, editingRun, onCancel, onSubmit, mess text: '', }); } - }, [editingRun]); + }, [editingRun, runDescription, runName]); const clear = () => { setRunName({ diff --git a/frontend/src/app/[locale]/projects/[projectId]/runs/RunsPage.tsx b/frontend/src/app/[locale]/projects/[projectId]/runs/RunsPage.tsx index dac54b2..f2810fa 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/runs/RunsPage.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/runs/RunsPage.tsx @@ -9,6 +9,7 @@ import { RunType, RunsMessages } from '@/types/run'; import DeleteConfirmDialog from '@/components/DeleteConfirmDialog'; import { TokenContext } from '@/utils/TokenProvider'; import { LocaleCodeType } from '@/types/locale'; +import { logError } from '@/utils/errorHandler'; type Props = { projectId: string; @@ -61,13 +62,13 @@ export default function RunsPage({ projectId, locale, messages }: Props) { try { const data = await fetchRuns(context.token.access_token, Number(projectId)); setRuns(data); - } catch (error: any) { - console.error('Error in effect:', error.message); + } catch (error: unknown) { + logError('Error fetching runs', error); } } fetchDataEffect(); - }, [context]); + }, [context, projectId]); const onSubmit = async (name: string, description: string) => { if (editingRun && editingRun.createdAt) { diff --git a/frontend/src/app/[locale]/projects/[projectId]/runs/RunsTable.tsx b/frontend/src/app/[locale]/projects/[projectId]/runs/RunsTable.tsx index 955bfaf..f135b84 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/runs/RunsTable.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/runs/RunsTable.tsx @@ -13,10 +13,10 @@ import { DropdownItem, SortDescriptor, } from '@heroui/react'; -import { Link, NextUiLinkClasses } from '@/src/i18n/routing'; import { MoreVertical } from 'lucide-react'; -import { RunsMessages, RunType } from '@/types/run'; import dayjs from 'dayjs'; +import { Link, NextUiLinkClasses } from '@/src/i18n/routing'; +import { RunsMessages, RunType } from '@/types/run'; import { LocaleCodeType } from '@/types/locale'; type Props = { @@ -70,7 +70,7 @@ export default function RunsTable({ projectId, isDisabled, runs, onDeleteRun, me switch (columnKey) { case 'id': return {cellValue as number}; - case 'name': + case 'name': { const maxLength = 30; const truncatedDescription = truncateText(run.description, maxLength); return ( @@ -83,6 +83,7 @@ export default function RunsTable({ projectId, isDisabled, runs, onDeleteRun, me
); + } case 'updatedAt': return {dayjs(cellValue as string).format('YYYY/MM/DD HH:mm')}; case 'actions': diff --git a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunEditor.tsx b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunEditor.tsx index b362969..abbf01e 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunEditor.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunEditor.tsx @@ -55,6 +55,7 @@ import { useFormGuard } from '@/utils/formGuard'; import { PriorityMessages } from '@/types/priority'; import { RunStatusMessages, TestRunCaseStatusMessages } from '@/types/status'; import { TestTypeMessages } from '@/types/testType'; +import { logError } from '@/utils/errorHandler'; const defaultTestRun = { id: 0, @@ -132,12 +133,13 @@ export default function RunEditor({ setFolders(foldersData); setSelectedFolder(foldersData[0]); initTestCases(); - } catch (error: any) { - console.error('Error in effect:', error.message); + } catch (error: unknown) { + logError('Error fetching run data', error); } } fetchDataEffect(); + // eslint-disable-next-line react-hooks/exhaustive-deps }, [tokenContext]); useEffect(() => { @@ -146,8 +148,8 @@ export default function RunEditor({ try { const filteredData = testCases.filter((testCase) => testCase.folderId === selectedFolder.id); setFilteredTestCases(filteredData); - } catch (error: any) { - console.error('Error fetching cases data:', error.message); + } catch (error: unknown) { + logError('Error filtering test cases', error); } } } diff --git a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunPregressDonutChart.tsx b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunPregressDonutChart.tsx index c9d2ad9..c55ac4f 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunPregressDonutChart.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunPregressDonutChart.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { useState, useEffect } from 'react'; import dynamic from 'next/dynamic'; import { testRunCaseStatus } from '@/config/selection'; @@ -34,7 +33,7 @@ export default function RunProgressDounut({ statusCounts, testRunCaseStatusMessa const colors = testRunCaseStatus.map((entry) => entry.chartColor); const legend = { labels: { - colors: testRunCaseStatus.map((entry) => { + colors: testRunCaseStatus.map(() => { if (theme === 'light') { return 'black'; } else { @@ -52,7 +51,7 @@ export default function RunProgressDounut({ statusCounts, testRunCaseStatusMessa }; updateChartDate(); - }, [statusCounts, theme]); + }, [statusCounts, testRunCaseStatusMessages, theme]); return ; } diff --git a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseDetailDialog.tsx b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseDetailDialog.tsx index 9673edb..0a7151b 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseDetailDialog.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseDetailDialog.tsx @@ -8,12 +8,12 @@ import TestCasePriority from '@/components/TestCasePriority'; import { TokenContext } from '@/utils/TokenProvider'; import { fetchCase } from '@/utils/caseControl'; import { TestTypeMessages } from '@/types/testType'; +import { logError } from '@/utils/errorHandler'; type Props = { isOpen: boolean; caseId: number; onCancel: () => void; - onChangeStatus: (changeCaseId: number, status: number) => {}; messages: RunMessages; testTypeMessages: TestTypeMessages; priorityMessages: PriorityMessages; @@ -37,7 +37,6 @@ export default function TestCaseDetailDialog({ isOpen, caseId, onCancel, - onChangeStatus, messages, testTypeMessages, priorityMessages, @@ -66,8 +65,8 @@ export default function TestCaseDetailDialog({ } setTestCase(data); - } catch (error: any) { - console.error('Error in effect:', error.message); + } catch (error: unknown) { + logError('Error fetching case data', error); } } diff --git a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseSelector.tsx b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseSelector.tsx index 90a871c..69b236c 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseSelector.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseSelector.tsx @@ -26,10 +26,10 @@ import { CircleX, CircleSlash2, } from 'lucide-react'; +import TestCaseDetailDialog from './TestCaseDetailDialog'; import { testRunCaseStatus } from '@/config/selection'; import { CaseType } from '@/types/case'; import { RunMessages } from '@/types/run'; -import TestCaseDetailDialog from './TestCaseDetailDialog'; import { PriorityMessages } from '@/types/priority'; import TestCasePriority from '@/components/TestCasePriority'; import { TestTypeMessages } from '@/types/testType'; @@ -40,9 +40,9 @@ type Props = { isDisabled: boolean; selectedKeys: Selection; onSelectionChange: React.Dispatch>; - onChangeStatus: (changeCaseId: number, status: number) => {}; - onIncludeCase: (includeCaseId: number) => {}; - onExcludeCase: (excludeCaseId: number) => {}; + onChangeStatus: (changeCaseId: number, status: number) => void; + onIncludeCase: (includeCaseId: number) => void; + onExcludeCase: (excludeCaseId: number) => void; messages: RunMessages; testRunCaseStatusMessages: TestRunCaseStatusMessages; priorityMessages: PriorityMessages; @@ -296,7 +296,6 @@ export default function TestCaseSelector({ isOpen={isTestCaseDetailDialogOpen} caseId={showingTestCaseId} onCancel={hideTestCaseDetailDialog} - onChangeStatus={(showingCaseId, newStatus) => onChangeStatus(showingCaseId, newStatus)} messages={messages} priorityMessages={priorityMessages} testTypeMessages={testTypeMessages} diff --git a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/page.tsx b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/page.tsx index 5089978..9bbeee9 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/page.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/page.tsx @@ -1,5 +1,5 @@ -import RunEditor from './RunEditor'; import { useTranslations } from 'next-intl'; +import RunEditor from './RunEditor'; import { RunMessages } from '@/types/run'; import { PriorityMessages } from '@/types/priority'; import { RunStatusMessages, TestRunCaseStatusMessages } from '@/types/status'; diff --git a/frontend/src/app/[locale]/projects/[projectId]/runs/runsControl.ts b/frontend/src/app/[locale]/projects/[projectId]/runs/runsControl.ts index 93463fd..ca78ba0 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/runs/runsControl.ts +++ b/frontend/src/app/[locale]/projects/[projectId]/runs/runsControl.ts @@ -1,3 +1,4 @@ +import { logError } from '@/utils/errorHandler'; import { CaseType } from '@/types/case'; import { RunType, RunCaseType } from '@/types/run'; import Config from '@/config/config'; @@ -22,8 +23,8 @@ async function fetchRun(jwt: string, runId: number) { const data = await response.json(); return data; - } catch (error: any) { - console.error('Error fetching data:', error.message); + } catch (error: unknown) { + logError('Error fetching data:', error); } } @@ -45,8 +46,8 @@ async function fetchRuns(jwt: string, projectId: number) { const data = await response.json(); return data; - } catch (error: any) { - console.error('Error fetching data:', error.message); + } catch (error: unknown) { + logError('Error fetching data:', error); } } @@ -76,8 +77,8 @@ async function createRun(jwt: string, projectId: number, name: string, descripti } const data = await response.json(); return data; - } catch (error: any) { - console.error('Error creating new test run:', error); + } catch (error: unknown) { + logError('Error creating new test run:', error); throw error; } } @@ -101,8 +102,8 @@ async function updateRun(jwt: string, updateTestRun: RunType) { } const data = await response.json(); return data; - } catch (error: any) { - console.error('Error updating run:', error); + } catch (error: unknown) { + logError('Error updating run:', error); throw error; } } @@ -123,8 +124,8 @@ async function deleteRun(jwt: string, runId: number) { if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } - } catch (error: any) { - console.error('Error deleting run:', error); + } catch (error: unknown) { + logError('Error deleting run:', error); throw error; } } @@ -157,8 +158,8 @@ async function exportRun(jwt: string, runId: number, type: string) { a.click(); a.remove(); window.URL.revokeObjectURL(objectUrl); - } catch (error: any) { - console.error('Error fetching data:', error.message); + } catch (error: unknown) { + logError('Error fetching data:', error); } } @@ -180,8 +181,8 @@ async function fetchRunCases(jwt: string, runId: number) { const data = await response.json(); return data; - } catch (error: any) { - console.error('Error fetching data:', error.message); + } catch (error: unknown) { + logError('Error fetching data:', error); } } @@ -308,8 +309,8 @@ async function updateRunCases(jwt: string, runId: number, testCases: CaseType[]) throw new Error(`HTTP error! Status: ${response.status}`); } return await response.json(); - } catch (error: any) { - console.error('Error deleting project:', error); + } catch (error: unknown) { + logError('Error updating run cases:', error); throw error; } } @@ -332,8 +333,8 @@ async function fetchProjectCases(jwt: string, projectId: number) { const data = await response.json(); return data; - } catch (error: any) { - console.error('Error fetching data:', error.message); + } catch (error: unknown) { + logError('Error fetching data:', error); } } diff --git a/frontend/src/app/[locale]/projects/[projectId]/settings/SettingsPage.tsx b/frontend/src/app/[locale]/projects/[projectId]/settings/SettingsPage.tsx index 8c0e661..4e27a61 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/settings/SettingsPage.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/settings/SettingsPage.tsx @@ -1,5 +1,4 @@ 'use client'; -import React from 'react'; import { useState, useEffect, useContext } from 'react'; import { Button, Table, TableHeader, TableColumn, TableBody, TableRow, TableCell } from '@heroui/react'; import Avatar from 'boring-avatars'; @@ -13,6 +12,7 @@ import { useRouter } from '@/src/i18n/routing'; import ProjectDialog from '@/components/ProjectDialog'; import { UserType } from '@/types/user'; import { findUser } from '@/utils/usersControl'; +import { logError } from '@/utils/errorHandler'; type Props = { projectId: string; @@ -60,13 +60,13 @@ export default function SettingsPage({ projectId, messages, projectDialogMessage } else { console.error('failed to get project owner id'); } - } catch (error: any) { - console.error('Error in effect:', error.message); + } catch (error: unknown) { + logError('Error fetching project data:', error); } } fetchDataEffect(); - }, [context]); + }, [context, projectId]); // project dialog const [isProjectDialogOpen, setIsProjectDialogOpen] = useState(false); diff --git a/frontend/src/app/[locale]/projects/[projectId]/settings/page.tsx b/frontend/src/app/[locale]/projects/[projectId]/settings/page.tsx index 0a34a7b..9dd5948 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/settings/page.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/settings/page.tsx @@ -1,8 +1,8 @@ -import { LocaleCodeType } from '@/types/locale'; -import { ProjectDialogMessages } from '@/types/project'; -import SettingsPage from './SettingsPage'; import { getTranslations } from 'next-intl/server'; import { useTranslations } from 'next-intl'; +import SettingsPage from './SettingsPage'; +import { LocaleCodeType } from '@/types/locale'; +import { ProjectDialogMessages } from '@/types/project'; import { SettingsMessages } from '@/types/settings'; export async function generateMetadata({ params: { locale } }: { params: { locale: LocaleCodeType } }) { diff --git a/frontend/src/app/[locale]/projects/layout.tsx b/frontend/src/app/[locale]/projects/layout.tsx index e82e979..da9996c 100644 --- a/frontend/src/app/[locale]/projects/layout.tsx +++ b/frontend/src/app/[locale]/projects/layout.tsx @@ -1,5 +1,5 @@ -import { LocaleCodeType } from '@/types/locale'; import { getTranslations } from 'next-intl/server'; +import { LocaleCodeType } from '@/types/locale'; export async function generateMetadata({ params: { locale } }: { params: { locale: LocaleCodeType } }) { const t = await getTranslations({ locale, namespace: 'Projects' }); diff --git a/frontend/src/app/[locale]/projects/page.tsx b/frontend/src/app/[locale]/projects/page.tsx index 2c64d5d..0661392 100644 --- a/frontend/src/app/[locale]/projects/page.tsx +++ b/frontend/src/app/[locale]/projects/page.tsx @@ -1,6 +1,6 @@ -import { PageType } from '@/types/base'; -import ProjectsPage from './ProjectsPage'; import { useTranslations } from 'next-intl'; +import ProjectsPage from './ProjectsPage'; +import { PageType } from '@/types/base'; import { LocaleCodeType } from '@/types/locale'; import { ProjectDialogMessages, ProjectsMessages } from '@/types/project'; diff --git a/frontend/src/app/[locale]/projects/projectsControl.ts b/frontend/src/app/[locale]/projects/projectsControl.ts deleted file mode 100644 index c1f6100..0000000 --- a/frontend/src/app/[locale]/projects/projectsControl.ts +++ /dev/null @@ -1,123 +0,0 @@ -import Config from '@/config/config'; -const apiServer = Config.apiServer; - -/** - * fetch project records - */ -async function fetchProjects(jwt: string) { - const url = `${apiServer}/projects`; - - try { - const response = await fetch(url, { - method: 'GET', - headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${jwt}`, - }, - }); - - if (!response.ok) { - throw new Error(`HTTP error! Status: ${response.status}`); - } - - const data = await response.json(); - return data; - } catch (error: any) { - console.error('Error fetching data:', error.message); - } -} - -/** - * Create project - */ -async function createProject(jwt: string, name: string, detail: string, isPublic: boolean) { - const newProjectData = { - name, - detail, - isPublic, - }; - - const fetchOptions = { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${jwt}`, - }, - body: JSON.stringify(newProjectData), - }; - - const url = `${apiServer}/projects`; - - try { - const response = await fetch(url, fetchOptions); - if (!response.ok) { - throw new Error(`HTTP error! Status: ${response.status}`); - } - const data = await response.json(); - return data; - } catch (error: any) { - console.error('Error creating new project:', error); - throw error; - } -} - -/** - * Update project - */ -async function updateProject(jwt: string, projectId: number, name: string, detail: string, isPublic: boolean) { - const updatedProjectData = { - name, - detail, - isPublic, - }; - - const fetchOptions = { - method: 'PUT', - headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${jwt}`, - }, - body: JSON.stringify(updatedProjectData), - }; - - const url = `${apiServer}/projects/${projectId}`; - - try { - const response = await fetch(url, fetchOptions); - if (!response.ok) { - throw new Error(`HTTP error! Status: ${response.status}`); - } - const data = await response.json(); - return data; - } catch (error: any) { - console.error('Error updating project:', error); - throw error; - } -} - -/** - * Delete project - */ -async function deleteProject(jwt: string, projectId: number) { - const fetchOptions = { - method: 'DELETE', - headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${jwt}`, - }, - }; - - const url = `${apiServer}/projects/${projectId}`; - - try { - const response = await fetch(url, fetchOptions); - if (!response.ok) { - throw new Error(`HTTP error! Status: ${response.status}`); - } - } catch (error: any) { - console.error('Error deleting project:', error); - throw error; - } -} - -export { fetchProjects, createProject, updateProject, deleteProject }; diff --git a/frontend/src/i18n/request.ts b/frontend/src/i18n/request.ts index 1878db1..8c79890 100644 --- a/frontend/src/i18n/request.ts +++ b/frontend/src/i18n/request.ts @@ -4,7 +4,7 @@ import { routing } from './routing'; export default getRequestConfig(async ({ requestLocale }) => { let locale = await requestLocale; - if (!locale || !routing.locales.includes(locale as any)) { + if (!locale || !routing.locales.includes(locale as (typeof routing.locales)[number])) { locale = routing.defaultLocale; } diff --git a/frontend/utils/TokenProvider.tsx b/frontend/utils/TokenProvider.tsx index 9b23cc1..c34ad7e 100644 --- a/frontend/utils/TokenProvider.tsx +++ b/frontend/utils/TokenProvider.tsx @@ -1,8 +1,6 @@ 'use client'; -import { createContext, useState, useEffect, useContext } from 'react'; -import { ProjectRoleType, TokenContextType, TokenType } from '@/types/user'; -import { TokenProps } from '@/types/user'; -import { useRouter, usePathname } from '@/src/i18n/routing'; +import { createContext, useState, useEffect } from 'react'; +import { addToast } from '@heroui/react'; import { isSignedIn as tokenIsSinedIn, isAdmin as tokenIsAdmin, @@ -13,7 +11,10 @@ import { checkSignInPage as tokenCheckSignInPage, fetchMyRoles, } from './token'; -import { addToast } from '@heroui/react'; +import { logError } from './errorHandler'; +import { ProjectRoleType, TokenContextType, TokenType } from '@/types/user'; +import { TokenProps } from '@/types/user'; +import { useRouter, usePathname } from '@/src/i18n/routing'; const LOCAL_STORAGE_KEY = 'unittcms-auth-token'; function storeTokenToLocalStorage(token: TokenType) { @@ -31,20 +32,20 @@ const defaultContext = { }, isSignedIn: () => false, isAdmin: () => false, - isProjectOwner: (projectId: number) => { + isProjectOwner: () => { return false; }, - isProjectManager: (projectId: number) => { + isProjectManager: () => { return false; }, - isProjectDeveloper: (projectId: number) => { + isProjectDeveloper: () => { return false; }, - isProjectReporter: (projectId: number) => { + isProjectReporter: () => { return false; }, refreshProjectRoles: () => {}, - setToken: (token: TokenType) => {}, + setToken: () => {}, storeTokenToLocalStorage, removeTokenFromLocalStorage, }; @@ -94,8 +95,8 @@ const TokenProvider = ({ toastMessages, locale, children }: TokenProps) => { try { const data = await fetchMyRoles(token.access_token); setProjectRoles(data); - } catch (error: any) { - console.error('Error in effect:', error.message); + } catch (error: unknown) { + logError('Error fetching project roles', error); } } @@ -154,10 +155,12 @@ const TokenProvider = ({ toastMessages, locale, children }: TokenProps) => { router.push(ret.redirectPath, { locale: locale }); } + // eslint-disable-next-line react-hooks/exhaustive-deps }, [pathname, hasRestoreFinished]); useEffect(() => { refreshProjectRoles(); + // eslint-disable-next-line react-hooks/exhaustive-deps }, [hasRestoreFinished, token]); return {children}; diff --git a/frontend/utils/caseControl.ts b/frontend/utils/caseControl.ts index 54cf2c6..ba1d5d1 100644 --- a/frontend/utils/caseControl.ts +++ b/frontend/utils/caseControl.ts @@ -1,3 +1,4 @@ +import { logError } from '@/utils/errorHandler'; import Config from '@/config/config'; const apiServer = Config.apiServer; import { CaseType } from '@/types/case'; @@ -20,8 +21,8 @@ async function fetchCase(jwt: string, caseId: number) { const data = await response.json(); return data; - } catch (error: any) { - console.error('Error fetching data:', error.message); + } catch (error: unknown) { + logError('Error fetching data', error); } } @@ -43,8 +44,8 @@ async function fetchCases(jwt: string, folderId: number) { const data = await response.json(); return data; - } catch (error: any) { - console.error('Error fetching data:', error.message); + } catch (error: unknown) { + logError('Error fetching data', error); } } @@ -79,9 +80,8 @@ async function createCase(jwt: string, folderId: string, title: string, descript } const data = await response.json(); return data; - } catch (error: any) { - console.error('Error creating case:', error); - throw error; + } catch (error: unknown) { + logError('Error creating case', error); } } @@ -103,9 +103,8 @@ async function updateCase(jwt: string, updateCaseData: CaseType) { } const data = await response.json(); return data; - } catch (error: any) { - console.error('Error updating project:', error); - throw error; + } catch (error: unknown) { + logError('Error updating project', error); } } @@ -126,9 +125,8 @@ async function deleteCases(jwt: string, deleteCaseIds: number[], projectId: numb if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } - } catch (error: any) { - console.error('Error deleting cases:', error); - throw error; + } catch (error: unknown) { + logError('Error deleting cases', error); } } @@ -160,8 +158,8 @@ async function exportCases(jwt: string, folderId: number, type: string) { a.click(); a.remove(); window.URL.revokeObjectURL(objectUrl); - } catch (error: any) { - console.error('Error fetching data:', error.message); + } catch (error: unknown) { + logError('Error fetching data', error); } } diff --git a/frontend/utils/errorHandler.ts b/frontend/utils/errorHandler.ts new file mode 100644 index 0000000..f27859a --- /dev/null +++ b/frontend/utils/errorHandler.ts @@ -0,0 +1,10 @@ +/** + * Error handler utility for logging errors + */ +export const logError = (context: string, error: unknown) => { + if (error instanceof Error) { + console.error(`${context}:`, error.message); + } else { + console.error(`${context}:`, error); + } +}; diff --git a/frontend/utils/formGuard.ts b/frontend/utils/formGuard.ts index f0e5d8a..79d5d16 100644 --- a/frontend/utils/formGuard.ts +++ b/frontend/utils/formGuard.ts @@ -25,5 +25,5 @@ export const useFormGuard = (isDirty: boolean, confirmText: string) => { window.removeEventListener('beforeunload', handleBeforeUnload); window.removeEventListener('click', handleClick, true); }; - }, [isDirty]); + }, [confirmText, isDirty]); }; diff --git a/frontend/utils/projectsControl.ts b/frontend/utils/projectsControl.ts index d0e8d0f..e2b72d4 100644 --- a/frontend/utils/projectsControl.ts +++ b/frontend/utils/projectsControl.ts @@ -1,32 +1,7 @@ +import { logError } from '@/utils/errorHandler'; import Config from '@/config/config'; const apiServer = Config.apiServer; -/** - * fetch project - */ -async function fetchProject(jwt: string, projectId: number) { - const url = `${apiServer}/projects/${projectId}`; - - try { - const response = await fetch(url, { - method: 'GET', - headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${jwt}`, - }, - }); - - if (!response.ok) { - throw new Error(`HTTP error! Status: ${response.status}`); - } - - const data = await response.json(); - return data; - } catch (error: any) { - console.error('Error fetching data:', error.message); - } -} - /** * fetch projects (public and user own projects) */ @@ -48,8 +23,34 @@ async function fetchProjects(jwt: string) { const data = await response.json(); return data; - } catch (error: any) { - console.error('Error fetching data:', error.message); + } catch (error: unknown) { + logError('Error fetching data:', error); + } +} + +/** + * fetch project + */ +async function fetchProject(jwt: string, projectId: number) { + const url = `${apiServer}/projects/${projectId}`; + + try { + const response = await fetch(url, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${jwt}`, + }, + }); + + if (!response.ok) { + throw new Error(`HTTP error! Status: ${response.status}`); + } + + const data = await response.json(); + return data; + } catch (error: unknown) { + logError('Error fetching data:', error); } } @@ -74,8 +75,8 @@ async function fetchMyProjects(jwt: string) { const data = await response.json(); return data; - } catch (error: any) { - console.error('Error fetching data:', error.message); + } catch (error: unknown) { + logError('Error fetching data:', error); } } @@ -107,8 +108,8 @@ async function createProject(jwt: string, name: string, detail: string, isPublic } const data = await response.json(); return data; - } catch (error: any) { - console.error('Error creating new project:', error); + } catch (error: unknown) { + logError('Error creating new project:', error); throw error; } } @@ -141,8 +142,8 @@ async function updateProject(jwt: string, projectId: number, name: string, detai } const data = await response.json(); return data; - } catch (error: any) { - console.error('Error updating project:', error); + } catch (error: unknown) { + logError('Error updating project:', error); throw error; } } @@ -166,8 +167,8 @@ async function deleteProject(jwt: string, projectId: number) { if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } - } catch (error: any) { - console.error('Error deleting project:', error); + } catch (error: unknown) { + logError('Error deleting project:', error); throw error; } } diff --git a/frontend/utils/token.ts b/frontend/utils/token.ts index fe29c15..0aa02c3 100644 --- a/frontend/utils/token.ts +++ b/frontend/utils/token.ts @@ -1,3 +1,4 @@ +import { logError } from '@/utils/errorHandler'; import { ProjectRoleType, TokenType } from '@/types/user'; import { roles, memberRoles } from '@/config/selection'; import Config from '@/config/config'; @@ -56,8 +57,8 @@ async function fetchMyRoles(jwt: string) { } const data = await response.json(); return data; - } catch (error: any) { - console.error('Error fetching data:', error.message); + } catch (error: unknown) { + logError('Error fetching data:', error); } } @@ -165,7 +166,7 @@ const isPrivatePath = (pathname: string) => { }; function checkSignInPage(token: TokenType, pathname: string) { - let ret = { + const ret = { ok: true, reason: '', redirectPath: '', diff --git a/frontend/utils/usersControl.ts b/frontend/utils/usersControl.ts index 2e3fdd4..4c50c3b 100644 --- a/frontend/utils/usersControl.ts +++ b/frontend/utils/usersControl.ts @@ -1,3 +1,4 @@ +import { logError } from '@/utils/errorHandler'; import Config from '@/config/config'; const apiServer = Config.apiServer; @@ -19,8 +20,8 @@ async function findUser(jwt: string, userId: number) { } const data = await response.json(); return data; - } catch (error: any) { - console.error('Error fetching data:', error.message); + } catch (error: unknown) { + logError('Error fetching data:', error); } } @@ -42,8 +43,8 @@ async function searchUsers(jwt: string, projectId: number, searchText: string) { } const data = await response.json(); return data; - } catch (error: any) { - console.error('Error fetching data:', error.message); + } catch (error: unknown) { + logError('Error fetching data:', error); } } @@ -70,8 +71,8 @@ async function updateUserRole(jwt: string, userId: number, newRole: number) { } const data = await response.json(); return data; - } catch (error: any) { - console.error('Error fetching data:', error.message); + } catch (error: unknown) { + logError('Error fetching data:', error); } } diff --git a/vitest.config.ts b/vitest.config.ts index aa2e9ed..5896dea 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -1,5 +1,5 @@ -import { defineConfig } from 'vitest/config'; import { resolve } from 'node:path'; +import { defineConfig } from 'vitest/config'; export default defineConfig({ test: {