fix: eslint warnings (#252)

This commit is contained in:
kimatata
2025-07-20 10:59:57 +09:00
committed by GitHub
parent e6be84b67e
commit 9ae67fd303
118 changed files with 423 additions and 511 deletions

View File

@@ -1,5 +1,4 @@
const path = require('path'); const path = require('path');
const databasePath = path.resolve(__dirname, '../database/database.sqlite'); const databasePath = path.resolve(__dirname, '../database/database.sqlite');
module.exports = { module.exports = {

View File

@@ -1,6 +1,6 @@
const jwt = require('jsonwebtoken'); const jwt = require('jsonwebtoken');
const { roles, defaultDangerKey } = require('../routes/users/authSettings');
const { DataTypes } = require('sequelize'); const { DataTypes } = require('sequelize');
const { roles, defaultDangerKey } = require('../routes/users/authSettings');
const defineUser = require('../models/users'); const defineUser = require('../models/users');
function authMiddleware(sequelize) { function authMiddleware(sequelize) {
@@ -23,6 +23,7 @@ function authMiddleware(sequelize) {
req.userId = decoded.userId; req.userId = decoded.userId;
next(); next();
} catch (error) { } catch (error) {
console.error('Token verification failed:', error);
res.status(401).json({ error: 'Invalid token' }); res.status(401).json({ error: 'Invalid token' });
} }
} }

View File

@@ -1,5 +1,5 @@
const { memberRoles } = require('../routes/users/authSettings');
const { DataTypes } = require('sequelize'); const { DataTypes } = require('sequelize');
const { memberRoles } = require('../routes/users/authSettings');
const defineMember = require('../models/members'); const defineMember = require('../models/members');
const defineProject = require('../models/projects'); const defineProject = require('../models/projects');
const defineFolder = require('../models/folders'); const defineFolder = require('../models/folders');

View File

@@ -40,7 +40,7 @@ module.exports = {
}); });
}, },
down: async (queryInterface, Sequelize) => { down: async (queryInterface) => {
await queryInterface.dropTable('users'); await queryInterface.dropTable('users');
}, },
}; };

View File

@@ -42,7 +42,7 @@ module.exports = {
}); });
}, },
down: async (queryInterface, Sequelize) => { down: async (queryInterface) => {
await queryInterface.dropTable('projects'); await queryInterface.dropTable('projects');
}, },
}; };

View File

@@ -42,7 +42,7 @@ module.exports = {
}); });
}, },
async down(queryInterface, Sequelize) { async down(queryInterface) {
await queryInterface.dropTable('folders'); await queryInterface.dropTable('folders');
}, },
}; };

View File

@@ -46,7 +46,7 @@ module.exports = {
}); });
}, },
async down(queryInterface, Sequelize) { async down(queryInterface) {
await queryInterface.dropTable('runs'); await queryInterface.dropTable('runs');
}, },
}; };

View File

@@ -66,7 +66,7 @@ module.exports = {
}); });
}, },
async down(queryInterface, Sequelize) { async down(queryInterface) {
await queryInterface.dropTable('cases'); await queryInterface.dropTable('cases');
}, },
}; };

View File

@@ -28,7 +28,7 @@ module.exports = {
}); });
}, },
down: async (queryInterface, Sequelize) => { down: async (queryInterface) => {
await queryInterface.dropTable('steps'); await queryInterface.dropTable('steps');
}, },
}; };

View File

@@ -46,7 +46,7 @@ module.exports = {
}); });
}, },
down: async (queryInterface, Sequelize) => { down: async (queryInterface) => {
await queryInterface.dropTable('caseSteps'); await queryInterface.dropTable('caseSteps');
}, },
}; };

View File

@@ -32,7 +32,7 @@ module.exports = {
}); });
}, },
async down(queryInterface, Sequelize) { async down(queryInterface) {
await queryInterface.dropTable('attachments'); await queryInterface.dropTable('attachments');
}, },
}; };

View File

@@ -42,7 +42,7 @@ module.exports = {
}); });
}, },
down: async (queryInterface, Sequelize) => { down: async (queryInterface) => {
await queryInterface.dropTable('caseAttachments'); await queryInterface.dropTable('caseAttachments');
}, },
}; };

View File

@@ -46,7 +46,7 @@ module.exports = {
}); });
}, },
down: async (queryInterface, Sequelize) => { down: async (queryInterface) => {
await queryInterface.dropTable('runCases'); await queryInterface.dropTable('runCases');
}, },
}; };

View File

@@ -46,7 +46,7 @@ module.exports = {
}); });
}, },
down: async (queryInterface, Sequelize) => { down: async (queryInterface) => {
await queryInterface.dropTable('members'); await queryInterface.dropTable('members');
}, },
}; };

View File

@@ -2,7 +2,7 @@
/** @type {import('sequelize-cli').Migration} */ /** @type {import('sequelize-cli').Migration} */
module.exports = { module.exports = {
async up(queryInterface, Sequelize) { async up(queryInterface) {
/** /**
* Add altering commands here. * Add altering commands here.
* *
@@ -15,7 +15,7 @@ module.exports = {
await queryInterface.renameColumn('users', 'avatarPath', 'avatar_path'); await queryInterface.renameColumn('users', 'avatarPath', 'avatar_path');
}, },
async down(queryInterface, Sequelize) { async down() {
/** /**
* Add reverting commands here. * Add reverting commands here.
* *

View File

@@ -2,8 +2,8 @@
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
const Sequelize = require('sequelize');
const process = require('process'); const process = require('process');
const Sequelize = require('sequelize');
const basename = path.basename(__filename); const basename = path.basename(__filename);
const env = process.env.NODE_ENV || 'development'; const env = process.env.NODE_ENV || 'development';
const config = require(__dirname + '/../config/config.json')[env]; const config = require(__dirname + '/../config/config.json')[env];

View File

@@ -1,7 +1,7 @@
const express = require('express'); const express = require('express');
const router = express.Router(); const router = express.Router();
const defineCase = require('../../models/cases');
const { DataTypes } = require('sequelize'); const { DataTypes } = require('sequelize');
const defineCase = require('../../models/cases');
module.exports = function (sequelize) { module.exports = function (sequelize) {
const { verifySignedIn } = require('../../middleware/auth')(sequelize); const { verifySignedIn } = require('../../middleware/auth')(sequelize);

View File

@@ -1,14 +1,12 @@
const express = require('express'); const express = require('express');
const router = express.Router(); const router = express.Router();
const defineCase = require('../../models/cases');
const defineStep = require('../../models/steps');
const { DataTypes } = require('sequelize'); const { DataTypes } = require('sequelize');
const defineCase = require('../../models/cases');
module.exports = function (sequelize) { module.exports = function (sequelize) {
const { verifySignedIn } = require('../../middleware/auth')(sequelize); const { verifySignedIn } = require('../../middleware/auth')(sequelize);
const { verifyProjectDeveloperFromCaseId } = require('../../middleware/verifyEditable')(sequelize); const { verifyProjectDeveloperFromCaseId } = require('../../middleware/verifyEditable')(sequelize);
const Case = defineCase(sequelize, DataTypes); const Case = defineCase(sequelize, DataTypes);
const Step = defineStep(sequelize, DataTypes);
router.put('/:caseId', verifySignedIn, verifyProjectDeveloperFromCaseId, async (req, res) => { router.put('/:caseId', verifySignedIn, verifyProjectDeveloperFromCaseId, async (req, res) => {
const caseId = req.params.caseId; const caseId = req.params.caseId;

View File

@@ -1,7 +1,7 @@
const express = require('express'); const express = require('express');
const router = express.Router(); const router = express.Router();
const defineCase = require('../../models/cases');
const { DataTypes } = require('sequelize'); const { DataTypes } = require('sequelize');
const defineCase = require('../../models/cases');
module.exports = function (sequelize) { module.exports = function (sequelize) {
const Case = defineCase(sequelize, DataTypes); const Case = defineCase(sequelize, DataTypes);

View File

@@ -1,10 +1,10 @@
const express = require('express'); const express = require('express');
const router = express.Router(); const router = express.Router();
const { DataTypes } = require('sequelize');
const defineProject = require('../../models/projects'); const defineProject = require('../../models/projects');
const defineFolder = require('../../models/folders'); const defineFolder = require('../../models/folders');
const defineCase = require('../../models/cases'); const defineCase = require('../../models/cases');
const defineRunCase = require('../../models/runCases'); const defineRunCase = require('../../models/runCases');
const { DataTypes } = require('sequelize');
module.exports = function (sequelize) { module.exports = function (sequelize) {
const Project = defineProject(sequelize, DataTypes); const Project = defineProject(sequelize, DataTypes);

View File

@@ -1,7 +1,7 @@
const express = require('express'); const express = require('express');
const router = express.Router(); const router = express.Router();
const defineCase = require('../../models/cases');
const { DataTypes } = require('sequelize'); const { DataTypes } = require('sequelize');
const defineCase = require('../../models/cases');
const requiredFields = ['title', 'state', 'priority', 'type', 'automationStatus', 'template']; const requiredFields = ['title', 'state', 'priority', 'type', 'automationStatus', 'template'];
@@ -50,6 +50,7 @@ module.exports = function (sequelize) {
res.json(newCase); res.json(newCase);
} catch (error) { } catch (error) {
console.error('Error creating new case:', error);
res.status(500).json({ error: 'Internal server error' }); res.status(500).json({ error: 'Internal server error' });
} }
}); });

View File

@@ -1,9 +1,9 @@
const express = require('express'); const express = require('express');
const router = express.Router(); const router = express.Router();
const { DataTypes } = require('sequelize');
const defineCase = require('../../models/cases'); const defineCase = require('../../models/cases');
const defineStep = require('../../models/steps'); const defineStep = require('../../models/steps');
const defineAttachment = require('../../models/attachments'); const defineAttachment = require('../../models/attachments');
const { DataTypes } = require('sequelize');
module.exports = function (sequelize) { module.exports = function (sequelize) {
const Case = defineCase(sequelize, DataTypes); const Case = defineCase(sequelize, DataTypes);

View File

@@ -1,7 +1,7 @@
const express = require('express'); const express = require('express');
const router = express.Router(); const router = express.Router();
const defineFolder = require('../../models/folders');
const { DataTypes } = require('sequelize'); const { DataTypes } = require('sequelize');
const defineFolder = require('../../models/folders');
module.exports = function (sequelize) { module.exports = function (sequelize) {
const { verifySignedIn } = require('../../middleware/auth')(sequelize); const { verifySignedIn } = require('../../middleware/auth')(sequelize);

View File

@@ -1,7 +1,7 @@
const express = require('express'); const express = require('express');
const router = express.Router(); const router = express.Router();
const defineFolder = require('../../models/folders');
const { DataTypes } = require('sequelize'); const { DataTypes } = require('sequelize');
const defineFolder = require('../../models/folders');
module.exports = function (sequelize) { module.exports = function (sequelize) {
const { verifySignedIn } = require('../../middleware/auth')(sequelize); const { verifySignedIn } = require('../../middleware/auth')(sequelize);

View File

@@ -1,7 +1,7 @@
const express = require('express'); const express = require('express');
const router = express.Router(); const router = express.Router();
const defineFolder = require('../../models/folders');
const { DataTypes } = require('sequelize'); const { DataTypes } = require('sequelize');
const defineFolder = require('../../models/folders');
module.exports = function (sequelize) { module.exports = function (sequelize) {
const { verifySignedIn } = require('../../middleware/auth')(sequelize); const { verifySignedIn } = require('../../middleware/auth')(sequelize);

View File

@@ -1,7 +1,7 @@
const express = require('express'); const express = require('express');
const router = express.Router(); const router = express.Router();
const defineFolder = require('../../models/folders');
const { DataTypes } = require('sequelize'); const { DataTypes } = require('sequelize');
const defineFolder = require('../../models/folders');
module.exports = function (sequelize) { module.exports = function (sequelize) {
const { verifySignedIn } = require('../../middleware/auth')(sequelize); const { verifySignedIn } = require('../../middleware/auth')(sequelize);
@@ -25,6 +25,7 @@ module.exports = function (sequelize) {
res.json(newFolder); res.json(newFolder);
} catch (error) { } catch (error) {
console.error('Error creating new folder:', error);
res.status(500).json({ error: 'Internal server error' }); res.status(500).json({ error: 'Internal server error' });
} }
}); });

View File

@@ -1,11 +1,11 @@
const express = require('express'); const express = require('express');
const router = express.Router(); const router = express.Router();
const { DataTypes } = require('sequelize');
const defineProject = require('../../models/projects'); const defineProject = require('../../models/projects');
const defineFolder = require('../../models/folders'); const defineFolder = require('../../models/folders');
const defineCase = require('../../models/cases'); const defineCase = require('../../models/cases');
const defineRun = require('../../models/runs'); const defineRun = require('../../models/runs');
const defineRunCase = require('../../models/runCases'); const defineRunCase = require('../../models/runCases');
const { DataTypes } = require('sequelize');
module.exports = function (sequelize) { module.exports = function (sequelize) {
const { verifySignedIn } = require('../../middleware/auth')(sequelize); const { verifySignedIn } = require('../../middleware/auth')(sequelize);

View File

@@ -1,8 +1,8 @@
const express = require('express'); const express = require('express');
const router = express.Router(); const router = express.Router();
const { DataTypes } = require('sequelize');
const defineMember = require('../../models/members'); const defineMember = require('../../models/members');
const defineProject = require('../../models/projects'); const defineProject = require('../../models/projects');
const { DataTypes } = require('sequelize');
module.exports = function (sequelize) { module.exports = function (sequelize) {
const { verifySignedIn } = require('../../middleware/auth')(sequelize); const { verifySignedIn } = require('../../middleware/auth')(sequelize);

View File

@@ -1,7 +1,7 @@
const express = require('express'); const express = require('express');
const router = express.Router(); const router = express.Router();
const defineMember = require('../../models/members');
const { DataTypes } = require('sequelize'); const { DataTypes } = require('sequelize');
const defineMember = require('../../models/members');
module.exports = function (sequelize) { module.exports = function (sequelize) {
const { verifySignedIn } = require('../../middleware/auth')(sequelize); const { verifySignedIn } = require('../../middleware/auth')(sequelize);

View File

@@ -1,7 +1,7 @@
const express = require('express'); const express = require('express');
const router = express.Router(); const router = express.Router();
const defineMember = require('../../models/members');
const { DataTypes } = require('sequelize'); const { DataTypes } = require('sequelize');
const defineMember = require('../../models/members');
module.exports = function (sequelize) { module.exports = function (sequelize) {
const { verifySignedIn } = require('../../middleware/auth')(sequelize); const { verifySignedIn } = require('../../middleware/auth')(sequelize);

View File

@@ -1,8 +1,8 @@
const express = require('express'); const express = require('express');
const router = express.Router(); const router = express.Router();
const { DataTypes } = require('sequelize');
const defineUser = require('../../models/users'); const defineUser = require('../../models/users');
const defineMember = require('../../models/members'); const defineMember = require('../../models/members');
const { DataTypes } = require('sequelize');
module.exports = function (sequelize) { module.exports = function (sequelize) {
const { verifySignedIn } = require('../../middleware/auth')(sequelize); const { verifySignedIn } = require('../../middleware/auth')(sequelize);

View File

@@ -1,7 +1,7 @@
const express = require('express'); const express = require('express');
const router = express.Router(); const router = express.Router();
const defineMember = require('../../models/members');
const { DataTypes } = require('sequelize'); const { DataTypes } = require('sequelize');
const defineMember = require('../../models/members');
const { memberRoles } = require('../../routes/users/authSettings'); const { memberRoles } = require('../../routes/users/authSettings');
module.exports = function (sequelize) { module.exports = function (sequelize) {

View File

@@ -1,9 +1,9 @@
const express = require('express'); const express = require('express');
const router = express.Router(); const router = express.Router();
const { DataTypes } = require('sequelize');
const defineProject = require('../../models/projects'); const defineProject = require('../../models/projects');
const defineFolder = require('../../models/folders'); const defineFolder = require('../../models/folders');
const defineRun = require('../../models/runs'); const defineRun = require('../../models/runs');
const { DataTypes } = require('sequelize');
module.exports = function (sequelize) { module.exports = function (sequelize) {
const { verifySignedIn } = require('../../middleware/auth')(sequelize); const { verifySignedIn } = require('../../middleware/auth')(sequelize);

View File

@@ -1,7 +1,7 @@
const express = require('express'); const express = require('express');
const router = express.Router(); const router = express.Router();
const defineProject = require('../../models/projects');
const { DataTypes } = require('sequelize'); const { DataTypes } = require('sequelize');
const defineProject = require('../../models/projects');
module.exports = function (sequelize) { module.exports = function (sequelize) {
const { verifySignedIn } = require('../../middleware/auth')(sequelize); const { verifySignedIn } = require('../../middleware/auth')(sequelize);

View File

@@ -1,7 +1,7 @@
const express = require('express'); const express = require('express');
const router = express.Router(); const router = express.Router();
const defineProject = require('../../models/projects');
const { DataTypes } = require('sequelize'); const { DataTypes } = require('sequelize');
const defineProject = require('../../models/projects');
module.exports = function (sequelize) { module.exports = function (sequelize) {
const { verifySignedIn } = require('../../middleware/auth')(sequelize); const { verifySignedIn } = require('../../middleware/auth')(sequelize);

View File

@@ -1,8 +1,8 @@
const express = require('express'); const express = require('express');
const router = express.Router(); const router = express.Router();
const { DataTypes } = require('sequelize');
const defineProject = require('../../models/projects'); const defineProject = require('../../models/projects');
const defineFolder = require('../../models/folders'); const defineFolder = require('../../models/folders');
const { DataTypes } = require('sequelize');
module.exports = function (sequelize) { module.exports = function (sequelize) {
const { verifySignedIn } = require('../../middleware/auth')(sequelize); const { verifySignedIn } = require('../../middleware/auth')(sequelize);

View File

@@ -1,7 +1,7 @@
const express = require('express'); const express = require('express');
const router = express.Router(); const router = express.Router();
const defineRunCase = require('../../models/runCases');
const { DataTypes } = require('sequelize'); const { DataTypes } = require('sequelize');
const defineRunCase = require('../../models/runCases');
module.exports = function (sequelize) { module.exports = function (sequelize) {
const { verifySignedIn } = require('../../middleware/auth')(sequelize); const { verifySignedIn } = require('../../middleware/auth')(sequelize);

View File

@@ -1,7 +1,7 @@
const express = require('express'); const express = require('express');
const router = express.Router(); const router = express.Router();
const defineRunCase = require('../../models/runCases');
const { DataTypes } = require('sequelize'); const { DataTypes } = require('sequelize');
const defineRunCase = require('../../models/runCases');
module.exports = function (sequelize) { module.exports = function (sequelize) {
const { verifySignedIn } = require('../../middleware/auth')(sequelize); const { verifySignedIn } = require('../../middleware/auth')(sequelize);

View File

@@ -1,7 +1,7 @@
const express = require('express'); const express = require('express');
const router = express.Router(); const router = express.Router();
const defineRun = require('../../models/runs');
const { DataTypes } = require('sequelize'); const { DataTypes } = require('sequelize');
const defineRun = require('../../models/runs');
module.exports = function (sequelize) { module.exports = function (sequelize) {
const { verifySignedIn } = require('../../middleware/auth')(sequelize); const { verifySignedIn } = require('../../middleware/auth')(sequelize);

View File

@@ -1,7 +1,7 @@
const express = require('express'); const express = require('express');
const router = express.Router(); const router = express.Router();
const defineRun = require('../../models/runs');
const { DataTypes } = require('sequelize'); const { DataTypes } = require('sequelize');
const defineRun = require('../../models/runs');
module.exports = function (sequelize) { module.exports = function (sequelize) {
const Run = defineRun(sequelize, DataTypes); const Run = defineRun(sequelize, DataTypes);

View File

@@ -1,7 +1,7 @@
const express = require('express'); const express = require('express');
const router = express.Router(); const router = express.Router();
const defineRun = require('../../models/runs');
const { DataTypes } = require('sequelize'); const { DataTypes } = require('sequelize');
const defineRun = require('../../models/runs');
module.exports = function (sequelize) { module.exports = function (sequelize) {
const { verifySignedIn } = require('../../middleware/auth')(sequelize); const { verifySignedIn } = require('../../middleware/auth')(sequelize);

View File

@@ -1,7 +1,7 @@
const express = require('express'); const express = require('express');
const router = express.Router(); const router = express.Router();
const defineRun = require('../../models/runs');
const { DataTypes } = require('sequelize'); const { DataTypes } = require('sequelize');
const defineRun = require('../../models/runs');
module.exports = function (sequelize) { module.exports = function (sequelize) {
const { verifySignedIn } = require('../../middleware/auth')(sequelize); const { verifySignedIn } = require('../../middleware/auth')(sequelize);
@@ -26,6 +26,7 @@ module.exports = function (sequelize) {
res.json(newRun); res.json(newRun);
} catch (error) { } catch (error) {
console.error('Error creating new run:', error);
res.status(500).json({ error: 'Internal server error' }); res.status(500).json({ error: 'Internal server error' });
} }
}); });

View File

@@ -1,8 +1,8 @@
const express = require('express'); const express = require('express');
const router = express.Router(); const router = express.Router();
const { DataTypes, literal } = require('sequelize');
const defineRun = require('../../models/runs'); const defineRun = require('../../models/runs');
const defineRunCase = require('../../models/runCases'); const defineRunCase = require('../../models/runCases');
const { DataTypes, literal } = require('sequelize');
module.exports = function (sequelize) { module.exports = function (sequelize) {
const { verifySignedIn } = require('../../middleware/auth')(sequelize); const { verifySignedIn } = require('../../middleware/auth')(sequelize);

View File

@@ -1,8 +1,8 @@
const express = require('express'); const express = require('express');
const router = express.Router(); const router = express.Router();
const { DataTypes } = require('sequelize');
const defineStep = require('../../models/steps'); const defineStep = require('../../models/steps');
const defineCaseStep = require('../../models/caseSteps'); const defineCaseStep = require('../../models/caseSteps');
const { DataTypes } = require('sequelize');
module.exports = function (sequelize) { module.exports = function (sequelize) {
const Step = defineStep(sequelize, DataTypes); const Step = defineStep(sequelize, DataTypes);

View File

@@ -1,7 +1,7 @@
const express = require('express'); const express = require('express');
const router = express.Router(); const router = express.Router();
const defineUser = require('../../models/users');
const { DataTypes } = require('sequelize'); const { DataTypes } = require('sequelize');
const defineUser = require('../../models/users');
module.exports = function (sequelize) { module.exports = function (sequelize) {
const { verifySignedIn } = require('../../middleware/auth')(sequelize); const { verifySignedIn } = require('../../middleware/auth')(sequelize);

View File

@@ -1,7 +1,7 @@
const express = require('express'); const express = require('express');
const router = express.Router(); const router = express.Router();
const defineUser = require('../../models/users');
const { DataTypes } = require('sequelize'); const { DataTypes } = require('sequelize');
const defineUser = require('../../models/users');
module.exports = function (sequelize) { module.exports = function (sequelize) {
const { verifySignedIn, verifyAdmin } = require('../../middleware/auth')(sequelize); const { verifySignedIn, verifyAdmin } = require('../../middleware/auth')(sequelize);

View File

@@ -1,8 +1,8 @@
const express = require('express'); const express = require('express');
const router = express.Router(); const router = express.Router();
const { DataTypes, Op } = require('sequelize');
const defineUser = require('../../models/users'); const defineUser = require('../../models/users');
const defineMember = require('../../models/members'); const defineMember = require('../../models/members');
const { DataTypes, Op } = require('sequelize');
module.exports = function (sequelize) { module.exports = function (sequelize) {
const { verifySignedIn } = require('../../middleware/auth')(sequelize); const { verifySignedIn } = require('../../middleware/auth')(sequelize);

View File

@@ -1,9 +1,9 @@
const express = require('express'); const express = require('express');
const router = express.Router(); const router = express.Router();
const defineUser = require('../../models/users');
const { DataTypes } = require('sequelize'); const { DataTypes } = require('sequelize');
const bcrypt = require('bcrypt'); const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken'); const jwt = require('jsonwebtoken');
const defineUser = require('../../models/users');
const { defaultDangerKey } = require('./authSettings'); const { defaultDangerKey } = require('./authSettings');
module.exports = function (sequelize) { module.exports = function (sequelize) {

View File

@@ -1,10 +1,10 @@
const express = require('express'); const express = require('express');
const router = express.Router(); const router = express.Router();
const defineUser = require('../../models/users');
const { DataTypes } = require('sequelize'); const { DataTypes } = require('sequelize');
const { roles, defaultDangerKey } = require('./authSettings');
const bcrypt = require('bcrypt'); const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken'); const jwt = require('jsonwebtoken');
const defineUser = require('../../models/users');
const { roles, defaultDangerKey } = require('./authSettings');
module.exports = function (sequelize) { module.exports = function (sequelize) {
const User = defineUser(sequelize, DataTypes); const User = defineUser(sequelize, DataTypes);

View File

@@ -1,8 +1,8 @@
import express from 'express'; import express from 'express';
import { DataTypes } from 'sequelize'; import { DataTypes } from 'sequelize';
import defineUser from '../../models/users.js'; import defineUser from '../../models/users.js';
import { roles } from './authSettings.js';
import authMiddleware from '../../middleware/auth.js'; import authMiddleware from '../../middleware/auth.js';
import { roles } from './authSettings.js';
const router = express.Router(); const router = express.Router();
export default function (sequelize) { export default function (sequelize) {

View File

@@ -1,8 +1,8 @@
import { describe, it, expect, vi, beforeEach } from 'vitest'; import { describe, it, expect, vi, beforeEach } from 'vitest';
import request from 'supertest'; import request from 'supertest';
import express from 'express'; import express from 'express';
import updateRoute from './update';
import { Sequelize } from 'sequelize'; import { Sequelize } from 'sequelize';
import updateRoute from './update';
import { roles } from './authSettings'; import { roles } from './authSettings';
const adminRoleIndex = roles.findIndex((entry) => entry.uid === 'administrator'); const adminRoleIndex = roles.findIndex((entry) => entry.uid === 'administrator');
@@ -28,7 +28,7 @@ const mockUser = {
update: vi.fn(), update: vi.fn(),
}; };
vi.mock('../../models/users', () => ({ vi.mock('../../models/users', () => ({
default: (sequelize, DataTypes) => mockUser, default: () => mockUser,
})); }));
// test // test

View File

@@ -3,7 +3,7 @@ const fs = require('fs');
const bcrypt = require('bcrypt'); const bcrypt = require('bcrypt');
module.exports = { module.exports = {
up: async (queryInterface, Sequelize) => { up: async (queryInterface) => {
const hashedPassword = await bcrypt.hash('password', 10); const hashedPassword = await bcrypt.hash('password', 10);
// Add projects table records // Add projects table records
@@ -696,7 +696,7 @@ module.exports = {
]); ]);
}, },
down: async (queryInterface, Sequelize) => { down: async () => {
// do nothingg // do nothing
}, },
}; };

View File

@@ -1,9 +1,9 @@
// Use express from backend node_modules // Use express from backend node_modules
const express = require('./backend/node_modules/express');
const { createServer: createHttpServer } = require('http'); const { createServer: createHttpServer } = require('http');
const path = require('path'); const path = require('path');
const fs = require('fs'); const fs = require('fs');
const { execSync } = require('child_process'); const { execSync } = require('child_process');
const express = require('./backend/node_modules/express');
async function runMigrations() { async function runMigrations() {
try { try {

View File

@@ -1,5 +1,4 @@
'use client'; 'use client';
import React from 'react';
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import { import {
Button, Button,
@@ -63,7 +62,7 @@ export default function ProjectDialog({ isOpen, editingProject, onCancel, onSubm
setIsProjectPublic(true); setIsProjectPublic(true);
} }
}, [editingProject]); }, [editingProject, projectDetail, projectName]);
const clear = () => { const clear = () => {
setProjectName({ setProjectName({

View File

@@ -19,7 +19,11 @@ export const ThemeSwitch: FC<ThemeSwitchProps> = ({ className, classNames }) =>
const isSSR = useIsSSR(); const isSSR = useIsSSR();
const onChange = () => { const onChange = () => {
theme === 'light' ? setTheme('dark') : setTheme('light'); if (theme === 'light') {
setTheme('dark');
} else {
setTheme('light');
}
}; };
const { Component, slots, isSelected, getBaseProps, getInputProps, getWrapperProps } = useSwitch({ const { Component, slots, isSelected, getBaseProps, getInputProps, getWrapperProps } = useSwitch({

View File

@@ -10,7 +10,7 @@ export default function PublicityChip({ context }: Props) {
return context.isSignedIn() ? ( return context.isSignedIn() ? (
<Avatar <Avatar
size={16} size={16}
name={context.token!.user!.username} name={context.token?.user?.username}
variant="beam" variant="beam"
colors={['#0A0310', '#49007E', '#FF005B', '#FF7D10', '#FFB238']} colors={['#0A0310', '#49007E', '#FF005B', '#FF7D10', '#FFB238']}
/> />

View File

@@ -78,7 +78,7 @@ export default function DropdownAccount({ messages, locale, onItemPress }: Props
startContent={<UserAvatar context={context} />} startContent={<UserAvatar context={context} />}
endContent={<ChevronDown size={16} />} endContent={<ChevronDown size={16} />}
> >
{context.isSignedIn() ? context.token!.user!.username : messages.signIn} {context.isSignedIn() ? context.token?.user?.username : messages.signIn}
</Button> </Button>
</DropdownTrigger> </DropdownTrigger>
{context.isSignedIn() ? ( {context.isSignedIn() ? (

View File

@@ -1,7 +1,5 @@
'use client'; 'use client';
import { useState, useContext } from 'react'; import { useState, useContext } from 'react';
import { TokenContext } from '@/utils/TokenProvider';
import { Link, useRouter } from '@/src/i18n/routing';
import { usePathname } from 'next/navigation'; import { usePathname } from 'next/navigation';
import Image from 'next/image'; import Image from 'next/image';
import { import {
@@ -12,16 +10,17 @@ import {
NavbarBrand, NavbarBrand,
NavbarItem, NavbarItem,
Link as NextUiLink, Link as NextUiLink,
Chip,
ListboxItem, ListboxItem,
Listbox, Listbox,
} from '@heroui/react'; } from '@heroui/react';
import { ArrowRightFromLine, ArrowRightToLine, File, Globe, MoveUpRight, PenTool } from 'lucide-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 { ThemeSwitch } from '@/components/ThemeSwitch';
import { GithubIcon } from '@/components/icons'; import { GithubIcon } from '@/components/icons';
import { locales } from '@/config/selection'; import { locales } from '@/config/selection';
import DropdownAccount from './DropdownAccount'; import { Link, useRouter } from '@/src/i18n/routing';
import DropdownLanguage from './DropdownLanguage'; import { TokenContext } from '@/utils/TokenProvider';
import UserAvatar from '@/components/UserAvatar'; import UserAvatar from '@/components/UserAvatar';
import { LocaleCodeType } from '@/types/locale'; import { LocaleCodeType } from '@/types/locale';
import Config from '@/config/config'; import Config from '@/config/config';

View File

@@ -1,14 +1,15 @@
'use client'; 'use client';
import { useState, useEffect, useContext } from 'react'; import { useState, useEffect, useContext } from 'react';
import { Link, NextUiLinkClasses } from '@/src/i18n/routing';
import { Button, Card, CardHeader, CardFooter } from '@heroui/react'; import { Button, Card, CardHeader, CardFooter } from '@heroui/react';
import { TokenContext } from '@/utils/TokenProvider';
import Avatar from 'boring-avatars'; 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 { fetchMyProjects } from '@/utils/projectsControl';
import { ProjectType } from '@/types/project'; import { ProjectType } from '@/types/project';
import PublicityChip from '@/components/PublicityChip'; import PublicityChip from '@/components/PublicityChip';
import { LocaleCodeType } from '@/types/locale'; import { LocaleCodeType } from '@/types/locale';
import { ArrowRight } from 'lucide-react'; import { logError } from '@/utils/errorHandler';
type AccountPageMessages = { type AccountPageMessages = {
yourProjects: string; yourProjects: string;
@@ -36,8 +37,8 @@ export default function AccountPage({ messages, locale }: Props) {
try { try {
const data = await fetchMyProjects(context.token.access_token); const data = await fetchMyProjects(context.token.access_token);
setMyProjects(data); setMyProjects(data);
} catch (error: any) { } catch (error: unknown) {
console.error('Error in effect:', error.message); logError('Error fetching data:', error);
} }
} }
@@ -53,13 +54,13 @@ export default function AccountPage({ messages, locale }: Props) {
<CardHeader className="flex gap-6"> <CardHeader className="flex gap-6">
<Avatar <Avatar
size={48} size={48}
name={context.token!.user!.username} name={context.token?.user?.username}
variant="beam" variant="beam"
colors={['#0A0310', '#49007E', '#FF005B', '#FF7D10', '#FFB238']} colors={['#0A0310', '#49007E', '#FF005B', '#FF7D10', '#FFB238']}
/> />
<div className="flex flex-col"> <div className="flex flex-col">
<p className="text-xl font-bold">{context.token!.user!.username}</p> <p className="text-xl font-bold">{context.token?.user?.username}</p>
<p className="text-lg text-default-500">{context.token!.user!.email}</p> <p className="text-lg text-default-500">{context.token?.user?.email}</p>
</div> </div>
</CardHeader> </CardHeader>
</Card> </Card>

View File

@@ -1,6 +1,7 @@
import { UserType } from '@/types/user'; import { UserType } from '@/types/user';
import Config from '@/config/config'; import Config from '@/config/config';
import { roles } from '@/config/selection'; import { roles } from '@/config/selection';
import { logError } from '@/utils/errorHandler';
const apiServer = Config.apiServer; const apiServer = Config.apiServer;
async function signUp(newUser: UserType) { async function signUp(newUser: UserType) {
@@ -21,8 +22,8 @@ async function signUp(newUser: UserType) {
} }
const token = await response.json(); const token = await response.json();
return token; return token;
} catch (error: any) { } catch (error: unknown) {
console.error('Error sign up:', error); logError('Error sign up:', error);
throw error; throw error;
} }
} }
@@ -45,8 +46,8 @@ async function signIn(signInUser: UserType) {
} }
const token = await response.json(); const token = await response.json();
return token; return token;
} catch (error: any) { } catch (error: unknown) {
console.error('Error sign in:', error); logError('Error sign in:', error);
throw error; throw error;
} }
} }

View File

@@ -1,13 +1,12 @@
'use client'; 'use client';
import React from 'react';
import { useState, useContext } from 'react'; import { useState, useContext } from 'react';
import { Input, Button, Card, CardHeader, CardBody } from '@heroui/react'; import { Input, Button, Card, CardHeader, CardBody } from '@heroui/react';
import { Link } from '@/src/i18n/routing';
import { ChevronRight, Eye, EyeOff } from 'lucide-react'; 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 { signUp, signIn, signInAsGuest } from './authControl';
import { isValidEmail, isValidPassword } from './validate'; 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 { TokenContext } from '@/utils/TokenProvider';
import { useRouter } from '@/src/i18n/routing'; import { useRouter } from '@/src/i18n/routing';
import Config from '@/config/config'; import Config from '@/config/config';

View File

@@ -1,5 +1,5 @@
import { LocaleCodeType } from '@/types/locale';
import { getTranslations } from 'next-intl/server'; import { getTranslations } from 'next-intl/server';
import { LocaleCodeType } from '@/types/locale';
export async function generateMetadata({ params: { locale } }: { params: { locale: LocaleCodeType } }) { export async function generateMetadata({ params: { locale } }: { params: { locale: LocaleCodeType } }) {
const t = await getTranslations({ locale, namespace: 'Auth' }); const t = await getTranslations({ locale, namespace: 'Auth' });

View File

@@ -1,7 +1,7 @@
import { PageType } from '@/types/base';
import AuthPage from '../authPage';
import { getTranslations } from 'next-intl/server'; import { getTranslations } from 'next-intl/server';
import { useTranslations } from 'next-intl'; import { useTranslations } from 'next-intl';
import AuthPage from '../authPage';
import { PageType } from '@/types/base';
import { LocaleCodeType } from '@/types/locale'; import { LocaleCodeType } from '@/types/locale';
export async function generateMetadata({ params: { locale } }: { params: { locale: LocaleCodeType } }) { export async function generateMetadata({ params: { locale } }: { params: { locale: LocaleCodeType } }) {

View File

@@ -1,7 +1,7 @@
import { PageType } from '@/types/base';
import AuthPage from '../authPage';
import { getTranslations } from 'next-intl/server'; import { getTranslations } from 'next-intl/server';
import { useTranslations } from 'next-intl'; import { useTranslations } from 'next-intl';
import AuthPage from '../authPage';
import { PageType } from '@/types/base';
import { LocaleCodeType } from '@/types/locale'; import { LocaleCodeType } from '@/types/locale';
export async function generateMetadata({ params: { locale } }: { params: { locale: LocaleCodeType } }) { export async function generateMetadata({ params: { locale } }: { params: { locale: LocaleCodeType } }) {

View File

@@ -1,16 +1,16 @@
'use client'; 'use client';
import React from 'react';
import { useState, useEffect, useContext } 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 { UserType, AdminMessages } from '@/types/user';
import { TokenContext } from '@/utils/TokenProvider'; import { TokenContext } from '@/utils/TokenProvider';
import { useRouter } from '@/src/i18n/routing'; import { useRouter } from '@/src/i18n/routing';
import UsersTable from './UsersTable';
import Config from '@/config/config'; import Config from '@/config/config';
import { LocaleCodeType } from '@/types/locale'; import { LocaleCodeType } from '@/types/locale';
import { updateUserRole } from '@/utils/usersControl'; import { updateUserRole } from '@/utils/usersControl';
import { Button, addToast } from '@heroui/react';
import { roles } from '@/config/selection'; import { roles } from '@/config/selection';
import DeleteConfirmDialog from '@/components/DeleteConfirmDialog'; import DeleteConfirmDialog from '@/components/DeleteConfirmDialog';
import { logError } from '@/utils/errorHandler';
const apiServer = Config.apiServer; const apiServer = Config.apiServer;
type Props = { type Props = {
@@ -36,8 +36,8 @@ async function fetchUsers(jwt: string) {
} }
const data = await response.json(); const data = await response.json();
return data; return data;
} catch (error: any) { } catch (error: unknown) {
console.error('Error fetching data:', error.message); logError('Error fetching data:', error);
} }
} }
@@ -66,8 +66,8 @@ export default function AdminPage({ messages, locale }: Props) {
if (tokenContext.token.user) { if (tokenContext.token.user) {
setMyself(tokenContext.token.user); setMyself(tokenContext.token.user);
} }
} catch (error: any) { } catch (error: unknown) {
console.error('Error in effect:', error.message); logError('Error fetching users:', error);
} }
} }

View File

@@ -14,9 +14,9 @@ import {
DropdownItem, DropdownItem,
} from '@heroui/react'; } from '@heroui/react';
import { ChevronDown } from 'lucide-react'; import { ChevronDown } from 'lucide-react';
import Avatar from 'boring-avatars';
import { UserType, AdminMessages } from '@/types/user'; import { UserType, AdminMessages } from '@/types/user';
import { roles } from '@/config/selection'; import { roles } from '@/config/selection';
import Avatar from 'boring-avatars';
type Props = { type Props = {
users: UserType[]; users: UserType[];

View File

@@ -4,6 +4,7 @@ import { Table, TableBody, TableRow, TableHeader, TableCell, Chip, TableColumn }
import { LocaleCodeType } from '@/types/locale'; import { LocaleCodeType } from '@/types/locale';
import { HealthMessages } from '@/types/health'; import { HealthMessages } from '@/types/health';
import Config from '@/config/config'; import Config from '@/config/config';
import { logError } from '@/utils/errorHandler';
const apiServer = Config.apiServer; const apiServer = Config.apiServer;
type Props = { type Props = {
@@ -21,8 +22,8 @@ async function fetchHealth() {
} }
const data = await response.json(); const data = await response.json();
return data; return data;
} catch (error: any) { } catch (error: unknown) {
console.log('Error fetching health data:', error); logError('Error fetching health data:', error);
} }
} }
@@ -38,8 +39,8 @@ export default function HealthPage({ messages, locale }: Props) {
const data = await fetchHealth(); const data = await fetchHealth();
setStatus(data.status); setStatus(data.status);
setIsFetching(false); setIsFetching(false);
} catch (error: any) { } catch (error: unknown) {
console.error('Error in effect:', error.message); logError('Error in effect:', error);
} }
} }

View File

@@ -1,12 +1,12 @@
import '@/styles/globals.css'; import '@/styles/globals.css';
import { fontSans } from '@/config/fonts';
import { Providers } from './providers';
import Header from './Header';
import clsx from 'clsx'; import clsx from 'clsx';
import { getTranslations } from 'next-intl/server'; import { getTranslations } from 'next-intl/server';
import { useTranslations } from 'next-intl'; import { useTranslations } from 'next-intl';
import { LocaleCodeType } from '@/types/locale';
import { headers } from 'next/headers'; 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 } }) { export async function generateMetadata({ params: { locale } }: { params: { locale: LocaleCodeType } }) {
const headersList = headers(); const headersList = headers();

View File

@@ -2,12 +2,13 @@
import { useEffect, useState, useContext } from 'react'; import { useEffect, useState, useContext } from 'react';
import { Button } from '@heroui/react'; import { Button } from '@heroui/react';
import { Plus } from 'lucide-react'; import { Plus } from 'lucide-react';
import ProjectsTable from './ProjectsTable';
import { TokenContext } from '@/utils/TokenProvider'; import { TokenContext } from '@/utils/TokenProvider';
import { ProjectDialogMessages, ProjectType, ProjectsMessages } from '@/types/project'; import { ProjectDialogMessages, ProjectType, ProjectsMessages } from '@/types/project';
import ProjectsTable from './ProjectsTable';
import ProjectDialog from '@/components/ProjectDialog'; import ProjectDialog from '@/components/ProjectDialog';
import { fetchProjects, createProject } from '@/utils/projectsControl'; import { fetchProjects, createProject } from '@/utils/projectsControl';
import { LocaleCodeType } from '@/types/locale'; import { LocaleCodeType } from '@/types/locale';
import { logError } from '@/utils/errorHandler';
export type Props = { export type Props = {
messages: ProjectsMessages; messages: ProjectsMessages;
@@ -27,8 +28,8 @@ export default function ProjectsPage({ messages, projectDialogMessages, locale }
try { try {
const data = await fetchProjects(context.token.access_token); const data = await fetchProjects(context.token.access_token);
setProjects(data); setProjects(data);
} catch (error: any) { } catch (error: unknown) {
console.error('Error in effect:', error.message); logError('Error fetching data:', error);
} }
} }

View File

@@ -1,8 +1,8 @@
import { useState, useMemo, useCallback, ReactNode } from 'react'; import { useState, useMemo, useCallback, ReactNode } from 'react';
import { Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, SortDescriptor } from '@heroui/react'; import { Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, SortDescriptor } from '@heroui/react';
import dayjs from 'dayjs';
import { Link, NextUiLinkClasses } from '@/src/i18n/routing'; import { Link, NextUiLinkClasses } from '@/src/i18n/routing';
import { ProjectType, ProjectsMessages } from '@/types/project'; import { ProjectType, ProjectsMessages } from '@/types/project';
import dayjs from 'dayjs';
import PublicityChip from '@/components/PublicityChip'; import PublicityChip from '@/components/PublicityChip';
import { LocaleCodeType } from '@/types/locale'; 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; return text.length > maxLength ? text.slice(0, maxLength) + '...' : text;
}; };
const renderCell = useCallback((project: ProjectType, columnKey: string): ReactNode => { const renderCell = useCallback(
const cellValue = project[columnKey as keyof ProjectType]; (project: ProjectType, columnKey: string): ReactNode => {
const cellValue = project[columnKey as keyof ProjectType];
switch (columnKey) { switch (columnKey) {
case 'id': case 'id':
return <span>{cellValue as number}</span>; return <span>{cellValue as number}</span>;
case 'isPublic': case 'isPublic':
return ( return (
<PublicityChip isPublic={cellValue as boolean} publicText={messages.public} privateText={messages.private} /> <PublicityChip
); isPublic={cellValue as boolean}
case 'name': publicText={messages.public}
const maxLength = 30; privateText={messages.private}
const truncatedDetail = truncateText(project.detail, maxLength); />
return ( );
<div> case 'name': {
<Link href={`/projects/${project.id}/home`} locale={locale} className={NextUiLinkClasses}> const maxLength = 30;
{cellValue as string} const truncatedDetail = truncateText(project.detail, maxLength);
</Link> return (
<div className="text-xs text-default-500"> <div>
<div>{truncatedDetail}</div> <Link href={`/projects/${project.id}/home`} locale={locale} className={NextUiLinkClasses}>
{cellValue as string}
</Link>
<div className="text-xs text-default-500">
<div>{truncatedDetail}</div>
</div>
</div> </div>
</div> );
); }
case 'updatedAt': case 'updatedAt':
return <span>{dayjs(cellValue as number).format('YYYY/MM/DD HH:mm')}</span>; return <span>{dayjs(cellValue as number).format('YYYY/MM/DD HH:mm')}</span>;
default: default:
return cellValue as string; return cellValue as string;
} }
}, []); },
[locale, messages.private, messages.public]
);
const classNames = useMemo( const classNames = useMemo(
() => ({ () => ({

View File

@@ -1,5 +1,4 @@
'use client'; 'use client';
import React from 'react';
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import { Button, Input, Textarea, Modal, ModalContent, ModalHeader, ModalBody, ModalFooter } from '@heroui/react'; import { Button, Input, Textarea, Modal, ModalContent, ModalHeader, ModalBody, ModalFooter } from '@heroui/react';
import { FolderType, FoldersMessages } from '@/types/folder'; import { FolderType, FoldersMessages } from '@/types/folder';
@@ -47,7 +46,7 @@ export default function FolderDialog({ isOpen, editingFolder, onCancel, onSubmit
text: '', text: '',
}); });
} }
}, [editingFolder]); }, [editingFolder, folderDetail, folderName]);
const clear = () => { const clear = () => {
setFolderName({ setFolderName({

View File

@@ -1,15 +1,16 @@
'use client'; 'use client';
import { FolderType, FoldersMessages } from '@/types/folder';
import { useState, useEffect, useContext } from 'react'; import { useState, useEffect, useContext } from 'react';
import { Button, Listbox, ListboxItem } from '@heroui/react'; import { Button, Listbox, ListboxItem } from '@heroui/react';
import { Folder, Plus } from 'lucide-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 { usePathname, useRouter } from '@/src/i18n/routing';
import { TokenContext } from '@/utils/TokenProvider'; import { TokenContext } from '@/utils/TokenProvider';
import useGetCurrentIds from '@/utils/useGetCurrentIds'; import useGetCurrentIds from '@/utils/useGetCurrentIds';
import FolderDialog from './FolderDialog';
import FolderEditMenu from './FolderEditMenu';
import DeleteConfirmDialog from '@/components/DeleteConfirmDialog'; 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 = { type Props = {
projectId: string; projectId: string;
@@ -49,13 +50,13 @@ export default function FoldersPane({ projectId, messages, locale }: Props) {
const smallestFolderId = Math.min(...folders.map((folder) => folder.id)); const smallestFolderId = Math.min(...folders.map((folder) => folder.id));
router.push(`/projects/${projectId}/folders/${smallestFolderId}/cases`, { locale: locale }); router.push(`/projects/${projectId}/folders/${smallestFolderId}/cases`, { locale: locale });
} }
} catch (error: any) { } catch (error: unknown) {
console.error('Error in effect:', error.message); logError('Error fetching folders:', error);
} }
} }
fetchDataEffect(); fetchDataEffect();
}, [context, folderId]); }, [context, folderId, locale, pathname, projectId, router]);
const openDialogForCreate = () => { const openDialogForCreate = () => {
setIsFolderDialogOpen(true); setIsFolderDialogOpen(true);

View File

@@ -1,6 +1,5 @@
'use client'; 'use client';
import React from 'react'; import { useState } from 'react';
import { useState, useEffect } from 'react';
import { Button, Input, Textarea, Modal, ModalContent, ModalHeader, ModalBody, ModalFooter } from '@heroui/react'; import { Button, Input, Textarea, Modal, ModalContent, ModalHeader, ModalBody, ModalFooter } from '@heroui/react';
import { CasesMessages } from '@/types/case'; import { CasesMessages } from '@/types/case';

View File

@@ -8,6 +8,7 @@ import { CaseType, CasesMessages } from '@/types/case';
import DeleteConfirmDialog from '@/components/DeleteConfirmDialog'; import DeleteConfirmDialog from '@/components/DeleteConfirmDialog';
import { PriorityMessages } from '@/types/priority'; import { PriorityMessages } from '@/types/priority';
import { LocaleCodeType } from '@/types/locale'; import { LocaleCodeType } from '@/types/locale';
import { logError } from '@/utils/errorHandler';
type Props = { type Props = {
projectId: string; projectId: string;
@@ -30,8 +31,8 @@ export default function CasesPane({ projectId, folderId, messages, priorityMessa
try { try {
const data = await fetchCases(context.token.access_token, Number(folderId)); const data = await fetchCases(context.token.access_token, Number(folderId));
setCases(data); setCases(data);
} catch (error: any) { } catch (error: unknown) {
console.error('Error in effect:', error.message); logError('Error fetching cases:', error);
} }
} }

View File

@@ -15,7 +15,7 @@ import {
SortDescriptor, SortDescriptor,
ButtonGroup, ButtonGroup,
} from '@heroui/react'; } 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 { Link } from '@/src/i18n/routing';
import { CaseType, CasesMessages } from '@/types/case'; import { CaseType, CasesMessages } from '@/types/case';
import { PriorityMessages } from '@/types/priority'; import { PriorityMessages } from '@/types/priority';
@@ -122,6 +122,7 @@ export default function TestCaseTable({
default: default:
return cellValue as string; return cellValue as string;
} }
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []); }, []);
const handleDeleteCases = () => { const handleDeleteCases = () => {

View File

@@ -1,19 +1,20 @@
'use client'; 'use client';
import { useState, useEffect, useContext, ChangeEvent, DragEvent } from 'react'; import { useState, useEffect, useContext, ChangeEvent, DragEvent } from 'react';
import { Input, Textarea, Select, SelectItem, Button, Divider, Tooltip, addToast, Badge } from '@heroui/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 { Save, Plus, ArrowLeft, Circle } from 'lucide-react';
import { priorities, testTypes, templates } from '@/config/selection';
import CaseStepsEditor from './CaseStepsEditor'; import CaseStepsEditor from './CaseStepsEditor';
import CaseAttachmentsEditor from './CaseAttachmentsEditor'; import CaseAttachmentsEditor from './CaseAttachmentsEditor';
import { fetchCase, updateCase } from '@/utils/caseControl';
import { updateSteps } from './stepControl'; import { updateSteps } from './stepControl';
import { fetchCreateAttachments, fetchDownloadAttachment, fetchDeleteAttachment } from './attachmentControl'; 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 { TokenContext } from '@/utils/TokenProvider';
import { useFormGuard } from '@/utils/formGuard'; import { useFormGuard } from '@/utils/formGuard';
import { CaseType, AttachmentType, CaseMessages, StepType } from '@/types/case'; import { CaseType, AttachmentType, CaseMessages, StepType } from '@/types/case';
import { PriorityMessages } from '@/types/priority'; import { PriorityMessages } from '@/types/priority';
import { TestTypeMessages } from '@/types/testType'; import { TestTypeMessages } from '@/types/testType';
import { logError } from '@/utils/errorHandler';
const defaultTestCase = { const defaultTestCase = {
id: 0, id: 0,
@@ -220,13 +221,13 @@ export default function CaseEditor({
step.editState = 'notChanged'; step.editState = 'notChanged';
}); });
setTestCase(data); setTestCase(data);
} catch (error: any) { } catch (error: unknown) {
console.error('Error in effect:', error.message); logError('Error fetching case data', error);
} }
} }
fetchDataEffect(); fetchDataEffect();
}, [tokenContext]); }, [caseId, tokenContext]);
return ( return (
<> <>

View File

@@ -1,6 +1,6 @@
import { Textarea, Button, Tooltip, Avatar } from '@heroui/react'; import { Textarea, Button, Tooltip, Avatar } from '@heroui/react';
import { CaseMessages, StepType } from '@/types/case';
import { Plus, Trash } from 'lucide-react'; import { Plus, Trash } from 'lucide-react';
import { CaseMessages, StepType } from '@/types/case';
type Props = { type Props = {
isDisabled: boolean; isDisabled: boolean;

View File

@@ -1,4 +1,5 @@
import Config from '@/config/config'; import Config from '@/config/config';
import { logError } from '@/utils/errorHandler';
const apiServer = Config.apiServer; const apiServer = Config.apiServer;
async function fetchDownloadAttachment(attachmentId: number, downloadFileName: string) { async function fetchDownloadAttachment(attachmentId: number, downloadFileName: string) {
@@ -26,8 +27,8 @@ async function fetchDownloadAttachment(attachmentId: number, downloadFileName: s
document.body.appendChild(link); document.body.appendChild(link);
link.click(); link.click();
document.body.removeChild(link); document.body.removeChild(link);
} catch (error: any) { } catch (error: unknown) {
console.error('Error downloading file:', error); logError('Error downloading attachment', error);
throw error; throw error;
} }
} }
@@ -51,8 +52,8 @@ async function fetchCreateAttachments(caseId: number, files: File[]) {
const responseData = await response.json(); const responseData = await response.json();
return responseData; return responseData;
} catch (error: any) { } catch (error: unknown) {
console.error('Error uploading files:', error); logError('Error uploading files', error);
} }
} }
@@ -71,8 +72,8 @@ async function fetchDeleteAttachment(attachmentId: number) {
if (!response.ok) { if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`); throw new Error(`HTTP error! Status: ${response.status}`);
} }
} catch (error: any) { } catch (error: unknown) {
console.error('Error deleting file:', error); logError('Error deleting file:', error);
throw error; throw error;
} }
} }

View File

@@ -1,6 +1,6 @@
import { PriorityMessages } from '@/types/priority';
import CaseEditor from './CaseEditor';
import { useTranslations } from 'next-intl'; import { useTranslations } from 'next-intl';
import CaseEditor from './CaseEditor';
import { PriorityMessages } from '@/types/priority';
import { TestTypeMessages } from '@/types/testType'; import { TestTypeMessages } from '@/types/testType';
export default function Page({ export default function Page({

View File

@@ -1,5 +1,6 @@
import Config from '@/config/config'; import Config from '@/config/config';
import { StepType } from '@/types/case'; import { StepType } from '@/types/case';
import { logError } from '@/utils/errorHandler';
const apiServer = Config.apiServer; const apiServer = Config.apiServer;
async function updateSteps(jwt: string, caseId: number, steps: StepType[]) { 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}`); throw new Error(`HTTP error! Status: ${response.status}`);
} }
return await response.json(); return await response.json();
} catch (error: any) { } catch (error: unknown) {
console.error('Error deleting project:', error); logError('Error updating steps', error);
throw error; throw error;
} }
} }

View File

@@ -1,4 +1,5 @@
import Config from '@/config/config'; import Config from '@/config/config';
import { logError } from '@/utils/errorHandler';
const apiServer = Config.apiServer; const apiServer = Config.apiServer;
/** /**
@@ -21,8 +22,8 @@ async function fetchFolders(jwt: string, projectId: number) {
const data = await response.json(); const data = await response.json();
return data; return data;
} catch (error: any) { } catch (error: unknown) {
console.error('Error fetching data:', error.message); logError('Error fetching data:', error);
} }
} }
@@ -60,8 +61,8 @@ async function createFolder(
} }
const data = await response.json(); const data = await response.json();
return data; return data;
} catch (error: any) { } catch (error: unknown) {
console.error('Error creating new project:', error); logError('Error creating new folder:', error);
throw error; throw error;
} }
} }
@@ -102,8 +103,8 @@ async function updateFolder(
} }
const data = await response.json(); const data = await response.json();
return data; return data;
} catch (error: any) { } catch (error: unknown) {
console.error('Error updating project:', error); logError('Error updating folder:', error);
throw error; throw error;
} }
} }
@@ -127,8 +128,8 @@ async function deleteFolder(jwt: string, folderId: number) {
if (!response.ok) { if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`); throw new Error(`HTTP error! Status: ${response.status}`);
} }
} catch (error: any) { } catch (error: unknown) {
console.error('Error deleting project:', error); logError('Error deleting folder:', error);
throw error; throw error;
} }
} }

View File

@@ -1,5 +1,5 @@
import FoldersPane from './FoldersPane';
import { useTranslations } from 'next-intl'; import { useTranslations } from 'next-intl';
import FoldersPane from './FoldersPane';
export default function FoldersLayout({ export default function FoldersLayout({
children, children,

View File

@@ -1,22 +1,23 @@
'use client'; 'use client';
import { useState, useEffect, useContext } from 'react'; import { useState, useEffect, useContext } from 'react';
import { title, subtitle } from '@/components/primitives';
import { Card, CardBody, Chip, Divider } from '@heroui/react'; import { Card, CardBody, Chip, Divider } from '@heroui/react';
import { Folder, Clipboard, FlaskConical } from 'lucide-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 { useTheme } from 'next-themes';
import { aggregateBasicInfo, aggregateTestPriority, aggregateTestType, aggregateProgress } from './aggregate';
import { HomeMessages } from './page';
import TestTypesChart from './TestTypesDonutChart'; import TestTypesChart from './TestTypesDonutChart';
import TestPriorityChart from './TestPriorityDonutChart'; import TestPriorityChart from './TestPriorityDonutChart';
import TestProgressBarChart from './TestProgressColumnChart'; 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 { TestRunCaseStatusMessages } from '@/types/status';
import { TestTypeMessages } from '@/types/testType'; import { TestTypeMessages } from '@/types/testType';
import { PriorityMessages } from '@/types/priority'; import { PriorityMessages } from '@/types/priority';
import { ProjectType } from '@/types/project'; import { ProjectType } from '@/types/project';
import { CasePriorityCountType, CaseTypeCountType } from '@/types/chart'; import { CasePriorityCountType, CaseTypeCountType } from '@/types/chart';
import { logError } from '@/utils/errorHandler';
const apiServer = Config.apiServer; const apiServer = Config.apiServer;
@@ -38,8 +39,8 @@ async function fetchProject(jwt: string, projectId: number) {
} }
const data = await response.json(); const data = await response.json();
return data; return data;
} catch (error: any) { } catch (error: unknown) {
console.error('Error fetching data:', error.message); logError('Error fetching data:', error);
} }
} }
@@ -59,7 +60,7 @@ export function ProjectHome({
priorityMessages, priorityMessages,
}: Props) { }: Props) {
const context = useContext(TokenContext); const context = useContext(TokenContext);
const { theme, setTheme } = useTheme(); const { theme } = useTheme();
const [project, setProject] = useState<ProjectType>({ const [project, setProject] = useState<ProjectType>({
id: 0, id: 0,
name: '', name: '',
@@ -88,13 +89,13 @@ export function ProjectHome({
try { try {
const data = await fetchProject(context.token.access_token, Number(projectId)); const data = await fetchProject(context.token.access_token, Number(projectId));
setProject(data); setProject(data);
} catch (error: any) { } catch (error: unknown) {
console.error('Error in effect:', error.message); logError('Error in effect:', error);
} }
} }
fetchDataEffect(); fetchDataEffect();
}, [context]); }, [context, projectId]);
useEffect(() => { useEffect(() => {
async function aggregate() { async function aggregate() {
@@ -118,7 +119,7 @@ export function ProjectHome({
} }
aggregate(); aggregate();
}, [project]); }, [project, testRunCaseStatusMessages]);
return ( return (
<div className="container mx-auto max-w-5xl pt-6 px-6 flex-grow"> <div className="container mx-auto max-w-5xl pt-6 px-6 flex-grow">

View File

@@ -1,4 +1,3 @@
import React from 'react';
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import dynamic from 'next/dynamic'; import dynamic from 'next/dynamic';
import { priorities } from '@/config/selection'; import { priorities } from '@/config/selection';
@@ -34,7 +33,7 @@ export default function TestPriorityDonutChart({ priorityCounts, priorityMessage
const colors = priorities.map((entry) => entry.chartColor); const colors = priorities.map((entry) => entry.chartColor);
const legend = { const legend = {
labels: { labels: {
colors: priorities.map((entry) => { colors: priorities.map(() => {
if (theme === 'light') { if (theme === 'light') {
return 'black'; return 'black';
} else { } else {
@@ -52,7 +51,7 @@ export default function TestPriorityDonutChart({ priorityCounts, priorityMessage
}; };
updateChartDate(); updateChartDate();
}, [priorityCounts, theme]); }, [priorityCounts, priorityMessages, theme]);
return <Chart options={chartData.options} series={chartData.series} type="donut" width={'100%'} height={'100%'} />; return <Chart options={chartData.options} series={chartData.series} type="donut" width={'100%'} height={'100%'} />;
} }

View File

@@ -1,4 +1,3 @@
import React from 'react';
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import dynamic from 'next/dynamic'; import dynamic from 'next/dynamic';
import { ProgressSeriesType } from '@/types/run'; import { ProgressSeriesType } from '@/types/run';
@@ -24,7 +23,7 @@ export default function TestProgressBarChart({ progressSeries, progressCategorie
useEffect(() => { useEffect(() => {
const updateChartDate = () => { const updateChartDate = () => {
if (progressSeries) { if (progressSeries) {
const legendsLabelColors = testRunCaseStatus.map((itr) => { const legendsLabelColors = testRunCaseStatus.map(() => {
if (theme === 'light') { if (theme === 'light') {
return 'black'; return 'black';
} else { } else {

View File

@@ -1,4 +1,3 @@
import React from 'react';
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import dynamic from 'next/dynamic'; import dynamic from 'next/dynamic';
import { testTypes } from '@/config/selection'; import { testTypes } from '@/config/selection';
@@ -33,7 +32,7 @@ export default function TestTypesDonutChart({ typesCounts, testTypeMessages, the
const colors = testTypes.map((entry) => entry.chartColor); const colors = testTypes.map((entry) => entry.chartColor);
const legend = { const legend = {
labels: { labels: {
colors: testTypes.map((entry) => { colors: testTypes.map(() => {
if (theme === 'light') { if (theme === 'light') {
return 'black'; return 'black';
} else { } else {
@@ -51,7 +50,7 @@ export default function TestTypesDonutChart({ typesCounts, testTypeMessages, the
}; };
updateChartDate(); updateChartDate();
}, [typesCounts, theme]); }, [typesCounts, theme, testTypeMessages]);
return <Chart options={chartData.options} series={chartData.series} type="donut" width={'100%'} height={'100%'} />; return <Chart options={chartData.options} series={chartData.series} type="donut" width={'100%'} height={'100%'} />;
} }

View File

@@ -18,7 +18,7 @@ function aggregateBasicInfo(project: ProjectType) {
function aggregateTestType(project: ProjectType): CaseTypeCountType[] { function aggregateTestType(project: ProjectType): CaseTypeCountType[] {
// count how many test cases are for each type // count how many test cases are for each type
const typesCounts: number[] = testTypes.map((entry) => { const typesCounts: number[] = testTypes.map(() => {
return 0; return 0;
}); });
project.Folders.forEach((folder) => { project.Folders.forEach((folder) => {
@@ -38,7 +38,7 @@ function aggregateTestType(project: ProjectType): CaseTypeCountType[] {
function aggregateTestPriority(project: ProjectType) { function aggregateTestPriority(project: ProjectType) {
// count how many test cases are for each priority // count how many test cases are for each priority
const priorityCounts: number[] = priorities.map((entry) => { const priorityCounts: number[] = priorities.map(() => {
return 0; return 0;
}); });
project.Folders.forEach((folder) => { project.Folders.forEach((folder) => {
@@ -58,10 +58,10 @@ function aggregateTestPriority(project: ProjectType) {
function aggregateProgress(project: ProjectType, testRunCaseStatusMessages: TestRunCaseStatusMessages) { function aggregateProgress(project: ProjectType, testRunCaseStatusMessages: TestRunCaseStatusMessages) {
type ChartSeries = { name: string; data: number[] }; type ChartSeries = { name: string; data: number[] };
let series: ChartSeries[] = testRunCaseStatus.map((status) => { const series: ChartSeries[] = testRunCaseStatus.map((status) => {
return { name: testRunCaseStatusMessages[status.uid], data: [] }; return { name: testRunCaseStatusMessages[status.uid], data: [] };
}); });
let categories: string[] = []; const categories: string[] = [];
project.Runs.forEach((run) => { project.Runs.forEach((run) => {
if (!run.RunCases) { if (!run.RunCases) {

View File

@@ -1,7 +1,7 @@
import { LocaleCodeType } from '@/types/locale';
import { ProjectHome } from './ProjectHome';
import { getTranslations } from 'next-intl/server'; import { getTranslations } from 'next-intl/server';
import { useTranslations } from 'next-intl'; import { useTranslations } from 'next-intl';
import { ProjectHome } from './ProjectHome';
import { LocaleCodeType } from '@/types/locale';
import { PriorityMessages } from '@/types/priority'; import { PriorityMessages } from '@/types/priority';
import { TestTypeMessages } from '@/types/testType'; import { TestTypeMessages } from '@/types/testType';
import { TestRunCaseStatusMessages } from '@/types/status'; import { TestRunCaseStatusMessages } from '@/types/status';

View File

@@ -1,6 +1,6 @@
import { ProjectMessages } from '@/types/project';
import Sidebar from './Sidebar';
import { useTranslations } from 'next-intl'; import { useTranslations } from 'next-intl';
import Sidebar from './Sidebar';
import { ProjectMessages } from '@/types/project';
export default function SidebarLayout({ export default function SidebarLayout({
children, children,

View File

@@ -1,12 +1,12 @@
'use client'; 'use client';
import React from 'react';
import { useState, useEffect, useContext } from 'react'; import { useState, useEffect, useContext } from 'react';
import { Button, Input, Modal, ModalContent, ModalHeader, ModalBody, ModalFooter } from '@heroui/react'; import { Button, Input, Modal, ModalContent, ModalHeader, ModalBody, ModalFooter } from '@heroui/react';
import CandidatesTable from './CandidatesTable';
import { TokenContext } from '@/utils/TokenProvider'; import { TokenContext } from '@/utils/TokenProvider';
import { UserType } from '@/types/user'; import { UserType } from '@/types/user';
import { searchUsers } from '@/utils/usersControl'; import { searchUsers } from '@/utils/usersControl';
import CandidatesTable from './CandidatesTable';
import { MembersMessages } from '@/types/member'; import { MembersMessages } from '@/types/member';
import { logError } from '@/utils/errorHandler';
type Props = { type Props = {
isOpen: boolean; isOpen: boolean;
@@ -34,13 +34,13 @@ export default function AddMemberDialog({ isOpen, projectId, onCancel, onAddMemb
try { try {
const data = await searchUsers(context.token.access_token, Number(projectId), searchText); const data = await searchUsers(context.token.access_token, Number(projectId), searchText);
setCandidates(data); setCandidates(data);
} catch (error: any) { } catch (error: unknown) {
console.error('Error in effect:', error.message); logError('Error fetching data:', error);
} }
} }
fetchDataEffect(); fetchDataEffect();
}, [searchText]); }, [context, projectId, searchText]);
const handleExit = () => { const handleExit = () => {
setSearchText(''); setSearchText('');

View File

@@ -1,7 +1,7 @@
import { useMemo, useCallback } from 'react'; import { useMemo, useCallback } from 'react';
import { Button, Table, TableHeader, TableColumn, TableBody, TableRow, TableCell } from '@heroui/react'; import { Button, Table, TableHeader, TableColumn, TableBody, TableRow, TableCell } from '@heroui/react';
import { UserType } from '@/types/user';
import Avatar from 'boring-avatars'; import Avatar from 'boring-avatars';
import { UserType } from '@/types/user';
import { MembersMessages } from '@/types/member'; import { MembersMessages } from '@/types/member';
type Props = { type Props = {
@@ -18,33 +18,36 @@ export default function MembersTable({ candidates, onAddPress, messages }: Props
{ name: messages.add, uid: 'add', sortable: false }, { name: messages.add, uid: 'add', sortable: false },
]; ];
const renderCell = useCallback((candidate: UserType, columnKey: string) => { const renderCell = useCallback(
const cellValue = candidate[columnKey as keyof UserType]; (candidate: UserType, columnKey: string) => {
const cellValue = candidate[columnKey as keyof UserType];
switch (columnKey) { switch (columnKey) {
case 'avatar': case 'avatar':
return ( return (
<Avatar <Avatar
size={16} size={16}
name={candidate.username} name={candidate.username}
variant="beam" variant="beam"
colors={['#0A0310', '#49007E', '#FF005B', '#FF7D10', '#FFB238']} colors={['#0A0310', '#49007E', '#FF005B', '#FF7D10', '#FFB238']}
/> />
); );
case 'email': case 'email':
return cellValue; return cellValue;
case 'username': case 'username':
return cellValue; return cellValue;
case 'add': case 'add':
return ( return (
<Button color="primary" variant="faded" size="sm" onPress={() => onAddPress(candidate)}> <Button color="primary" variant="faded" size="sm" onPress={() => onAddPress(candidate)}>
{messages.add} {messages.add}
</Button> </Button>
); );
default: default:
return cellValue; return cellValue;
} }
}, []); },
[messages.add, onAddPress]
);
const classNames = useMemo( const classNames = useMemo(
() => ({ () => ({

View File

@@ -1,23 +1,22 @@
'use client'; 'use client';
import React from 'react';
import { useState, useEffect, useContext } from 'react'; import { useState, useEffect, useContext } from 'react';
import { Button } from '@heroui/react'; import { Button } from '@heroui/react';
import { Plus } from 'lucide-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 MembersTable from './MembersTable';
import AddMemberDialog from './AddMemberDialog'; import AddMemberDialog from './AddMemberDialog';
import { fetchProjectMembers, addMember, deleteMember, updateMember } from './membersControl'; 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 DeleteConfirmDialog from '@/components/DeleteConfirmDialog';
import { logError } from '@/utils/errorHandler';
type Props = { type Props = {
projectId: string; projectId: string;
messages: MembersMessages; messages: MembersMessages;
locale: string;
}; };
export default function MembersPage({ projectId, messages, locale }: Props) { export default function MembersPage({ projectId, messages }: Props) {
const context = useContext(TokenContext); const context = useContext(TokenContext);
const [members, setMembers] = useState<MemberType[]>([]); const [members, setMembers] = useState<MemberType[]>([]);
const [isDialogOpen, setIsDialogOpen] = useState(false); const [isDialogOpen, setIsDialogOpen] = useState(false);
@@ -31,13 +30,13 @@ export default function MembersPage({ projectId, messages, locale }: Props) {
try { try {
const data = await fetchProjectMembers(context.token.access_token, projectId); const data = await fetchProjectMembers(context.token.access_token, projectId);
setMembers(data); setMembers(data);
} catch (error: any) { } catch (error: unknown) {
console.error('Error in effect:', error.message); logError('Error fetching members:', error);
} }
} }
fetchDataEffect(); fetchDataEffect();
}, [context]); }, [context, projectId]);
const handleAddMember = async (userAdded: UserType) => { const handleAddMember = async (userAdded: UserType) => {
if (userAdded.id) { if (userAdded.id) {

View File

@@ -14,9 +14,9 @@ import {
DropdownItem, DropdownItem,
} from '@heroui/react'; } from '@heroui/react';
import { ChevronDown } from 'lucide-react'; import { ChevronDown } from 'lucide-react';
import Avatar from 'boring-avatars';
import { MemberType, UserType } from '@/types/user'; import { MemberType, UserType } from '@/types/user';
import { memberRoles } from '@/config/selection'; import { memberRoles } from '@/config/selection';
import Avatar from 'boring-avatars';
import { MembersMessages } from '@/types/member'; import { MembersMessages } from '@/types/member';
type Props = { type Props = {

View File

@@ -1,3 +1,4 @@
import { logError } from '@/utils/errorHandler';
import Config from '@/config/config'; import Config from '@/config/config';
const apiServer = Config.apiServer; const apiServer = Config.apiServer;
@@ -19,8 +20,8 @@ async function fetchProjectMembers(jwt: string, projectId: string) {
} }
const data = await response.json(); const data = await response.json();
return data; return data;
} catch (error: any) { } catch (error: unknown) {
console.error('Error fetching data:', error.message); logError('Error fetching data:', error);
} }
} }
@@ -42,8 +43,8 @@ async function addMember(jwt: string, userId: number, projectId: number) {
} }
const data = await response.json(); const data = await response.json();
return data; return data;
} catch (error: any) { } catch (error: unknown) {
console.error('Error fetching data:', error.message); logError('Error fetching data:', error);
} }
} }
@@ -63,8 +64,8 @@ async function deleteMember(jwt: string, userId: number, projectId: number) {
if (!response.ok) { if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`); throw new Error(`HTTP error! Status: ${response.status}`);
} }
} catch (error: any) { } catch (error: unknown) {
console.error('Error fetching data:', error.message); logError('Error fetching data:', error);
} }
} }
@@ -86,8 +87,8 @@ async function updateMember(jwt: string, userId: number, projectId: number, role
} }
const data = await response.json(); const data = await response.json();
return data; return data;
} catch (error: any) { } catch (error: unknown) {
console.error('Error fetching data:', error.message); logError('Error fetching data:', error);
} }
} }

View File

@@ -1,7 +1,7 @@
import { LocaleCodeType } from '@/types/locale';
import MembersPage from './MembersPage';
import { getTranslations } from 'next-intl/server'; import { getTranslations } from 'next-intl/server';
import { useTranslations } from 'next-intl'; import { useTranslations } from 'next-intl';
import MembersPage from './MembersPage';
import { LocaleCodeType } from '@/types/locale';
export async function generateMetadata({ params: { locale } }: { params: { locale: LocaleCodeType } }) { export async function generateMetadata({ params: { locale } }: { params: { locale: LocaleCodeType } }) {
const t = await getTranslations({ locale, namespace: 'Members' }); const t = await getTranslations({ locale, namespace: 'Members' });
@@ -34,7 +34,7 @@ export default function Page({ params }: { params: { projectId: string; locale:
return ( return (
<> <>
<MembersPage projectId={params.projectId} messages={messages} locale={params.locale} /> <MembersPage projectId={params.projectId} messages={messages} />
</> </>
); );
} }

View File

@@ -1,5 +1,4 @@
'use client'; 'use client';
import React from 'react';
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import { Button, Input, Textarea, Modal, ModalContent, ModalHeader, ModalBody, ModalFooter } from '@heroui/react'; import { Button, Input, Textarea, Modal, ModalContent, ModalHeader, ModalBody, ModalFooter } from '@heroui/react';
import { RunType, RunsMessages } from '@/types/run'; import { RunType, RunsMessages } from '@/types/run';
@@ -47,7 +46,7 @@ export default function RunDialog({ isOpen, editingRun, onCancel, onSubmit, mess
text: '', text: '',
}); });
} }
}, [editingRun]); }, [editingRun, runDescription, runName]);
const clear = () => { const clear = () => {
setRunName({ setRunName({

View File

@@ -9,6 +9,7 @@ import { RunType, RunsMessages } from '@/types/run';
import DeleteConfirmDialog from '@/components/DeleteConfirmDialog'; import DeleteConfirmDialog from '@/components/DeleteConfirmDialog';
import { TokenContext } from '@/utils/TokenProvider'; import { TokenContext } from '@/utils/TokenProvider';
import { LocaleCodeType } from '@/types/locale'; import { LocaleCodeType } from '@/types/locale';
import { logError } from '@/utils/errorHandler';
type Props = { type Props = {
projectId: string; projectId: string;
@@ -61,13 +62,13 @@ export default function RunsPage({ projectId, locale, messages }: Props) {
try { try {
const data = await fetchRuns(context.token.access_token, Number(projectId)); const data = await fetchRuns(context.token.access_token, Number(projectId));
setRuns(data); setRuns(data);
} catch (error: any) { } catch (error: unknown) {
console.error('Error in effect:', error.message); logError('Error fetching runs', error);
} }
} }
fetchDataEffect(); fetchDataEffect();
}, [context]); }, [context, projectId]);
const onSubmit = async (name: string, description: string) => { const onSubmit = async (name: string, description: string) => {
if (editingRun && editingRun.createdAt) { if (editingRun && editingRun.createdAt) {

View File

@@ -13,10 +13,10 @@ import {
DropdownItem, DropdownItem,
SortDescriptor, SortDescriptor,
} from '@heroui/react'; } from '@heroui/react';
import { Link, NextUiLinkClasses } from '@/src/i18n/routing';
import { MoreVertical } from 'lucide-react'; import { MoreVertical } from 'lucide-react';
import { RunsMessages, RunType } from '@/types/run';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { Link, NextUiLinkClasses } from '@/src/i18n/routing';
import { RunsMessages, RunType } from '@/types/run';
import { LocaleCodeType } from '@/types/locale'; import { LocaleCodeType } from '@/types/locale';
type Props = { type Props = {
@@ -70,7 +70,7 @@ export default function RunsTable({ projectId, isDisabled, runs, onDeleteRun, me
switch (columnKey) { switch (columnKey) {
case 'id': case 'id':
return <span>{cellValue as number}</span>; return <span>{cellValue as number}</span>;
case 'name': case 'name': {
const maxLength = 30; const maxLength = 30;
const truncatedDescription = truncateText(run.description, maxLength); const truncatedDescription = truncateText(run.description, maxLength);
return ( return (
@@ -83,6 +83,7 @@ export default function RunsTable({ projectId, isDisabled, runs, onDeleteRun, me
</div> </div>
</div> </div>
); );
}
case 'updatedAt': case 'updatedAt':
return <span>{dayjs(cellValue as string).format('YYYY/MM/DD HH:mm')}</span>; return <span>{dayjs(cellValue as string).format('YYYY/MM/DD HH:mm')}</span>;
case 'actions': case 'actions':

View File

@@ -55,6 +55,7 @@ import { useFormGuard } from '@/utils/formGuard';
import { PriorityMessages } from '@/types/priority'; import { PriorityMessages } from '@/types/priority';
import { RunStatusMessages, TestRunCaseStatusMessages } from '@/types/status'; import { RunStatusMessages, TestRunCaseStatusMessages } from '@/types/status';
import { TestTypeMessages } from '@/types/testType'; import { TestTypeMessages } from '@/types/testType';
import { logError } from '@/utils/errorHandler';
const defaultTestRun = { const defaultTestRun = {
id: 0, id: 0,
@@ -132,12 +133,13 @@ export default function RunEditor({
setFolders(foldersData); setFolders(foldersData);
setSelectedFolder(foldersData[0]); setSelectedFolder(foldersData[0]);
initTestCases(); initTestCases();
} catch (error: any) { } catch (error: unknown) {
console.error('Error in effect:', error.message); logError('Error fetching run data', error);
} }
} }
fetchDataEffect(); fetchDataEffect();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [tokenContext]); }, [tokenContext]);
useEffect(() => { useEffect(() => {
@@ -146,8 +148,8 @@ export default function RunEditor({
try { try {
const filteredData = testCases.filter((testCase) => testCase.folderId === selectedFolder.id); const filteredData = testCases.filter((testCase) => testCase.folderId === selectedFolder.id);
setFilteredTestCases(filteredData); setFilteredTestCases(filteredData);
} catch (error: any) { } catch (error: unknown) {
console.error('Error fetching cases data:', error.message); logError('Error filtering test cases', error);
} }
} }
} }

View File

@@ -1,4 +1,3 @@
import React from 'react';
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import dynamic from 'next/dynamic'; import dynamic from 'next/dynamic';
import { testRunCaseStatus } from '@/config/selection'; import { testRunCaseStatus } from '@/config/selection';
@@ -34,7 +33,7 @@ export default function RunProgressDounut({ statusCounts, testRunCaseStatusMessa
const colors = testRunCaseStatus.map((entry) => entry.chartColor); const colors = testRunCaseStatus.map((entry) => entry.chartColor);
const legend = { const legend = {
labels: { labels: {
colors: testRunCaseStatus.map((entry) => { colors: testRunCaseStatus.map(() => {
if (theme === 'light') { if (theme === 'light') {
return 'black'; return 'black';
} else { } else {
@@ -52,7 +51,7 @@ export default function RunProgressDounut({ statusCounts, testRunCaseStatusMessa
}; };
updateChartDate(); updateChartDate();
}, [statusCounts, theme]); }, [statusCounts, testRunCaseStatusMessages, theme]);
return <Chart options={chartData.options} series={chartData.series} type="donut" width={'100%'} height={'100%'} />; return <Chart options={chartData.options} series={chartData.series} type="donut" width={'100%'} height={'100%'} />;
} }

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