refactor: priority messages duplication

This commit is contained in:
Takeshi Kimata
2024-07-21 13:59:49 +09:00
parent 63df563b87
commit 74bb379c1a
16 changed files with 84 additions and 90 deletions

View File

@@ -1,3 +1,5 @@
import { PriorityType } from '@/types/priority';
const roles = [{ uid: 'administrator' }, { uid: 'user' }]; const roles = [{ uid: 'administrator' }, { uid: 'user' }];
const memberRoles = [{ uid: 'manager' }, { uid: 'developer' }, { uid: 'reporter' }]; const memberRoles = [{ uid: 'manager' }, { uid: 'developer' }, { uid: 'reporter' }];
@@ -9,7 +11,7 @@ const locales = [
{ code: 'ja', name: '日本語' }, { code: 'ja', name: '日本語' },
]; ];
const priorities = [ const priorities: PriorityType[] = [
{ uid: 'critical', color: '#bb3e03', chartColor: '#bb3e03' }, { uid: 'critical', color: '#bb3e03', chartColor: '#bb3e03' },
{ uid: 'high', color: '#ca6702', chartColor: '#ca6702' }, { uid: 'high', color: '#ca6702', chartColor: '#ca6702' },
{ uid: 'medium', color: '#ee9b00', chartColor: '#ee9b00' }, { uid: 'medium', color: '#ee9b00', chartColor: '#ee9b00' },

View File

@@ -133,11 +133,7 @@
"destructive": "Destructive", "destructive": "Destructive",
"regression": "Regression", "regression": "Regression",
"automated": "Automated", "automated": "Automated",
"manual": "Manual", "manual": "Manual"
"critical": "Critical",
"high": "High",
"medium": "Medium",
"low": "Low"
}, },
"Folders": { "Folders": {
"folder": "Folder", "folder": "Folder",
@@ -166,10 +162,6 @@
"are_you_sure": "Are you sure you want to delete test cases?", "are_you_sure": "Are you sure you want to delete test cases?",
"new_test_case": "New Test Case", "new_test_case": "New Test Case",
"status": "Status", "status": "Status",
"critical": "Critical",
"high": "High",
"medium": "Medium",
"low": "Low",
"no_cases_found": "No test cases found", "no_cases_found": "No test cases found",
"case_title": "Test Case Title", "case_title": "Test Case Title",
"case_description": "Test Case Description", "case_description": "Test Case Description",
@@ -186,10 +178,6 @@
"description": "Description", "description": "Description",
"test_case_description": "Test case description", "test_case_description": "Test case description",
"priority": "Priority", "priority": "Priority",
"critical": "Critical",
"high": "High",
"medium": "Medium",
"low": "Low",
"type": "Type", "type": "Type",
"other": "Other", "other": "Other",
"security": "Security", "security": "Security",
@@ -264,10 +252,6 @@
"priority": "Priority", "priority": "Priority",
"status": "Status", "status": "Status",
"actions": "Actions", "actions": "Actions",
"critical": "Critical",
"high": "High",
"medium": "Medium",
"low": "Low",
"untested": "Untested", "untested": "Untested",
"passed": "Passed", "passed": "Passed",
"failed": "Failed", "failed": "Failed",

View File

@@ -134,11 +134,7 @@
"destructive": "破壊", "destructive": "破壊",
"regression": "回帰", "regression": "回帰",
"automated": "自動", "automated": "自動",
"manual": "手動", "manual": "手動"
"critical": "致",
"high": "高",
"medium": "中",
"low": "低"
}, },
"Folders": { "Folders": {
"folder": "フォルダー", "folder": "フォルダー",
@@ -167,10 +163,6 @@
"are_you_sure": "テストケースを削除してもよろしいですか?", "are_you_sure": "テストケースを削除してもよろしいですか?",
"new_test_case": "新規テストケース", "new_test_case": "新規テストケース",
"status": "ステータス", "status": "ステータス",
"critical": "致",
"high": "高",
"medium": "中",
"low": "低",
"no_cases_found": "テストケースがありません", "no_cases_found": "テストケースがありません",
"case_title": "テストケースタイトル", "case_title": "テストケースタイトル",
"case_description": "テストケース詳細", "case_description": "テストケース詳細",
@@ -187,10 +179,6 @@
"description": "詳細", "description": "詳細",
"test_case_description": "テストケース詳細", "test_case_description": "テストケース詳細",
"priority": "優先度", "priority": "優先度",
"critical": "致",
"high": "高",
"medium": "中",
"low": "低",
"type": "タイプ", "type": "タイプ",
"other": "その他", "other": "その他",
"security": "セキュリティ", "security": "セキュリティ",
@@ -265,10 +253,6 @@
"priority": "優先度", "priority": "優先度",
"status": "ステータス", "status": "ステータス",
"actions": "アクション", "actions": "アクション",
"critical": "致",
"high": "高",
"medium": "中",
"low": "低",
"untested": "未実行", "untested": "未実行",
"passed": "成功", "passed": "成功",
"failed": "失敗", "failed": "失敗",

View File

@@ -6,15 +6,17 @@ import { fetchCases, createCase, deleteCases } from '@/utils/caseControl';
import { CaseType, CasesMessages } from '@/types/case'; import { CaseType, CasesMessages } from '@/types/case';
import DeleteConfirmDialog from '@/components/DeleteConfirmDialog'; import DeleteConfirmDialog from '@/components/DeleteConfirmDialog';
import CaseDialog from './CaseDialog'; import CaseDialog from './CaseDialog';
import { PriorityMessages } from '@/types/priority';
type Props = { type Props = {
projectId: string; projectId: string;
folderId: string; folderId: string;
messages: CasesMessages; messages: CasesMessages;
priorityMessages: PriorityMessages;
locale: string; locale: string;
}; };
export default function CasesPane({ projectId, folderId, messages, locale }: Props) { export default function CasesPane({ projectId, folderId, messages, priorityMessages, locale }: Props) {
const [cases, setCases] = useState<CaseType[]>([]); const [cases, setCases] = useState<CaseType[]>([]);
const context = useContext(TokenContext); const context = useContext(TokenContext);
const [isCaseDialogOpen, setIsCaseDialogOpen] = useState(false); const [isCaseDialogOpen, setIsCaseDialogOpen] = useState(false);
@@ -81,6 +83,7 @@ export default function CasesPane({ projectId, folderId, messages, locale }: Pro
onDeleteCase={onDeleteCase} onDeleteCase={onDeleteCase}
onDeleteCases={onDeleteCases} onDeleteCases={onDeleteCases}
messages={messages} messages={messages}
priorityMessages={priorityMessages}
locale={locale} locale={locale}
/> />

View File

@@ -17,7 +17,8 @@ import {
import { Link, NextUiLinkClasses } from '@/src/navigation'; import { Link, NextUiLinkClasses } from '@/src/navigation';
import { Plus, MoreVertical, Trash, Circle } from 'lucide-react'; import { Plus, MoreVertical, Trash, Circle } from 'lucide-react';
import { CaseType, CasesMessages } from '@/types/case'; import { CaseType, CasesMessages } from '@/types/case';
import { priorities } from '@/config/selection'; import { PriorityMessages } from '@/types/priority';
import TestCasePriority from '@/components/TestCasePriority';
type Props = { type Props = {
projectId: string; projectId: string;
@@ -27,6 +28,7 @@ type Props = {
onDeleteCase: (caseId: number) => void; onDeleteCase: (caseId: number) => void;
onDeleteCases: (caseIds: number[]) => void; onDeleteCases: (caseIds: number[]) => void;
messages: CasesMessages; messages: CasesMessages;
priorityMessages: PriorityMessages;
locale: string; locale: string;
}; };
@@ -38,6 +40,7 @@ export default function TestCaseTable({
onDeleteCase, onDeleteCase,
onDeleteCases, onDeleteCases,
messages, messages,
priorityMessages,
locale, locale,
}: Props) { }: Props) {
const headerColumns = [ const headerColumns = [
@@ -89,12 +92,7 @@ export default function TestCaseTable({
</Button> </Button>
); );
case 'priority': case 'priority':
return ( return <TestCasePriority priorityValue={cellValue} priorityMessages={priorityMessages} />;
<div className="flex items-center">
<Circle size={8} color={priorities[cellValue].color} fill={priorities[cellValue].color} />
<div className="ms-3">{messages[priorities[cellValue].uid]}</div>
</div>
);
case 'actions': case 'actions':
return ( return (
<Dropdown> <Dropdown>

View File

@@ -6,12 +6,13 @@ import { Save, Plus, ArrowLeft, Circle } from 'lucide-react';
import { priorities, testTypes, templates } from '@/config/selection'; import { priorities, testTypes, templates } from '@/config/selection';
import CaseStepsEditor from './CaseStepsEditor'; import CaseStepsEditor from './CaseStepsEditor';
import CaseAttachmentsEditor from './CaseAttachmentsEditor'; import CaseAttachmentsEditor from './CaseAttachmentsEditor';
import { CaseType, AttachmentType, CaseMessages, StepType } from '@/types/case';
import { fetchCase, updateCase } from '@/utils/caseControl'; 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 { 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 { PriorityMessages } from '@/types/priority';
const defaultTestCase = { const defaultTestCase = {
id: 0, id: 0,
@@ -36,10 +37,11 @@ type Props = {
folderId: string; folderId: string;
caseId: string; caseId: string;
messages: CaseMessages; messages: CaseMessages;
priorityMessages: PriorityMessages;
locale: string; locale: string;
}; };
export default function CaseEditor({ projectId, folderId, caseId, messages, locale }: Props) { export default function CaseEditor({ projectId, folderId, caseId, messages, priorityMessages, locale }: Props) {
const context = useContext(TokenContext); const context = useContext(TokenContext);
const [testCase, setTestCase] = useState<CaseType>(defaultTestCase); const [testCase, setTestCase] = useState<CaseType>(defaultTestCase);
const [isTitleInvalid, setIsTitleInvalid] = useState<boolean>(false); const [isTitleInvalid, setIsTitleInvalid] = useState<boolean>(false);
@@ -262,7 +264,7 @@ export default function CaseEditor({ projectId, folderId, caseId, messages, loca
> >
{priorities.map((priority, index) => ( {priorities.map((priority, index) => (
<SelectItem key={priority.uid} value={index}> <SelectItem key={priority.uid} value={index}>
{messages[priority.uid]} {priorityMessages[priority.uid]}
</SelectItem> </SelectItem>
))} ))}
</Select> </Select>

View File

@@ -1,3 +1,4 @@
import { PriorityMessages } from '@/types/priority';
import CaseEditor from './CaseEditor'; import CaseEditor from './CaseEditor';
import { useTranslations } from 'next-intl'; import { useTranslations } from 'next-intl';
@@ -22,10 +23,6 @@ export default function Page({
description: t('description'), description: t('description'),
testCaseDescription: t('test_case_description'), testCaseDescription: t('test_case_description'),
priority: t('priority'), priority: t('priority'),
critical: t('critical'),
high: t('high'),
medium: t('medium'),
low: t('low'),
type: t('type'), type: t('type'),
other: t('other'), other: t('other'),
security: t('security'), security: t('security'),
@@ -61,12 +58,21 @@ export default function Page({
areYouSureLeave: t('are_you_sure_leave'), areYouSureLeave: t('are_you_sure_leave'),
}; };
const priorityTranslation = useTranslations('Priority');
const priorityMessages: PriorityMessages = {
critical: priorityTranslation('critical'),
high: priorityTranslation('high'),
medium: priorityTranslation('medium'),
low: priorityTranslation('low'),
};
return ( return (
<CaseEditor <CaseEditor
projectId={params.projectId} projectId={params.projectId}
folderId={params.folderId} folderId={params.folderId}
caseId={params.caseId} caseId={params.caseId}
messages={messages} messages={messages}
priorityMessages={priorityMessages}
locale={params.locale} locale={params.locale}
/> />
); );

View File

@@ -1,3 +1,4 @@
import { PriorityMessages } from '@/types/priority';
import CasesPane from './CasesPane'; import CasesPane from './CasesPane';
import { useTranslations } from 'next-intl'; import { useTranslations } from 'next-intl';
@@ -15,10 +16,6 @@ export default function Page({ params }: { params: { projectId: string; folderId
areYouSure: t('are_you_sure'), areYouSure: t('are_you_sure'),
newTestCase: t('new_test_case'), newTestCase: t('new_test_case'),
status: t('status'), status: t('status'),
critical: t('critical'),
high: t('high'),
medium: t('medium'),
low: t('low'),
noCasesFound: t('no_cases_found'), noCasesFound: t('no_cases_found'),
caseTitle: t('case_title'), caseTitle: t('case_title'),
caseDescription: t('case_description'), caseDescription: t('case_description'),
@@ -26,9 +23,23 @@ export default function Page({ params }: { params: { projectId: string; folderId
pleaseEnter: t('please_enter'), pleaseEnter: t('please_enter'),
}; };
const priorityTranslation = useTranslations('Priority');
const priorityMessages: PriorityMessages = {
critical: priorityTranslation('critical'),
high: priorityTranslation('high'),
medium: priorityTranslation('medium'),
low: priorityTranslation('low'),
};
return ( return (
<> <>
<CasesPane projectId={params.projectId} folderId={params.folderId} locale={params.locale} messages={messages} /> <CasesPane
projectId={params.projectId}
folderId={params.folderId}
locale={params.locale}
messages={messages}
priorityMessages={priorityMessages}
/>
</> </>
); );
} }

View File

@@ -13,6 +13,7 @@ import TestPriorityChart from './TestPriorityDonutChart';
import TestProgressBarChart from './TestProgressColumnChart'; import TestProgressBarChart from './TestProgressColumnChart';
import Config from '@/config/config'; import Config from '@/config/config';
import { useTheme } from 'next-themes'; import { useTheme } from 'next-themes';
import { PriorityMessages } from '@/types/priority';
const apiServer = Config.apiServer; const apiServer = Config.apiServer;
async function fetchProject(jwt: string, projectId: number) { async function fetchProject(jwt: string, projectId: number) {
@@ -41,9 +42,10 @@ async function fetchProject(jwt: string, projectId: number) {
type Props = { type Props = {
projectId: string; projectId: string;
messages: HomeMessages; messages: HomeMessages;
priorityMessages: PriorityMessages;
}; };
export function ProjectHome({ projectId, messages }: Props) { export function ProjectHome({ projectId, messages, priorityMessages }: Props) {
const context = useContext(TokenContext); const context = useContext(TokenContext);
const { theme, setTheme } = useTheme(); const { theme, setTheme } = useTheme();
const [project, setProject] = useState({ const [project, setProject] = useState({
@@ -134,7 +136,7 @@ export function ProjectHome({ projectId, messages }: Props) {
</div> </div>
<div style={{ width: '30rem', height: '18rem' }}> <div style={{ width: '30rem', height: '18rem' }}>
<h3>{messages.byPriority}</h3> <h3>{messages.byPriority}</h3>
<TestPriorityChart priorityCounts={priorityCounts} messages={messages} theme={theme} /> <TestPriorityChart priorityCounts={priorityCounts} priorityMessages={priorityMessages} theme={theme} />
</div> </div>
</div> </div>
</div> </div>

View File

@@ -3,16 +3,16 @@ 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';
import { CasePriorityCountType } from '@/types/case'; import { CasePriorityCountType } from '@/types/case';
import { HomeMessages } from './page'; import { PriorityMessages } from '@/types/priority';
const Chart = dynamic(() => import('react-apexcharts'), { ssr: false }); const Chart = dynamic(() => import('react-apexcharts'), { ssr: false });
type Props = { type Props = {
priorityCounts: CasePriorityCountType[]; priorityCounts: CasePriorityCountType[];
messages: HomeMessages; priorityMessages: PriorityMessages;
theme: string; theme: string;
}; };
export default function TestPriorityDonutChart({ priorityCounts, messages, theme }: Props) { export default function TestPriorityDonutChart({ priorityCounts, priorityMessages, theme }: Props) {
const [chartData, setChartData] = useState({ const [chartData, setChartData] = useState({
series: [], series: [],
options: { options: {
@@ -29,7 +29,7 @@ export default function TestPriorityDonutChart({ priorityCounts, messages, theme
return found ? found.count : 0; return found ? found.count : 0;
}); });
const labels = priorities.map((entry) => messages[entry.uid]); const labels = priorities.map((entry) => priorityMessages[entry.uid]);
const colors = priorities.map((entry) => entry.chartColor); const colors = priorities.map((entry) => entry.chartColor);
const legend = { const legend = {
labels: { labels: {

View File

@@ -1,5 +1,6 @@
import { ProjectHome } from './ProjectHome'; import { ProjectHome } from './ProjectHome';
import { useTranslations } from 'next-intl'; import { useTranslations } from 'next-intl';
import { PriorityMessages } from '@/types/priority';
export type HomeMessages = { export type HomeMessages = {
folders: string; folders: string;
@@ -28,10 +29,6 @@ export type HomeMessages = {
regression: string; regression: string;
automated: string; automated: string;
manual: string; manual: string;
critical: string;
high: string;
medium: string;
low: string;
}; };
export default function Page({ params }: { params: { projectId: string } }) { export default function Page({ params }: { params: { projectId: string } }) {
@@ -62,14 +59,19 @@ export default function Page({ params }: { params: { projectId: string } }) {
regression: t('regression'), regression: t('regression'),
automated: t('automated'), automated: t('automated'),
manual: t('manual'), manual: t('manual'),
critical: t('critical'),
high: t('high'),
medium: t('medium'),
low: t('low'),
}; };
const pt = useTranslations('Priority');
const priorityMessages: PriorityMessages = {
critical: pt('critical'),
high: pt('high'),
medium: pt('medium'),
low: pt('low'),
};
return ( return (
<> <>
<ProjectHome projectId={params.projectId} messages={messages} /> <ProjectHome projectId={params.projectId} messages={messages} priorityMessages={priorityMessages} />
</> </>
); );
} }

View File

@@ -1,9 +1,9 @@
import { Button, Modal, ModalContent, ModalHeader, ModalBody, ModalFooter } from '@nextui-org/react'; import { Button, Modal, ModalContent, ModalHeader, ModalBody, ModalFooter } from '@nextui-org/react';
import { testTypes, templates } from '@/config/selection'; import { testTypes, templates } from '@/config/selection';
import TestCasePriority from '@/components/TestCasePriority';
import { RunMessages } from '@/types/run'; import { RunMessages } from '@/types/run';
import { CaseType } from '@/types/case'; import { CaseType } from '@/types/case';
import { PriorityMessages } from '@/types/priority'; import { PriorityMessages } from '@/types/priority';
import TestCasePriority from '@/components/TestCasePriority';
type Props = { type Props = {
isOpen: boolean; isOpen: boolean;

View File

@@ -26,11 +26,12 @@ import {
CircleSlash2, CircleSlash2,
} from 'lucide-react'; } from 'lucide-react';
import { NextUiLinkClasses } from '@/src/navigation'; import { NextUiLinkClasses } from '@/src/navigation';
import { priorities, testRunCaseStatus } from '@/config/selection'; import { testRunCaseStatus } from '@/config/selection';
import { CaseType } from '@/types/case'; import { CaseType } from '@/types/case';
import { RunMessages } from '@/types/run'; import { RunMessages } from '@/types/run';
import TestCaseDetailDialog from './TestCaseDetailDialog'; import TestCaseDetailDialog from './TestCaseDetailDialog';
import { PriorityMessages } from '@/types/priority'; import { PriorityMessages } from '@/types/priority';
import TestCasePriority from '@/components/TestCasePriority';
type Props = { type Props = {
cases: CaseType[]; cases: CaseType[];
@@ -95,7 +96,6 @@ export default function TestCaseSelector({
}, [sortDescriptor, cases]); }, [sortDescriptor, cases]);
const notIncludedCaseClass = 'text-neutral-200 dark:text-neutral-600'; const notIncludedCaseClass = 'text-neutral-200 dark:text-neutral-600';
const chipBaseClass = 'flex items-center text-default-600';
const renderStatusIcon = (uid: string) => { const renderStatusIcon = (uid: string) => {
if (uid === 'untested') { if (uid === 'untested') {
@@ -142,13 +142,8 @@ export default function TestCaseSelector({
); );
case 'priority': case 'priority':
return ( return (
<div className={isIncluded ? chipBaseClass : chipBaseClass + notIncludedCaseClass}> <div className={isIncluded ? '' : notIncludedCaseClass}>
<Circle <TestCasePriority priorityValue={cellValue} priorityMessages={priorityMessages} />
size={8}
color={isIncluded ? priorities[cellValue].color : '#d4d4d8'}
fill={isIncluded ? priorities[cellValue].color : '#d4d4d8'}
/>
<div className="ms-3">{messages[priorities[cellValue].uid]}</div>
</div> </div>
); );
case 'runStatus': case 'runStatus':

View File

@@ -55,12 +55,12 @@ export default function Page({ params }: { params: { projectId: string; runId: s
close: t('close'), close: t('close'),
}; };
const priorityTranslation = useTranslations('Priority'); const pt = useTranslations('Priority');
const priorityMessages: PriorityMessages = { const priorityMessages: PriorityMessages = {
critical: priorityTranslation('critical'), critical: pt('critical'),
high: priorityTranslation('high'), high: pt('high'),
medium: priorityTranslation('medium'), medium: pt('medium'),
low: priorityTranslation('low'), low: pt('low'),
}; };
return ( return (

View File

@@ -1,7 +1,16 @@
type PriorityUidType = 'critical' | 'high' | 'medium' | 'low';
type PriorityType = {
uid: PriorityUidType;
color: string;
chartColor: string;
};
type PriorityMessages = { type PriorityMessages = {
critical: string; critical: string;
high: string; high: string;
medium: string; medium: string;
low: string; low: string;
}; };
export type { PriorityMessages };
export type { PriorityUidType, PriorityType, PriorityMessages };

View File

@@ -68,10 +68,6 @@ type RunMessages = {
priority: string; priority: string;
status: string; status: string;
actions: string; actions: string;
critical: string;
high: string;
medium: string;
low: string;
untested: string; untested: string;
passed: string; passed: string;
failed: string; failed: string;