diff --git a/backend/config/swagger.js b/backend/config/swagger.js index 5b61eea..8e7183a 100644 --- a/backend/config/swagger.js +++ b/backend/config/swagger.js @@ -133,10 +133,17 @@ const options = { type: 'string', description: 'Project description', }, - state: { + status: { type: 'string', - enum: ['active', 'archived', 'completed'], - description: 'Project state', + enum: [ + 'not_started', + 'planned', + 'in_progress', + 'waiting', + 'done', + 'cancelled', + ], + description: 'Project status', }, priority: { type: 'string', diff --git a/backend/docs/swagger/projects.js b/backend/docs/swagger/projects.js index d42ce98..4b8dcf7 100644 --- a/backend/docs/swagger/projects.js +++ b/backend/docs/swagger/projects.js @@ -9,11 +9,11 @@ * - BearerAuth: [] * parameters: * - in: query - * name: state + * name: status * schema: * type: string - * enum: [planned, in_progress, blocked, completed, archived, all] - * description: Filter by project state + * enum: [not_started, planned, in_progress, waiting, done, cancelled, all, not_completed] + * description: Filter by project status * - in: query * name: area_id * schema: @@ -62,10 +62,10 @@ * type: string * enum: [low, medium, high] * description: Project priority - * state: + * status: * type: string - * enum: [idea, planned, in_progress, blocked, completed, archived] - * description: Project state + * enum: [not_started, planned, in_progress, waiting, done, cancelled] + * description: Project status * area_id: * type: integer * description: Associated area ID @@ -127,10 +127,10 @@ * type: string * enum: [low, medium, high] * description: Project priority - * state: + * status: * type: string - * enum: [idea, planned, in_progress, blocked, completed, archived] - * description: Project state + * enum: [not_started, planned, in_progress, waiting, done, cancelled] + * description: Project status * area_id: * type: integer * description: Associated area ID diff --git a/backend/migrations/20251228000001-update-project-state-enum.js b/backend/migrations/20251228000001-update-project-state-enum.js new file mode 100644 index 0000000..7dda077 --- /dev/null +++ b/backend/migrations/20251228000001-update-project-state-enum.js @@ -0,0 +1,182 @@ +'use strict'; + +/** + * Migration to update project state ENUM to use task status values. + * This aligns project states with task statuses for consistency. + * + * Old values: 'idea', 'planned', 'in_progress', 'blocked', 'completed' + * New values: 'not_started', 'in_progress', 'done', 'waiting', 'cancelled', 'planned' + * + * Mapping: + * - 'idea' → 'not_started' + * - 'planned' → 'planned' + * - 'in_progress' → 'in_progress' + * - 'blocked' → 'waiting' + * - 'completed' → 'done' + */ +module.exports = { + async up(queryInterface, Sequelize) { + // For SQLite: recreate the column with new values + // For PostgreSQL/MySQL: alter the enum type + + const dialect = queryInterface.sequelize.getDialect(); + + if (dialect === 'sqlite') { + // SQLite doesn't support ENUM, it's stored as TEXT + // Just update the data values + await queryInterface.sequelize.query( + `UPDATE projects SET state = 'not_started' WHERE state = 'idea'` + ); + await queryInterface.sequelize.query( + `UPDATE projects SET state = 'waiting' WHERE state = 'blocked'` + ); + await queryInterface.sequelize.query( + `UPDATE projects SET state = 'done' WHERE state = 'completed'` + ); + } else if (dialect === 'postgres') { + // PostgreSQL: Create new enum type, migrate data, swap types + await queryInterface.sequelize.query(` + CREATE TYPE "enum_projects_state_new" AS ENUM( + 'not_started', 'in_progress', 'done', 'waiting', 'cancelled', 'planned' + ); + `); + + // Update values before changing type + await queryInterface.sequelize.query( + `UPDATE projects SET state = 'not_started' WHERE state = 'idea'` + ); + await queryInterface.sequelize.query( + `UPDATE projects SET state = 'waiting' WHERE state = 'blocked'` + ); + await queryInterface.sequelize.query( + `UPDATE projects SET state = 'done' WHERE state = 'completed'` + ); + + // Change column type + await queryInterface.sequelize.query(` + ALTER TABLE projects + ALTER COLUMN state TYPE "enum_projects_state_new" + USING state::text::"enum_projects_state_new"; + `); + + // Drop old enum and rename new one + await queryInterface.sequelize.query( + `DROP TYPE IF EXISTS "enum_projects_state";` + ); + await queryInterface.sequelize.query( + `ALTER TYPE "enum_projects_state_new" RENAME TO "enum_projects_state";` + ); + + // Update default value + await queryInterface.sequelize.query(` + ALTER TABLE projects ALTER COLUMN state SET DEFAULT 'not_started'; + `); + } else if (dialect === 'mysql' || dialect === 'mariadb') { + // MySQL: Alter column directly + await queryInterface.sequelize.query( + `UPDATE projects SET state = 'not_started' WHERE state = 'idea'` + ); + await queryInterface.sequelize.query( + `UPDATE projects SET state = 'waiting' WHERE state = 'blocked'` + ); + await queryInterface.sequelize.query( + `UPDATE projects SET state = 'done' WHERE state = 'completed'` + ); + + await queryInterface.changeColumn('projects', 'state', { + type: Sequelize.ENUM( + 'not_started', + 'in_progress', + 'done', + 'waiting', + 'cancelled', + 'planned' + ), + allowNull: false, + defaultValue: 'not_started', + }); + } + }, + + async down(queryInterface, Sequelize) { + const dialect = queryInterface.sequelize.getDialect(); + + if (dialect === 'sqlite') { + // Reverse the data mapping + await queryInterface.sequelize.query( + `UPDATE projects SET state = 'idea' WHERE state = 'not_started'` + ); + await queryInterface.sequelize.query( + `UPDATE projects SET state = 'blocked' WHERE state = 'waiting'` + ); + await queryInterface.sequelize.query( + `UPDATE projects SET state = 'completed' WHERE state = 'done'` + ); + await queryInterface.sequelize.query( + `UPDATE projects SET state = 'idea' WHERE state = 'cancelled'` + ); + } else if (dialect === 'postgres') { + await queryInterface.sequelize.query(` + CREATE TYPE "enum_projects_state_old" AS ENUM( + 'idea', 'planned', 'in_progress', 'blocked', 'completed' + ); + `); + + // Reverse data mapping + await queryInterface.sequelize.query( + `UPDATE projects SET state = 'idea' WHERE state = 'not_started'` + ); + await queryInterface.sequelize.query( + `UPDATE projects SET state = 'blocked' WHERE state = 'waiting'` + ); + await queryInterface.sequelize.query( + `UPDATE projects SET state = 'completed' WHERE state = 'done'` + ); + await queryInterface.sequelize.query( + `UPDATE projects SET state = 'idea' WHERE state = 'cancelled'` + ); + + await queryInterface.sequelize.query(` + ALTER TABLE projects + ALTER COLUMN state TYPE "enum_projects_state_old" + USING state::text::"enum_projects_state_old"; + `); + + await queryInterface.sequelize.query( + `DROP TYPE IF EXISTS "enum_projects_state";` + ); + await queryInterface.sequelize.query( + `ALTER TYPE "enum_projects_state_old" RENAME TO "enum_projects_state";` + ); + + await queryInterface.sequelize.query(` + ALTER TABLE projects ALTER COLUMN state SET DEFAULT 'idea'; + `); + } else if (dialect === 'mysql' || dialect === 'mariadb') { + await queryInterface.sequelize.query( + `UPDATE projects SET state = 'idea' WHERE state = 'not_started'` + ); + await queryInterface.sequelize.query( + `UPDATE projects SET state = 'blocked' WHERE state = 'waiting'` + ); + await queryInterface.sequelize.query( + `UPDATE projects SET state = 'completed' WHERE state = 'done'` + ); + await queryInterface.sequelize.query( + `UPDATE projects SET state = 'idea' WHERE state = 'cancelled'` + ); + + await queryInterface.changeColumn('projects', 'state', { + type: Sequelize.ENUM( + 'idea', + 'planned', + 'in_progress', + 'blocked', + 'completed' + ), + allowNull: false, + defaultValue: 'idea', + }); + } + }, +}; diff --git a/backend/migrations/20251228000002-rename-project-state-to-status.js b/backend/migrations/20251228000002-rename-project-state-to-status.js new file mode 100644 index 0000000..cd6d2fd --- /dev/null +++ b/backend/migrations/20251228000002-rename-project-state-to-status.js @@ -0,0 +1,14 @@ +'use strict'; + +/** + * Migration to rename project 'state' column to 'status' for consistency. + */ +module.exports = { + async up(queryInterface, Sequelize) { + await queryInterface.renameColumn('projects', 'state', 'status'); + }, + + async down(queryInterface, Sequelize) { + await queryInterface.renameColumn('projects', 'status', 'state'); + }, +}; diff --git a/backend/models/project.js b/backend/models/project.js index 3b5d4c7..52fde35 100644 --- a/backend/models/project.js +++ b/backend/models/project.js @@ -71,16 +71,17 @@ module.exports = (sequelize) => { allowNull: true, defaultValue: 'created_at:desc', }, - state: { + status: { type: DataTypes.ENUM( - 'idea', - 'planned', + 'not_started', 'in_progress', - 'blocked', - 'completed' + 'done', + 'waiting', + 'cancelled', + 'planned' ), allowNull: false, - defaultValue: 'idea', + defaultValue: 'not_started', }, }, { diff --git a/backend/routes/projects.js b/backend/routes/projects.js index c1f8b93..f96c4c7 100644 --- a/backend/routes/projects.js +++ b/backend/routes/projects.js @@ -158,7 +158,10 @@ router.post( router.get('/projects', async (req, res) => { try { - const { state, active, pin_to_sidebar, area_id, area } = req.query; + const { status, state, active, pin_to_sidebar, area_id, area } = + req.query; + // Support both 'status' (new) and 'state' (legacy) query params + const statusFilter = status || state; // Base: owned or shared projects const ownedOrShared = @@ -168,22 +171,22 @@ router.get('/projects', async (req, res) => { ); let whereClause = ownedOrShared; - // Filter by state (new primary filter) - if (state && state !== 'all') { - if (Array.isArray(state)) { - whereClause.state = { [Op.in]: state }; + // Filter by status + if (statusFilter && statusFilter !== 'all') { + if (Array.isArray(statusFilter)) { + whereClause.status = { [Op.in]: statusFilter }; } else { - whereClause.state = state; + whereClause.status = statusFilter; } } - // Legacy support for active filter - map to states + // Legacy support for active filter - map to statuses if (active === 'true') { - whereClause.state = { - [Op.in]: ['planned', 'in_progress', 'blocked'], + whereClause.status = { + [Op.in]: ['planned', 'in_progress', 'waiting'], }; } else if (active === 'false') { - whereClause.state = { [Op.in]: ['idea', 'completed'] }; + whereClause.status = { [Op.in]: ['not_started', 'done'] }; } // Filter by pinned status @@ -490,7 +493,8 @@ router.post('/project', async (req, res) => { priority, due_date_at, image_url, - state, + status, + state, // Legacy support tags, Tags, } = req.body; @@ -514,7 +518,7 @@ router.post('/project', async (req, res) => { priority: priority || null, due_date_at: due_date_at || null, image_url: image_url || null, - state: state || 'idea', + status: status || state || 'not_started', user_id: req.authUserId, }; @@ -578,7 +582,8 @@ router.patch( priority, due_date_at, image_url, - state, + status, + state, // Legacy support tags, Tags, } = req.body; @@ -595,7 +600,9 @@ router.patch( if (priority !== undefined) updateData.priority = priority; if (due_date_at !== undefined) updateData.due_date_at = due_date_at; if (image_url !== undefined) updateData.image_url = image_url; - if (state !== undefined) updateData.state = state; + // Support both status (new) and state (legacy) + if (status !== undefined) updateData.status = status; + else if (state !== undefined) updateData.status = state; await project.update(updateData); await updateProjectTags(project, tagsData, req.authUserId); diff --git a/backend/routes/search.js b/backend/routes/search.js index b1e532d..80e4297 100644 --- a/backend/routes/search.js +++ b/backend/routes/search.js @@ -432,7 +432,7 @@ router.get('/', async (req, res) => { name: project.name, description: project.description, priority: project.priority, - status: project.state, + status: project.status, })) ); } diff --git a/backend/routes/tasks/queries/query-builders.js b/backend/routes/tasks/queries/query-builders.js index d6bca24..3af7d21 100644 --- a/backend/routes/tasks/queries/query-builders.js +++ b/backend/routes/tasks/queries/query-builders.js @@ -83,7 +83,7 @@ async function filterTasksByParams( }, { model: Project, - attributes: ['id', 'name', 'state', 'uid'], + attributes: ['id', 'name', 'status', 'uid'], required: false, }, { @@ -373,7 +373,7 @@ function getTaskIncludeConfig() { }, { model: Project, - attributes: ['id', 'name', 'state', 'uid'], + attributes: ['id', 'name', 'status', 'uid'], required: false, }, { diff --git a/backend/services/backupService.js b/backend/services/backupService.js index 114611d..39164ee 100644 --- a/backend/services/backupService.js +++ b/backend/services/backupService.js @@ -364,7 +364,7 @@ async function importUserData(userId, backupData, options = { merge: true }) { task_show_completed: projectData.task_show_completed, task_sort_order: projectData.task_sort_order, - state: projectData.state, + status: projectData.status || projectData.state, user_id: userId, area_id: areaId, }, diff --git a/backend/tests/integration/projects.test.js b/backend/tests/integration/projects.test.js index ffe43c4..8a0efaa 100644 --- a/backend/tests/integration/projects.test.js +++ b/backend/tests/integration/projects.test.js @@ -29,7 +29,7 @@ describe('Projects Routes', () => { const projectData = { name: 'Test Project', description: 'Test Description', - state: 'planned', + status: 'planned', pin_to_sidebar: false, priority: 1, area_id: area.id, @@ -40,7 +40,7 @@ describe('Projects Routes', () => { expect(response.status).toBe(201); expect(response.body.name).toBe(projectData.name); expect(response.body.description).toBe(projectData.description); - expect(response.body.state).toBe(projectData.state); + expect(response.body.status).toBe(projectData.status); expect(response.body.pin_to_sidebar).toBe( projectData.pin_to_sidebar ); @@ -217,7 +217,7 @@ describe('Projects Routes', () => { project = await Project.create({ name: 'Test Project', description: 'Test Description', - state: 'idea', + status: 'not_started', priority: 0, user_id: user.id, }); @@ -227,7 +227,7 @@ describe('Projects Routes', () => { const updateData = { name: 'Updated Project', description: 'Updated Description', - state: 'in_progress', + status: 'in_progress', priority: 2, }; @@ -238,7 +238,7 @@ describe('Projects Routes', () => { expect(response.status).toBe(200); expect(response.body.name).toBe(updateData.name); expect(response.body.description).toBe(updateData.description); - expect(response.body.state).toBe(updateData.state); + expect(response.body.status).toBe(updateData.status); expect(response.body.priority).toBe(updateData.priority); }); diff --git a/backend/tests/integration/search.test.js b/backend/tests/integration/search.test.js index 3400ed4..69afb85 100644 --- a/backend/tests/integration/search.test.js +++ b/backend/tests/integration/search.test.js @@ -961,7 +961,7 @@ describe('Universal Search Routes', () => { expect(project.name).toBe('Test project'); expect(project.description).toBe('Project description'); expect(project.priority).toBe('medium'); - expect(project.status).toBe('active'); + expect(project.status).toBe('not_started'); }); it('should return note with correct structure', async () => { diff --git a/backend/tests/unit/models/project.test.js b/backend/tests/unit/models/project.test.js index 0964df8..0e31ce2 100644 --- a/backend/tests/unit/models/project.test.js +++ b/backend/tests/unit/models/project.test.js @@ -21,7 +21,7 @@ describe('Project Model', () => { const projectData = { name: 'Test Project', description: 'Test Description', - state: 'planned', + status: 'planned', pin_to_sidebar: false, priority: 1, user_id: user.id, @@ -32,7 +32,7 @@ describe('Project Model', () => { expect(project.name).toBe(projectData.name); expect(project.description).toBe(projectData.description); - expect(project.state).toBe(projectData.state); + expect(project.status).toBe(projectData.status); expect(project.pin_to_sidebar).toBe(projectData.pin_to_sidebar); expect(project.priority).toBe(projectData.priority); expect(project.user_id).toBe(user.id); @@ -85,7 +85,7 @@ describe('Project Model', () => { user_id: user.id, }); - expect(project.state).toBe('idea'); + expect(project.status).toBe('not_started'); expect(project.pin_to_sidebar).toBe(false); expect(project.task_show_completed).toBe(false); expect(project.task_sort_order).toBe('created_at:desc'); diff --git a/frontend/Layout.tsx b/frontend/Layout.tsx index 78095a1..595bac1 100644 --- a/frontend/Layout.tsx +++ b/frontend/Layout.tsx @@ -219,7 +219,7 @@ const Layout: React.FC = ({ try { const newProject = await createProject({ name, - state: 'planned', + status: 'planned', }); return newProject; } catch (error) { diff --git a/frontend/components/Inbox/InboxItemDetail.tsx b/frontend/components/Inbox/InboxItemDetail.tsx index d1c8fa4..21f5543 100644 --- a/frontend/components/Inbox/InboxItemDetail.tsx +++ b/frontend/components/Inbox/InboxItemDetail.tsx @@ -418,7 +418,7 @@ const InboxItemDetail: React.FC = ({ const newProject: Project = { name: payload.cleanedContent || displayText, description: '', - state: 'planned', + status: 'planned', tags: payload.tagObjects, }; diff --git a/frontend/components/Inbox/InboxItems.tsx b/frontend/components/Inbox/InboxItems.tsx index 5fb1e3c..cafc8d2 100644 --- a/frontend/components/Inbox/InboxItems.tsx +++ b/frontend/components/Inbox/InboxItems.tsx @@ -374,7 +374,7 @@ const InboxItems: React.FC = () => { const handleCreateProject = async (name: string): Promise => { try { - const project = await createProject({ name, state: 'planned' }); + const project = await createProject({ name, status: 'planned' }); showSuccessToast(t('project.createSuccess')); return project; } catch (error) { diff --git a/frontend/components/Inbox/QuickCaptureInput.tsx b/frontend/components/Inbox/QuickCaptureInput.tsx index 9cf3ac3..6dc526d 100644 --- a/frontend/components/Inbox/QuickCaptureInput.tsx +++ b/frontend/components/Inbox/QuickCaptureInput.tsx @@ -1065,7 +1065,7 @@ const QuickCaptureInput = React.forwardRef< try { await createProject({ name: projectName, - state: 'planned', + status: 'planned', }); } catch (error) { console.error( @@ -1411,7 +1411,7 @@ const QuickCaptureInput = React.forwardRef< const newProject: Project = { name: cleaned, description: '', - state: 'planned', + status: 'planned', tags: buildTagObjects( composerFooterContext.hashtags ), diff --git a/frontend/components/Productivity/ProductivityAssistant.tsx b/frontend/components/Productivity/ProductivityAssistant.tsx index d2b0671..375885a 100644 --- a/frontend/components/Productivity/ProductivityAssistant.tsx +++ b/frontend/components/Productivity/ProductivityAssistant.tsx @@ -72,8 +72,8 @@ const ProductivityAssistant: React.FC = ({ // 1. Stalled Projects (no tasks/actions) const stalledProjects = projects.filter( (project) => - (project.state === 'planned' || - project.state === 'in_progress') && + (project.status === 'planned' || + project.status === 'in_progress') && !activeTasks.some((task) => task.project_id === project.id) ); @@ -110,8 +110,8 @@ const ProductivityAssistant: React.FC = ({ task.status === 'in_progress') ); return ( - (project.state === 'planned' || - project.state === 'in_progress') && + (project.status === 'planned' || + project.status === 'in_progress') && hasCompletedTasks && !hasNextAction ); @@ -214,8 +214,8 @@ const ProductivityAssistant: React.FC = ({ const stuckProjects = projects.filter((project) => { if ( !( - project.state === 'planned' || - project.state === 'in_progress' + project.status === 'planned' || + project.status === 'in_progress' ) ) return false; diff --git a/frontend/components/Project/ProjectBanner.tsx b/frontend/components/Project/ProjectBanner.tsx index e364a87..3211620 100644 --- a/frontend/components/Project/ProjectBanner.tsx +++ b/frontend/components/Project/ProjectBanner.tsx @@ -22,7 +22,7 @@ interface ProjectBannerProps { project: Project; areas: Area[]; t: TFunction; - getStateIcon: (state: string) => React.ReactNode; + getStatusIcon: (status: string) => React.ReactNode; onDeleteClick: () => void; editButtonRef: RefObject; onEditBannerClick?: () => void; @@ -32,7 +32,7 @@ const ProjectBanner: React.FC = ({ project, areas, t, - getStateIcon, + getStatusIcon, onDeleteClick, editButtonRef, onEditBannerClick, @@ -76,11 +76,11 @@ const ProjectBanner: React.FC = ({
- {project.state && ( + {project.status && ( - {getStateIcon(project.state)} + {getStatusIcon(project.status)} - {t(`projects.states.${project.state}`)} + {t(`projectStatus.${project.status}`)} )} diff --git a/frontend/components/Project/ProjectDetails.tsx b/frontend/components/Project/ProjectDetails.tsx index c7ae6f1..187853e 100644 --- a/frontend/components/Project/ProjectDetails.tsx +++ b/frontend/components/Project/ProjectDetails.tsx @@ -3,11 +3,12 @@ import { useParams, useNavigate } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { MagnifyingGlassIcon, - LightBulbIcon, + EllipsisHorizontalCircleIcon, ClipboardDocumentListIcon, PlayIcon, - ExclamationTriangleIcon, + ClockIcon, CheckCircleIcon, + XCircleIcon, ChartBarIcon, CheckIcon, } from '@heroicons/react/24/outline'; @@ -700,32 +701,35 @@ const ProjectDetails: React.FC = () => { monthlyCompleted, } = useProjectMetrics(tasks, handleTaskUpdate, t, showSuccessToast); - const getStateIcon = (state: string) => { - switch (state) { - case 'idea': + const getStatusIcon = (status: string) => { + switch (status) { + case 'not_started': return ( - + ); case 'planned': return ( ); case 'in_progress': - case 'active': return ( ); - case 'blocked': + case 'waiting': return ( - + ); - case 'completed': + case 'done': return ( - + + ); + case 'cancelled': + return ( + ); default: return ( - + ); } }; @@ -834,7 +838,7 @@ const ProjectDetails: React.FC = () => { project={project} areas={areas} t={t} - getStateIcon={getStateIcon} + getStatusIcon={getStatusIcon} onDeleteClick={() => { setNoteToDelete(null); setIsConfirmDialogOpen(true); diff --git a/frontend/components/Project/ProjectItem.tsx b/frontend/components/Project/ProjectItem.tsx index 75d09b5..f608269 100644 --- a/frontend/components/Project/ProjectItem.tsx +++ b/frontend/components/Project/ProjectItem.tsx @@ -4,15 +4,16 @@ import { EllipsisVerticalIcon } from '@heroicons/react/24/solid'; import { PencilSquareIcon, TrashIcon, - LightBulbIcon, - DocumentTextIcon, + EllipsisHorizontalCircleIcon, + ClipboardDocumentListIcon, PlayIcon, - StopIcon, + ClockIcon, CheckCircleIcon, + XCircleIcon, ShareIcon, ExclamationTriangleIcon, } from '@heroicons/react/24/outline'; -import { Project, ProjectState } from '../../entities/Project'; +import { Project, ProjectStatus } from '../../entities/Project'; import { useTranslation } from 'react-i18next'; import { useToast } from '../Shared/ToastContext'; import { getCurrentUser } from '../../utils/userUtils'; @@ -48,38 +49,41 @@ const getProjectInitials = (name: string, maxLetters?: number) => { return maxLetters ? initials.substring(0, maxLetters) : initials; }; -const getStateIcon = (state: ProjectState | undefined) => { - switch (state) { - case 'idea': - return { icon: LightBulbIcon }; +const getStatusIcon = (status: ProjectStatus | undefined) => { + switch (status) { + case 'not_started': + return { icon: EllipsisHorizontalCircleIcon }; case 'planned': - return { icon: DocumentTextIcon }; + return { icon: ClipboardDocumentListIcon }; case 'in_progress': return { icon: PlayIcon }; - case 'blocked': - return { icon: StopIcon }; - case 'completed': + case 'waiting': + return { icon: ClockIcon }; + case 'done': return { icon: CheckCircleIcon }; + case 'cancelled': + return { icon: XCircleIcon }; default: - return { icon: LightBulbIcon }; + return { icon: EllipsisHorizontalCircleIcon }; } }; -const getStateLabel = (state: ProjectState | undefined, t: any): string => { - switch (state) { - case 'idea': - return t('projects.states.idea', 'Idea'); +const getStatusLabel = (status: ProjectStatus | undefined, t: any): string => { + switch (status) { + case 'not_started': + return t('projectStatus.not_started', 'Not Started'); case 'planned': - return t('projects.states.planned', 'Planned'); + return t('projectStatus.planned', 'Planned'); case 'in_progress': - case 'active': - return t('projects.states.in_progress', 'In Progress'); - case 'blocked': - return t('projects.states.blocked', 'Blocked'); - case 'completed': - return t('projects.states.completed', 'Completed'); + return t('projectStatus.in_progress', 'In Progress'); + case 'waiting': + return t('projectStatus.waiting', 'Waiting'); + case 'done': + return t('projectStatus.done', 'Completed'); + case 'cancelled': + return t('projectStatus.cancelled', 'Cancelled'); default: - return t('projects.states.idea', 'Idea'); + return t('projectStatus.not_started', 'Not Started'); } }; @@ -299,14 +303,14 @@ const ProjectItem: React.FC = ({ /> )} {(() => { - const { icon: StateIcon } = getStateIcon( - project.state + const { icon: StatusIcon } = getStatusIcon( + project.status ); return ( - diff --git a/frontend/components/Project/ProjectModal.tsx b/frontend/components/Project/ProjectModal.tsx index ef96dd8..ca8da87 100644 --- a/frontend/components/Project/ProjectModal.tsx +++ b/frontend/components/Project/ProjectModal.tsx @@ -45,7 +45,7 @@ const ProjectModal: React.FC = ({ name: '', description: '', area_id: null, - state: 'idea', + status: 'not_started', tags: [], priority: null, due_date_at: null, @@ -71,7 +71,7 @@ const ProjectModal: React.FC = ({ // Collapsible sections state const [expandedSections, setExpandedSections] = useState({ - state: false, + status: false, tags: false, area: false, priority: false, @@ -128,7 +128,7 @@ const ProjectModal: React.FC = ({ name: '', description: '', area_id: null, - state: 'idea', + status: 'not_started', tags: [], priority: null, due_date_at: null, @@ -328,7 +328,7 @@ const ProjectModal: React.FC = ({ formData.name.trim() !== '' || formData.description?.trim() !== '' || formData.area_id !== null || - formData.state !== 'idea' || + formData.status !== 'not_started' || tags.length > 0 || formData.priority !== null || formData.due_date_at !== null @@ -340,7 +340,7 @@ const ProjectModal: React.FC = ({ formData.name !== project.name || formData.description !== project.description || formData.area_id !== project.area_id || - formData.state !== project.state || + formData.status !== project.status || formData.priority !== project.priority || formData.due_date_at !== project.due_date_at; @@ -511,25 +511,25 @@ const ProjectModal: React.FC = ({
{/* Expandable Sections - Only show when expanded */} - {/* State Section - First */} - {expandedSections.state && ( + {/* Status Section - First */} + {expandedSections.status && (

{t( - 'projects.state', - 'Project State' + 'projects.status', + 'Project Status' )}

+ onChange={(status) => setFormData( (prev) => ({ ...prev, - state, + status, }) ) } @@ -646,25 +646,26 @@ const ProjectModal: React.FC = ({
{/* Left side: Section icons */}
- {/* State Toggle - First */} + {/* Status Toggle - First */} diff --git a/frontend/components/Projects.tsx b/frontend/components/Projects.tsx index 572919a..f9b3cb1 100644 --- a/frontend/components/Projects.tsx +++ b/frontend/components/Projects.tsx @@ -69,7 +69,7 @@ const Projects: React.FC = () => { const [orderBy, setOrderBy] = useState('created_at:desc'); const [searchParams, setSearchParams] = useSearchParams(); - const stateFilter = searchParams.get('state') || 'all'; + const statusFilter = searchParams.get('status') || 'not_completed'; // Get area UID from URL parameters const getAreaUidFromParams = () => { @@ -94,16 +94,25 @@ const Projects: React.FC = () => { // Filter options for dropdowns const statusOptions: FilterOption[] = [ { value: 'all', label: t('projects.filters.all') }, - { value: 'idea', label: t('projects.states.idea', 'Idea') }, - { value: 'planned', label: t('projects.states.planned', 'Planned') }, + { + value: 'not_started', + label: t('projectStatus.not_started', 'Not Started'), + }, + { value: 'planned', label: t('projectStatus.planned', 'Planned') }, { value: 'in_progress', - label: t('projects.states.in_progress', 'In Progress'), + label: t('projectStatus.in_progress', 'In Progress'), }, - { value: 'blocked', label: t('projects.states.blocked', 'Blocked') }, + { value: 'waiting', label: t('projectStatus.waiting', 'Waiting') }, + { value: 'done', label: t('projectStatus.done', 'Completed') }, { - value: 'completed', - label: t('projects.states.completed', 'Completed'), + value: 'cancelled', + label: t('projectStatus.cancelled', 'Cancelled'), + }, + { value: 'divider', label: '' }, + { + value: 'not_completed', + label: t('projects.filters.notCompleted', 'Not Completed'), }, ]; @@ -241,13 +250,13 @@ const Projects: React.FC = () => { return (project as any).completion_percentage || 0; }; - const handleStateFilterChange = (value: string) => { + const handleStatusFilterChange = (value: string) => { const params = new URLSearchParams(searchParams); - if (value === 'all') { - params.delete('state'); + if (value === 'not_completed') { + params.delete('status'); } else { - params.set('state', value); + params.set('status', value); } setSearchParams(params); }; @@ -273,10 +282,15 @@ const Projects: React.FC = () => { const displayProjects = useMemo(() => { let filteredProjects = [...projects]; - // Apply state filter - if (stateFilter !== 'all') { + // Apply status filter + if (statusFilter === 'not_completed') { filteredProjects = filteredProjects.filter( - (project) => project.state === stateFilter + (project) => + project.status !== 'done' && project.status !== 'cancelled' + ); + } else if (statusFilter !== 'all') { + filteredProjects = filteredProjects.filter( + (project) => project.status === statusFilter ); } @@ -347,7 +361,7 @@ const Projects: React.FC = () => { }); return filteredProjects; - }, [projects, stateFilter, actualAreaFilter, searchQuery, orderBy]); + }, [projects, statusFilter, actualAreaFilter, searchQuery, orderBy]); if (isLoading) { return ( @@ -426,8 +440,8 @@ const Projects: React.FC = () => {
diff --git a/frontend/components/Shared/FilterDropdown.tsx b/frontend/components/Shared/FilterDropdown.tsx index 5d9db40..2abd38c 100644 --- a/frontend/components/Shared/FilterDropdown.tsx +++ b/frontend/components/Shared/FilterDropdown.tsx @@ -103,26 +103,33 @@ const FilterDropdown: React.FC = ({ style={autoWidth ? dynamicStyles : {}} >
- {options.map((option) => ( - - ))} + {options.map((option, index) => + option.value === 'divider' ? ( +
+ ) : ( + + ) + )}
)} diff --git a/frontend/components/Shared/ProjectStateDropdown.tsx b/frontend/components/Shared/ProjectStateDropdown.tsx index 0c4318f..55a68da 100644 --- a/frontend/components/Shared/ProjectStateDropdown.tsx +++ b/frontend/components/Shared/ProjectStateDropdown.tsx @@ -1,18 +1,19 @@ import React, { useState, useRef, useEffect } from 'react'; import { ChevronDownIcon, - LightBulbIcon, ClipboardDocumentListIcon, PlayIcon, - ExclamationTriangleIcon, CheckCircleIcon, + ClockIcon, + XCircleIcon, + EllipsisHorizontalCircleIcon, } from '@heroicons/react/24/outline'; -import { ProjectState } from '../../entities/Project'; +import { ProjectStatus } from '../../entities/Project'; import { useTranslation } from 'react-i18next'; interface ProjectStateDropdownProps { - value: ProjectState; - onChange: (value: ProjectState) => void; + value: ProjectStatus; + onChange: (value: ProjectStatus) => void; } const ProjectStateDropdown: React.FC = ({ @@ -23,19 +24,21 @@ const ProjectStateDropdown: React.FC = ({ const states = [ { - value: 'idea' as ProjectState, - label: t('projects.states.idea', 'Idea'), + value: 'not_started' as ProjectStatus, + label: t('projectStatus.not_started', 'Not Started'), description: t( - 'projects.states.idea_desc', - 'captured but not planned yet' + 'projectStatus.not_started_desc', + 'captured but not started yet' + ), + icon: ( + ), - icon: , }, { - value: 'planned' as ProjectState, - label: t('projects.states.planned', 'Planned'), + value: 'planned' as ProjectStatus, + label: t('projectStatus.planned', 'Planned'), description: t( - 'projects.states.planned_desc', + 'projectStatus.planned_desc', 'scoped and ready to start' ), icon: ( @@ -43,31 +46,37 @@ const ProjectStateDropdown: React.FC = ({ ), }, { - value: 'in_progress' as ProjectState, - label: t('projects.states.in_progress', 'In Progress'), + value: 'in_progress' as ProjectStatus, + label: t('projectStatus.in_progress', 'In Progress'), description: t( - 'projects.states.in_progress_desc', + 'projectStatus.in_progress_desc', 'active work happening' ), icon: , }, { - value: 'blocked' as ProjectState, - label: t('projects.states.blocked', 'Blocked'), + value: 'waiting' as ProjectStatus, + label: t('projectStatus.waiting', 'Waiting'), description: t( - 'projects.states.blocked_desc', - 'temporarily paused or stuck' + 'projectStatus.waiting_desc', + 'waiting on external input' ), - icon: , + icon: , }, { - value: 'completed' as ProjectState, - label: t('projects.states.completed', 'Completed'), + value: 'done' as ProjectStatus, + label: t('projectStatus.done', 'Completed'), + description: t('projectStatus.done_desc', 'finished and done'), + icon: , + }, + { + value: 'cancelled' as ProjectStatus, + label: t('projectStatus.cancelled', 'Cancelled'), description: t( - 'projects.states.completed_desc', - 'finished and done' + 'projectStatus.cancelled_desc', + 'will not be completed' ), - icon: , + icon: , }, ]; @@ -110,8 +119,8 @@ const ProjectStateDropdown: React.FC = ({ } }; - const handleSelect = (state: ProjectState) => { - onChange(state); + const handleSelect = (status: ProjectStatus) => { + onChange(status); setIsOpen(false); }; @@ -182,7 +191,7 @@ const ProjectStateDropdown: React.FC = ({ {selectedState ? ( selectedState.icon ) : ( - + )} {selectedState diff --git a/frontend/components/Task/TasksToday.tsx b/frontend/components/Task/TasksToday.tsx index 565c7bd..3ee2351 100644 --- a/frontend/components/Task/TasksToday.tsx +++ b/frontend/components/Task/TasksToday.tsx @@ -1196,12 +1196,12 @@ const TasksToday: React.FC = () => { {Array.isArray(localProjects) ? localProjects.filter( (project) => - project.state && + project.status && [ 'planned', 'in_progress', - 'blocked', - ].includes(project.state) + 'waiting', + ].includes(project.status) ).length : 0}

diff --git a/frontend/entities/Project.ts b/frontend/entities/Project.ts index c2add54..d3c89a0 100644 --- a/frontend/entities/Project.ts +++ b/frontend/entities/Project.ts @@ -3,13 +3,13 @@ import { Tag } from './Tag'; import { PriorityType, Task } from './Task'; import { Note } from './Note'; -export type ProjectState = - | 'idea' +export type ProjectStatus = + | 'not_started' | 'planned' | 'in_progress' - | 'active' - | 'blocked' - | 'completed'; + | 'waiting' + | 'done' + | 'cancelled'; export interface Project { id?: number; @@ -30,7 +30,7 @@ export interface Project { image_url?: string; task_show_completed?: boolean; task_sort_order?: string; - state?: ProjectState; + status?: ProjectStatus; created_at?: string; updated_at?: string; share_count?: number; diff --git a/public/locales/ar/translation.json b/public/locales/ar/translation.json index 75804bb..220887a 100644 --- a/public/locales/ar/translation.json +++ b/public/locales/ar/translation.json @@ -151,7 +151,9 @@ "open": "فتح", "completed": "مكتمل", "noCompletedTasksToday": "لا توجد مهام مكتملة اليوم.", - "markAsDone": "Mark as done" + "markAsDone": "Mark as done", + "notStarted": "لم يبدأ بعد", + "done": "تم" }, "timeline": { "activityTimeline": "جدول الأنشطة", @@ -820,7 +822,8 @@ "active": "نشط", "inactive": "غير نشط", "all": "الكل", - "allAreas": "جميع المناطق" + "allAreas": "جميع المناطق", + "notCompleted": "لم يكتمل" }, "selectState": "اختر الحالة", "state": "حالة المشروع", @@ -1342,5 +1345,19 @@ "title": "ملاحظة:", "message": "ستكون إشعارات البريد الإلكتروني وإشعارات الدفع متاحة قريبًا. الإشعارات داخل التطبيق وإشعارات تليجرام متاحة حاليًا." } + }, + "projectStatus": { + "not_started": "لم يبدأ بعد", + "not_started_desc": "تم التقاطه ولكن لم يبدأ بعد", + "planned": "مخطط", + "planned_desc": "تم تحديد نطاقه وجاهز للبدء", + "in_progress": "قيد التنفيذ", + "in_progress_desc": "عمل نشط جارٍ", + "waiting": "انتظار", + "waiting_desc": "في انتظار مدخلات خارجية", + "done": "مكتمل", + "done_desc": "انتهى وتم", + "cancelled": "ملغى", + "cancelled_desc": "لن يكتمل" } -} \ No newline at end of file +} diff --git a/public/locales/bg/translation.json b/public/locales/bg/translation.json index cdf7f56..38c35b4 100644 --- a/public/locales/bg/translation.json +++ b/public/locales/bg/translation.json @@ -151,7 +151,9 @@ "open": "Отвори", "completed": "Завършено", "noCompletedTasksToday": "Няма завършени задачи днес.", - "markAsDone": "Mark as done" + "markAsDone": "Mark as done", + "notStarted": "Не е започнато", + "done": "Завършено" }, "timeline": { "activityTimeline": "Хронология на активността", @@ -820,7 +822,8 @@ "active": "Активен", "inactive": "Неактивен", "all": "Всички", - "allAreas": "Всички области" + "allAreas": "Всички области", + "notCompleted": "Не е завършено" }, "selectState": "Изберете състояние", "state": "Състояние на проекта", @@ -1342,5 +1345,19 @@ "title": "Забележка:", "message": "Имейл и Push известия ще бъдат налични скоро. В приложението и Telegram известията в момента са налични." } + }, + "projectStatus": { + "not_started": "Не е започнато", + "not_started_desc": "Записано, но все още не е започнато", + "planned": "Планирано", + "planned_desc": "Определено и готово за започване", + "in_progress": "В процес", + "in_progress_desc": "Активна работа в ход", + "waiting": "Изчакване", + "waiting_desc": "Изчакване на външна информация", + "done": "Завършено", + "done_desc": "Завършено и готово", + "cancelled": "Отменено", + "cancelled_desc": "Няма да бъде завършено" } -} \ No newline at end of file +} diff --git a/public/locales/da/translation.json b/public/locales/da/translation.json index 6aa8f08..0b729ba 100644 --- a/public/locales/da/translation.json +++ b/public/locales/da/translation.json @@ -151,7 +151,9 @@ "open": "Åbn", "completed": "Fuldført", "noCompletedTasksToday": "Ingen fuldførte opgaver i dag.", - "markAsDone": "Mark as done" + "markAsDone": "Mark as done", + "notStarted": "Ikke startet", + "done": "Færdig" }, "timeline": { "activityTimeline": "Aktivitets Tidslinje", @@ -820,7 +822,8 @@ "active": "Aktiv", "inactive": "Inaktiv", "all": "Alle", - "allAreas": "Alle områder" + "allAreas": "Alle områder", + "notCompleted": "Ikke færdiggjort" }, "selectState": "Vælg tilstand", "state": "Projektstatus", @@ -1342,5 +1345,19 @@ "title": "Bemærk:", "message": "E-mail og push-notifikationer kommer snart. Notifikationer i appen og Telegram er i øjeblikket tilgængelige." } + }, + "projectStatus": { + "not_started": "Ikke startet", + "not_started_desc": "Registreret, men ikke startet endnu", + "planned": "Planlagt", + "planned_desc": "Afgrænset og klar til at starte", + "in_progress": "I gang", + "in_progress_desc": "Aktivt arbejde i gang", + "waiting": "Venter", + "waiting_desc": "Venter på ekstern input", + "done": "Færdiggjort", + "done_desc": "Afsluttet og færdig", + "cancelled": "Annulleret", + "cancelled_desc": "Vil ikke blive færdiggjort" } -} \ No newline at end of file +} diff --git a/public/locales/de/translation.json b/public/locales/de/translation.json index 3d56472..5591c2f 100644 --- a/public/locales/de/translation.json +++ b/public/locales/de/translation.json @@ -151,7 +151,9 @@ "open": "Öffnen", "completed": "Abgeschlossen", "noCompletedTasksToday": "Keine abgeschlossenen Aufgaben heute.", - "markAsDone": "Mark as done" + "markAsDone": "Mark as done", + "notStarted": "Nicht gestartet", + "done": "Fertig" }, "timeline": { "activityTimeline": "Aktivitätsverlauf", @@ -912,7 +914,8 @@ "active": "Aktiv", "inactive": "Inaktiv", "all": "Alle", - "allAreas": "Alle Bereiche" + "allAreas": "Alle Bereiche", + "notCompleted": "Nicht abgeschlossen" }, "selectState": "Zustand auswählen", "state": "Projektzustand", @@ -1351,5 +1354,19 @@ "title": "Hinweis:", "message": "E-Mail- und Push-Benachrichtigungen kommen bald. In-App- und Telegram-Benachrichtigungen sind derzeit verfügbar." } + }, + "projectStatus": { + "not_started": "Nicht gestartet", + "not_started_desc": "Erfasst, aber noch nicht gestartet", + "planned": "Geplant", + "planned_desc": "Abgegrenzt und bereit zum Start", + "in_progress": "In Bearbeitung", + "in_progress_desc": "Aktive Arbeit läuft", + "waiting": "Warten", + "waiting_desc": "Warten auf externe Eingaben", + "done": "Abgeschlossen", + "done_desc": "Fertig und abgeschlossen", + "cancelled": "Abgebrochen", + "cancelled_desc": "Wird nicht abgeschlossen" } -} \ No newline at end of file +} diff --git a/public/locales/el/translation.json b/public/locales/el/translation.json index 2ec30bd..a99486c 100644 --- a/public/locales/el/translation.json +++ b/public/locales/el/translation.json @@ -366,7 +366,9 @@ "open": "Άνοιγμα", "completed": "Ολοκληρώθηκε", "noCompletedTasksToday": "Καμία ολοκληρωμένη εργασία σήμερα.", - "markAsDone": "Mark as done" + "markAsDone": "Mark as done", + "notStarted": "Δεν έχει ξεκινήσει", + "done": "Ολοκληρώθηκε" }, "timeline": { "activityTimeline": "Χρονοδιάγραμμα Δραστηριότητας", @@ -427,7 +429,8 @@ "active": "Ενεργά", "inactive": "Ανενεργά", "all": "Όλα", - "allAreas": "Όλες οι περιοχές" + "allAreas": "Όλες οι περιοχές", + "notCompleted": "Δεν έχει ολοκληρωθεί" }, "selectState": "Επιλέξτε Κατάσταση", "state": "Κατάσταση Έργου", @@ -1346,5 +1349,19 @@ "title": "Σημείωση:", "message": "Οι ειδοποιήσεις μέσω Email και Push έρχονται σύντομα. Οι ειδοποιήσεις εντός της εφαρμογής και μέσω Telegram είναι διαθέσιμες αυτή τη στιγμή." } + }, + "projectStatus": { + "not_started": "Δεν έχει ξεκινήσει", + "not_started_desc": "Καταγεγραμμένο αλλά δεν έχει ξεκινήσει ακόμα", + "planned": "Προγραμματισμένο", + "planned_desc": "Καθορισμένο και έτοιμο για εκκίνηση", + "in_progress": "Σε εξέλιξη", + "in_progress_desc": "Ενεργή εργασία σε εξέλιξη", + "waiting": "Αναμονή", + "waiting_desc": "Αναμονή για εξωτερική είσοδο", + "done": "Ολοκληρώθηκε", + "done_desc": "Ολοκληρωμένο και τελειωμένο", + "cancelled": "Ακυρώθηκε", + "cancelled_desc": "Δεν θα ολοκληρωθεί" } -} \ No newline at end of file +} diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json index 0e0499a..98ce005 100644 --- a/public/locales/en/translation.json +++ b/public/locales/en/translation.json @@ -812,26 +812,6 @@ "metrics": "Projects", "selectState": "Select State", "state": "Project State", - "filters": { - "active": "Active", - "inactive": "Inactive", - "all": "All", - "allAreas": "All Areas" - }, - "states": { - "idea": "Idea", - "planned": "Planned", - "in_progress": "In Progress", - "active": "In Progress", - "blocked": "Blocked", - "completed": "Completed", - "idea_desc": "Captured but not planned yet", - "planned_desc": "Scoped and ready to start", - "in_progress_desc": "Active work happening", - "active_desc": "Active work happening", - "blocked_desc": "Temporarily paused or stuck", - "completed_desc": "Finished and done" - }, "showMetrics": "Show metrics", "hideMetrics": "Hide metrics", "progress": "Progress", @@ -854,7 +834,28 @@ "nextUp": "Next best action", "focusTask": "Most impactful task", "focusHint": "Shifts this task to in progress and today", - "noNextAction": "All clear—no outstanding tasks." + "noNextAction": "All clear—no outstanding tasks.", + "filters": { + "active": "Active", + "inactive": "Inactive", + "all": "All", + "allAreas": "All Areas", + "notCompleted": "Not Completed" + } + }, + "projectStatus": { + "not_started": "Not Started", + "not_started_desc": "Captured but not started yet", + "planned": "Planned", + "planned_desc": "Scoped and ready to start", + "in_progress": "In Progress", + "in_progress_desc": "Active work happening", + "waiting": "Waiting", + "waiting_desc": "Waiting on external input", + "done": "Completed", + "done_desc": "Finished and done", + "cancelled": "Cancelled", + "cancelled_desc": "Will not be completed" }, "projectItem": { "edit": "Edit", diff --git a/public/locales/es/translation.json b/public/locales/es/translation.json index 569a318..a36711b 100644 --- a/public/locales/es/translation.json +++ b/public/locales/es/translation.json @@ -366,7 +366,9 @@ "open": "Abrir", "completed": "Completado", "noCompletedTasksToday": "No hay tareas completadas hoy.", - "markAsDone": "Mark as done" + "markAsDone": "Mark as done", + "notStarted": "No Iniciado", + "done": "Hecho" }, "timeline": { "activityTimeline": "Línea de Tiempo de Actividad", @@ -427,24 +429,11 @@ "active": "Activos", "inactive": "Inactivos", "all": "Todos", - "allAreas": "Todas las áreas" + "allAreas": "Todas las áreas", + "notCompleted": "No Completados" }, "selectState": "Seleccionar Estado", "state": "Estado del Proyecto", - "states": { - "idea": "Idea", - "planned": "Planificado", - "in_progress": "En Progreso", - "blocked": "Bloqueado", - "completed": "Completado", - "idea_desc": "Capturado pero aún no planificado", - "planned_desc": "Definido y listo para comenzar", - "in_progress_desc": "Trabajo activo en curso", - "blocked_desc": "Pausado temporalmente o atascado", - "completed_desc": "Terminado y completado", - "active": "En Progreso", - "active_desc": "Trabajo activo en curso" - }, "showMetrics": "Mostrar métricas", "hideMetrics": "Ocultar métricas", "progress": "Progreso", @@ -1343,5 +1332,19 @@ "title": "Nota:", "message": "Las notificaciones por correo electrónico y Push llegarán pronto. Las notificaciones en la aplicación y de Telegram están disponibles actualmente." } + }, + "projectStatus": { + "not_started": "No Iniciado", + "not_started_desc": "Capturado pero aún no iniciado", + "planned": "Planificado", + "planned_desc": "Definido y listo para comenzar", + "in_progress": "En Progreso", + "in_progress_desc": "Trabajo activo en curso", + "waiting": "Esperando", + "waiting_desc": "Esperando entrada externa", + "done": "Completado", + "done_desc": "Terminado y hecho", + "cancelled": "Cancelado", + "cancelled_desc": "No se completará" } } diff --git a/public/locales/fi/translation.json b/public/locales/fi/translation.json index f578b00..b78de94 100644 --- a/public/locales/fi/translation.json +++ b/public/locales/fi/translation.json @@ -151,7 +151,9 @@ "open": "Avaa", "completed": "Valmis", "noCompletedTasksToday": "Ei suoritettuja tehtäviä tänään.", - "markAsDone": "Mark as done" + "markAsDone": "Mark as done", + "notStarted": "Ei aloitettu", + "done": "Valmis" }, "timeline": { "activityTimeline": "Toiminta-aikajana", @@ -820,7 +822,8 @@ "active": "Aktiivinen", "inactive": "Passiivinen", "all": "Kaikki", - "allAreas": "Kaikki alueet" + "allAreas": "Kaikki alueet", + "notCompleted": "Ei valmis" }, "selectState": "Valitse tila", "state": "Projektin tila", @@ -1342,5 +1345,19 @@ "title": "Huom:", "message": "Sähköposti- ja Push-ilmoitukset ovat tulossa pian. Sovelluksen sisäiset ja Telegram-ilmoitukset ovat tällä hetkellä saatavilla." } + }, + "projectStatus": { + "not_started": "Ei aloitettu", + "not_started_desc": "Tallennettu mutta ei vielä aloitettu", + "planned": "Suunniteltu", + "planned_desc": "Määritelty ja valmis aloittamaan", + "in_progress": "Käynnissä", + "in_progress_desc": "Aktiivista työtä käynnissä", + "waiting": "Odottaa", + "waiting_desc": "Odottaa ulkoista syötettä", + "done": "Valmistunut", + "done_desc": "Valmis ja tehty", + "cancelled": "Peruutettu", + "cancelled_desc": "Ei tule valmistumaan" } -} \ No newline at end of file +} diff --git a/public/locales/fr/translation.json b/public/locales/fr/translation.json index 57fc7ac..a90a8e8 100644 --- a/public/locales/fr/translation.json +++ b/public/locales/fr/translation.json @@ -151,7 +151,9 @@ "open": "Ouvrir", "completed": "Terminé", "noCompletedTasksToday": "Aucune tâche terminée aujourd'hui.", - "markAsDone": "Mark as done" + "markAsDone": "Mark as done", + "notStarted": "Non commencé", + "done": "Fait" }, "timeline": { "activityTimeline": "Chronologie d'Activité", @@ -820,7 +822,8 @@ "active": "Actif", "inactive": "Inactif", "all": "Tous", - "allAreas": "Toutes les zones" + "allAreas": "Toutes les zones", + "notCompleted": "Non terminé" }, "selectState": "Sélectionner l'état", "state": "État du projet", @@ -1342,5 +1345,19 @@ "title": "Remarque :", "message": "Les notifications par e-mail et push arrivent bientôt. Les notifications dans l'application et sur Telegram sont actuellement disponibles." } + }, + "projectStatus": { + "not_started": "Non commencé", + "not_started_desc": "Capturé mais pas encore commencé", + "planned": "Prévu", + "planned_desc": "Défini et prêt à commencer", + "in_progress": "En cours", + "in_progress_desc": "Travail actif en cours", + "waiting": "En attente", + "waiting_desc": "En attente d'une entrée externe", + "done": "Terminé", + "done_desc": "Fini et terminé", + "cancelled": "Annulé", + "cancelled_desc": "Ne sera pas terminé" } -} \ No newline at end of file +} diff --git a/public/locales/id/translation.json b/public/locales/id/translation.json index ad439ac..95a552f 100644 --- a/public/locales/id/translation.json +++ b/public/locales/id/translation.json @@ -151,7 +151,9 @@ "open": "Buka", "completed": "Selesai", "noCompletedTasksToday": "Tidak ada tugas yang diselesaikan hari ini.", - "markAsDone": "Mark as done" + "markAsDone": "Mark as done", + "notStarted": "Belum Dimulai", + "done": "Selesai" }, "timeline": { "activityTimeline": "Garis Waktu Aktivitas", @@ -820,7 +822,8 @@ "active": "Aktif", "inactive": "Tidak Aktif", "all": "Semua", - "allAreas": "Semua Area" + "allAreas": "Semua Area", + "notCompleted": "Belum Selesai" }, "selectState": "Pilih Status", "state": "Status Proyek", @@ -1342,5 +1345,19 @@ "title": "Catatan:", "message": "Notifikasi Email dan Push akan segera hadir. Notifikasi di dalam aplikasi dan Telegram saat ini tersedia." } + }, + "projectStatus": { + "not_started": "Belum Dimulai", + "not_started_desc": "Tercatat tetapi belum dimulai", + "planned": "Direncanakan", + "planned_desc": "Sudah ditentukan dan siap untuk dimulai", + "in_progress": "Sedang Berlangsung", + "in_progress_desc": "Pekerjaan aktif sedang berlangsung", + "waiting": "Menunggu", + "waiting_desc": "Menunggu masukan eksternal", + "done": "Selesai", + "done_desc": "Telah selesai dan selesai", + "cancelled": "Dibatalkan", + "cancelled_desc": "Tidak akan diselesaikan" } -} \ No newline at end of file +} diff --git a/public/locales/it/translation.json b/public/locales/it/translation.json index 6a5b08c..1416068 100644 --- a/public/locales/it/translation.json +++ b/public/locales/it/translation.json @@ -151,7 +151,9 @@ "open": "Apri", "completed": "Completato", "noCompletedTasksToday": "Nessuna attività completata oggi.", - "markAsDone": "Mark as done" + "markAsDone": "Mark as done", + "notStarted": "Non Iniziato", + "done": "Fatto" }, "timeline": { "activityTimeline": "Timeline delle Attività", @@ -820,7 +822,8 @@ "active": "Attivo", "inactive": "Inattivo", "all": "Tutti", - "allAreas": "Tutte le Aree" + "allAreas": "Tutte le Aree", + "notCompleted": "Non Completato" }, "selectState": "Seleziona Stato", "state": "Stato del Progetto", @@ -1342,5 +1345,19 @@ "title": "Nota:", "message": "Le notifiche via Email e Push arriveranno presto. Le notifiche in-app e su Telegram sono attualmente disponibili." } + }, + "projectStatus": { + "not_started": "Non Iniziato", + "not_started_desc": "Catturato ma non ancora iniziato", + "planned": "Pianificato", + "planned_desc": "Definito e pronto per iniziare", + "in_progress": "In Corso", + "in_progress_desc": "Lavoro attivo in corso", + "waiting": "In Attesa", + "waiting_desc": "In attesa di input esterno", + "done": "Completato", + "done_desc": "Finito e completato", + "cancelled": "Annullato", + "cancelled_desc": "Non sarà completato" } -} \ No newline at end of file +} diff --git a/public/locales/jp/translation.json b/public/locales/jp/translation.json index fd9d20f..1708c7b 100644 --- a/public/locales/jp/translation.json +++ b/public/locales/jp/translation.json @@ -151,7 +151,9 @@ "open": "開く", "completed": "完了", "noCompletedTasksToday": "本日完了したタスクはありません。", - "markAsDone": "Mark as done" + "markAsDone": "Mark as done", + "notStarted": "未開始", + "done": "完了" }, "timeline": { "activityTimeline": "アクティビティタイムライン", @@ -589,7 +591,8 @@ "active": "有効", "inactive": "無効", "all": "すべて", - "allAreas": "すべてのエリア" + "allAreas": "すべてのエリア", + "notCompleted": "未完了" }, "active": "アクティブ", "inactive": "非アクティブ", @@ -1342,5 +1345,19 @@ "title": "注意:", "message": "メールおよびプッシュ通知は近日中に提供予定です。アプリ内およびTelegram通知は現在利用可能です。" } + }, + "projectStatus": { + "not_started": "未開始", + "not_started_desc": "キャプチャされたが、まだ開始されていません", + "planned": "計画中", + "planned_desc": "スコープが決まり、開始準備が整いました", + "in_progress": "進行中", + "in_progress_desc": "アクティブな作業が行われています", + "waiting": "待機中", + "waiting_desc": "外部の入力を待っています", + "done": "完了", + "done_desc": "終了しました", + "cancelled": "キャンセル", + "cancelled_desc": "完了しません" } } diff --git a/public/locales/ko/translation.json b/public/locales/ko/translation.json index 58bf616..7090bff 100644 --- a/public/locales/ko/translation.json +++ b/public/locales/ko/translation.json @@ -151,7 +151,9 @@ "open": "열기", "completed": "완료됨", "noCompletedTasksToday": "오늘 완료된 작업이 없습니다.", - "markAsDone": "Mark as done" + "markAsDone": "Mark as done", + "notStarted": "시작되지 않음", + "done": "완료됨" }, "timeline": { "activityTimeline": "활동 타임라인", @@ -820,7 +822,8 @@ "active": "활성", "inactive": "비활성", "all": "모두", - "allAreas": "모든 영역" + "allAreas": "모든 영역", + "notCompleted": "완료되지 않음" }, "selectState": "상태 선택", "state": "프로젝트 상태", @@ -1342,5 +1345,19 @@ "title": "참고:", "message": "이메일 및 푸시 알림이 곧 제공됩니다. 현재 앱 내 및 텔레그램 알림이 가능합니다." } + }, + "projectStatus": { + "not_started": "시작되지 않음", + "not_started_desc": "포착되었지만 아직 시작되지 않음", + "planned": "계획됨", + "planned_desc": "범위가 정해지고 시작할 준비가 됨", + "in_progress": "진행 중", + "in_progress_desc": "활동적인 작업 진행 중", + "waiting": "대기 중", + "waiting_desc": "외부 입력 대기 중", + "done": "완료됨", + "done_desc": "끝났고 완료됨", + "cancelled": "취소됨", + "cancelled_desc": "완료되지 않을 것임" } } diff --git a/public/locales/nl/translation.json b/public/locales/nl/translation.json index 20b7ea3..6f53d32 100644 --- a/public/locales/nl/translation.json +++ b/public/locales/nl/translation.json @@ -151,7 +151,9 @@ "open": "Open", "completed": "Voltooid", "noCompletedTasksToday": "Geen voltooide taken vandaag.", - "markAsDone": "Mark as done" + "markAsDone": "Mark as done", + "notStarted": "Niet Begonnen", + "done": "Voltooid" }, "timeline": { "activityTimeline": "Activiteit Tijdlijn", @@ -820,7 +822,8 @@ "active": "Actief", "inactive": "Inactief", "all": "Alle", - "allAreas": "Alle gebieden" + "allAreas": "Alle gebieden", + "notCompleted": "Niet Voltooid" }, "selectState": "Selecteer Staat", "state": "Projectstaat", @@ -1342,5 +1345,19 @@ "title": "Opmerking:", "message": "E-mail- en pushmeldingen komen binnenkort. In-app en Telegram-meldingen zijn momenteel beschikbaar." } + }, + "projectStatus": { + "not_started": "Niet Begonnen", + "not_started_desc": "Vastgelegd maar nog niet begonnen", + "planned": "Gepland", + "planned_desc": "Afgebakend en klaar om te beginnen", + "in_progress": "Bezig", + "in_progress_desc": "Actief werk bezig", + "waiting": "Wachten", + "waiting_desc": "Wachten op externe input", + "done": "Voltooid", + "done_desc": "Afgerond en voltooid", + "cancelled": "Geannuleerd", + "cancelled_desc": "Zal niet worden voltooid" } -} \ No newline at end of file +} diff --git a/public/locales/no/translation.json b/public/locales/no/translation.json index 96500e9..eb9b449 100644 --- a/public/locales/no/translation.json +++ b/public/locales/no/translation.json @@ -151,7 +151,9 @@ "open": "Åpne", "completed": "Fullført", "noCompletedTasksToday": "Ingen fullførte oppgaver i dag.", - "markAsDone": "Mark as done" + "markAsDone": "Mark as done", + "notStarted": "Ikke startet", + "done": "Ferdig" }, "timeline": { "activityTimeline": "Aktivitetslinje", @@ -820,7 +822,8 @@ "active": "Aktiv", "inactive": "Inaktiv", "all": "Alle", - "allAreas": "Alle områder" + "allAreas": "Alle områder", + "notCompleted": "Ikke fullført" }, "selectState": "Velg tilstand", "state": "Prosjektstatus", @@ -1342,5 +1345,19 @@ "title": "Merk:", "message": "E-post og Push-varsler kommer snart. Varsler i appen og Telegram er for øyeblikket tilgjengelige." } + }, + "projectStatus": { + "not_started": "Ikke startet", + "not_started_desc": "Registrert, men ikke startet ennå", + "planned": "Planlagt", + "planned_desc": "Avgrenset og klar til å starte", + "in_progress": "Pågår", + "in_progress_desc": "Aktivt arbeid pågår", + "waiting": "Venter", + "waiting_desc": "Venter på ekstern input", + "done": "Fullført", + "done_desc": "Ferdig og avsluttet", + "cancelled": "Avbrutt", + "cancelled_desc": "Vil ikke bli fullført" } -} \ No newline at end of file +} diff --git a/public/locales/pl/translation.json b/public/locales/pl/translation.json index 41a672a..b277844 100644 --- a/public/locales/pl/translation.json +++ b/public/locales/pl/translation.json @@ -151,7 +151,9 @@ "open": "Otwórz", "completed": "Zakończone", "noCompletedTasksToday": "Brak ukończonych zadań dzisiaj.", - "markAsDone": "Mark as done" + "markAsDone": "Mark as done", + "notStarted": "Nie rozpoczęto", + "done": "Zrobione" }, "timeline": { "activityTimeline": "Oś czasu aktywności", @@ -820,7 +822,8 @@ "active": "Aktywne", "inactive": "Nieaktywne", "all": "Wszystkie", - "allAreas": "Wszystkie obszary" + "allAreas": "Wszystkie obszary", + "notCompleted": "Nie ukończono" }, "selectState": "Wybierz stan", "state": "Stan projektu", @@ -1342,5 +1345,19 @@ "title": "Uwaga:", "message": "Powiadomienia e-mailowe i push będą dostępne wkrótce. Powiadomienia w aplikacji i na Telegramie są obecnie dostępne." } + }, + "projectStatus": { + "not_started": "Nie rozpoczęto", + "not_started_desc": "Zarejestrowano, ale jeszcze nie rozpoczęto", + "planned": "Zaplanowane", + "planned_desc": "Zakres ustalony i gotowy do rozpoczęcia", + "in_progress": "W trakcie", + "in_progress_desc": "Aktywna praca w toku", + "waiting": "Oczekiwanie", + "waiting_desc": "Oczekiwanie na zewnętrzne dane", + "done": "Ukończono", + "done_desc": "Zakończono i wykonano", + "cancelled": "Anulowane", + "cancelled_desc": "Nie zostanie ukończone" } -} \ No newline at end of file +} diff --git a/public/locales/pt/translation.json b/public/locales/pt/translation.json index 9ecf956..1e8020d 100644 --- a/public/locales/pt/translation.json +++ b/public/locales/pt/translation.json @@ -151,7 +151,9 @@ "open": "Abrir", "completed": "Concluído", "noCompletedTasksToday": "Nenhuma tarefa concluída hoje.", - "markAsDone": "Mark as done" + "markAsDone": "Mark as done", + "notStarted": "Não Iniciado", + "done": "Concluído" }, "timeline": { "activityTimeline": "Linha do Tempo de Atividades", @@ -820,7 +822,8 @@ "active": "Ativo", "inactive": "Inativo", "all": "Todos", - "allAreas": "Todas as Áreas" + "allAreas": "Todas as Áreas", + "notCompleted": "Não Concluído" }, "selectState": "Selecionar Estado", "state": "Estado do Projeto", @@ -1342,5 +1345,19 @@ "title": "Nota:", "message": "Notificações por Email e Push estarão disponíveis em breve. Notificações no aplicativo e no Telegram estão atualmente disponíveis." } + }, + "projectStatus": { + "not_started": "Não Iniciado", + "not_started_desc": "Capturado, mas ainda não iniciado", + "planned": "Planejado", + "planned_desc": "Escopado e pronto para começar", + "in_progress": "Em Andamento", + "in_progress_desc": "Trabalho ativo em andamento", + "waiting": "Aguardando", + "waiting_desc": "Aguardando entrada externa", + "done": "Concluído", + "done_desc": "Finalizado e concluído", + "cancelled": "Cancelado", + "cancelled_desc": "Não será concluído" } -} \ No newline at end of file +} diff --git a/public/locales/ro/translation.json b/public/locales/ro/translation.json index 3b568bd..7da252b 100644 --- a/public/locales/ro/translation.json +++ b/public/locales/ro/translation.json @@ -151,7 +151,9 @@ "open": "Deschide", "completed": "Finalizat", "noCompletedTasksToday": "Nicio sarcină finalizată astăzi.", - "markAsDone": "Mark as done" + "markAsDone": "Mark as done", + "notStarted": "Nefăcut", + "done": "Finalizat" }, "timeline": { "activityTimeline": "Cronologia activităților", @@ -820,7 +822,8 @@ "active": "Activ", "inactive": "Inactiv", "all": "Toate", - "allAreas": "Toate zonele" + "allAreas": "Toate zonele", + "notCompleted": "Nefinalizat" }, "selectState": "Selectați Starea", "state": "Starea Proiectului", @@ -1342,5 +1345,19 @@ "title": "Notă:", "message": "Notificările prin Email și Push vor fi disponibile în curând. Notificările în aplicație și pe Telegram sunt disponibile în prezent." } + }, + "projectStatus": { + "not_started": "Nefăcut", + "not_started_desc": "Capturat, dar încă nefăcut", + "planned": "Planificat", + "planned_desc": "Definit și gata de început", + "in_progress": "În desfășurare", + "in_progress_desc": "Lucrări active în desfășurare", + "waiting": "Așteptând", + "waiting_desc": "Așteptând input extern", + "done": "Finalizat", + "done_desc": "Terminată și finalizată", + "cancelled": "Anulat", + "cancelled_desc": "Nu va fi finalizat" } -} \ No newline at end of file +} diff --git a/public/locales/ru/translation.json b/public/locales/ru/translation.json index 6fc413c..96a7271 100644 --- a/public/locales/ru/translation.json +++ b/public/locales/ru/translation.json @@ -151,7 +151,9 @@ "open": "Открыть", "completed": "Завершено", "noCompletedTasksToday": "Сегодня нет завершенных задач.", - "markAsDone": "Mark as done" + "markAsDone": "Mark as done", + "notStarted": "Не начато", + "done": "Выполнено" }, "timeline": { "activityTimeline": "Хронология активности", @@ -820,7 +822,8 @@ "active": "Активные", "inactive": "Неактивные", "all": "Все", - "allAreas": "Все области" + "allAreas": "Все области", + "notCompleted": "Не завершено" }, "selectState": "Выберите состояние", "state": "Состояние проекта", @@ -1342,5 +1345,19 @@ "title": "Примечание:", "message": "Уведомления по электронной почте и Push скоро будут доступны. Уведомления в приложении и Telegram в настоящее время доступны." } + }, + "projectStatus": { + "not_started": "Не начато", + "not_started_desc": "Зафиксировано, но еще не начато", + "planned": "Запланировано", + "planned_desc": "Определено и готово к началу", + "in_progress": "В процессе", + "in_progress_desc": "Активная работа ведется", + "waiting": "Ожидание", + "waiting_desc": "Ожидание внешнего ввода", + "done": "Завершено", + "done_desc": "Закончено и выполнено", + "cancelled": "Отменено", + "cancelled_desc": "Не будет завершено" } -} \ No newline at end of file +} diff --git a/public/locales/sl/translation.json b/public/locales/sl/translation.json index 681d8d1..7bb4f08 100644 --- a/public/locales/sl/translation.json +++ b/public/locales/sl/translation.json @@ -151,7 +151,9 @@ "open": "Odpri", "completed": "Dokončano", "noCompletedTasksToday": "Danes ni zaključenih nalog.", - "markAsDone": "Mark as done" + "markAsDone": "Mark as done", + "notStarted": "Niso začeli", + "done": "Dokončano" }, "timeline": { "activityTimeline": "Časovnica aktivnosti", @@ -820,7 +822,8 @@ "active": "Aktivno", "inactive": "Neaktivno", "all": "Vse", - "allAreas": "Vse področja" + "allAreas": "Vse področja", + "notCompleted": "Nedokončano" }, "selectState": "Izberite stanje", "state": "Stanje projekta", @@ -1342,5 +1345,19 @@ "title": "Opomba:", "message": "Obvestila po e-pošti in potisna obvestila kmalu prihajajo. Obvestila v aplikaciji in na Telegramu so trenutno na voljo." } + }, + "projectStatus": { + "not_started": "Niso začeli", + "not_started_desc": "Zajeto, a še ni začeto", + "planned": "Načrtovano", + "planned_desc": "Opredeljeno in pripravljeno za začetek", + "in_progress": "V teku", + "in_progress_desc": "Aktivno delo poteka", + "waiting": "Čaka", + "waiting_desc": "Čaka na zunanje vnose", + "done": "Dokončano", + "done_desc": "Končano in opravljeno", + "cancelled": "Preklicano", + "cancelled_desc": "Ne bo dokončano" } -} \ No newline at end of file +} diff --git a/public/locales/sv/translation.json b/public/locales/sv/translation.json index 29b58ea..82cc51e 100644 --- a/public/locales/sv/translation.json +++ b/public/locales/sv/translation.json @@ -151,7 +151,9 @@ "open": "Öppna", "completed": "Avslutad", "noCompletedTasksToday": "Inga slutförda uppgifter idag.", - "markAsDone": "Mark as done" + "markAsDone": "Mark as done", + "notStarted": "Ej påbörjad", + "done": "Utförd" }, "timeline": { "activityTimeline": "Aktivitetslinje", @@ -820,7 +822,8 @@ "active": "Aktiva", "inactive": "Inaktiva", "all": "Alla", - "allAreas": "Alla områden" + "allAreas": "Alla områden", + "notCompleted": "Ej slutförd" }, "selectState": "Välj status", "state": "Projektstatus", @@ -1342,5 +1345,19 @@ "title": "Notera:", "message": "E-post och push-notifikationer kommer snart. In-app och Telegram-notifikationer är för närvarande tillgängliga." } + }, + "projectStatus": { + "not_started": "Ej påbörjad", + "not_started_desc": "Fångad men ej påbörjad än", + "planned": "Planerad", + "planned_desc": "Definierad och redo att starta", + "in_progress": "Pågående", + "in_progress_desc": "Aktivt arbete pågår", + "waiting": "Väntar", + "waiting_desc": "Väntar på extern input", + "done": "Slutförd", + "done_desc": "Avslutad och klar", + "cancelled": "Avbruten", + "cancelled_desc": "Kommer inte att slutföras" } -} \ No newline at end of file +} diff --git a/public/locales/tr/translation.json b/public/locales/tr/translation.json index cfc91e7..e1cd8e8 100644 --- a/public/locales/tr/translation.json +++ b/public/locales/tr/translation.json @@ -151,7 +151,9 @@ "open": "Aç", "completed": "Tamamlandı", "noCompletedTasksToday": "Bugün tamamlanan görev yok.", - "markAsDone": "Mark as done" + "markAsDone": "Mark as done", + "notStarted": "Başlanmadı", + "done": "Tamamlandı" }, "timeline": { "activityTimeline": "Etkinlik Zaman Çizelgesi", @@ -820,7 +822,8 @@ "active": "Aktif", "inactive": "Pasif", "all": "Hepsi", - "allAreas": "Tüm Alanlar" + "allAreas": "Tüm Alanlar", + "notCompleted": "Tamamlanmadı" }, "selectState": "Durum Seç", "state": "Proje Durumu", @@ -1342,5 +1345,19 @@ "title": "Not:", "message": "E-posta ve Push bildirimleri yakında geliyor. Uygulama içi ve Telegram bildirimleri şu anda mevcuttur." } + }, + "projectStatus": { + "not_started": "Başlanmadı", + "not_started_desc": "Kaydedildi ama henüz başlanmadı", + "planned": "Planlandı", + "planned_desc": "Kapsam belirlendi ve başlamaya hazır", + "in_progress": "Devam Ediyor", + "in_progress_desc": "Aktif çalışma yapılıyor", + "waiting": "Bekliyor", + "waiting_desc": "Dışsal girdi bekleniyor", + "done": "Tamamlandı", + "done_desc": "Bitirildi ve tamamlandı", + "cancelled": "İptal Edildi", + "cancelled_desc": "Tamamlanmayacak" } -} \ No newline at end of file +} diff --git a/public/locales/ua/translation.json b/public/locales/ua/translation.json index 7d0ebe1..f580c9d 100644 --- a/public/locales/ua/translation.json +++ b/public/locales/ua/translation.json @@ -151,7 +151,9 @@ "open": "Відкрити", "completed": "Завершено", "noCompletedTasksToday": "Сьогодні немає завершених завдань.", - "markAsDone": "Mark as done" + "markAsDone": "Mark as done", + "notStarted": "Не розпочато", + "done": "Завершено" }, "timeline": { "activityTimeline": "Хронологія Активності", @@ -209,7 +211,8 @@ "active": "Активні", "inactive": "Неактивні", "all": "Всі", - "allAreas": "Всі області" + "allAreas": "Всі області", + "notCompleted": "Не завершено" }, "active": "Активні", "inactive": "Неактивні", @@ -1342,5 +1345,19 @@ "title": "Примітка:", "message": "Сповіщення електронною поштою та Push скоро з'являться. Сповіщення в додатку та Telegram наразі доступні." } + }, + "projectStatus": { + "not_started": "Не розпочато", + "not_started_desc": "Зафіксовано, але ще не розпочато", + "planned": "Заплановано", + "planned_desc": "Окреслено і готово до початку", + "in_progress": "В процесі", + "in_progress_desc": "Активна робота триває", + "waiting": "Очікування", + "waiting_desc": "Очікування на зовнішній внесок", + "done": "Завершено", + "done_desc": "Закінчено і виконано", + "cancelled": "Скасовано", + "cancelled_desc": "Не буде завершено" } -} \ No newline at end of file +} diff --git a/public/locales/vi/translation.json b/public/locales/vi/translation.json index e54a335..df89180 100644 --- a/public/locales/vi/translation.json +++ b/public/locales/vi/translation.json @@ -151,7 +151,9 @@ "open": "Mở", "completed": "Đã hoàn thành", "noCompletedTasksToday": "Không có nhiệm vụ hoàn thành hôm nay.", - "markAsDone": "Mark as done" + "markAsDone": "Mark as done", + "notStarted": "Chưa bắt đầu", + "done": "Đã hoàn thành" }, "timeline": { "activityTimeline": "Dòng Thời Gian Hoạt Động", @@ -820,7 +822,8 @@ "active": "Đang hoạt động", "inactive": "Không hoạt động", "all": "Tất cả", - "allAreas": "Tất cả các khu vực" + "allAreas": "Tất cả các khu vực", + "notCompleted": "Chưa hoàn thành" }, "selectState": "Chọn Trạng Thái", "state": "Trạng Thái Dự Án", @@ -1342,5 +1345,19 @@ "title": "Lưu ý:", "message": "Thông báo Email và Push sẽ sớm có. Thông báo trong ứng dụng và Telegram hiện đang có sẵn." } + }, + "projectStatus": { + "not_started": "Chưa bắt đầu", + "not_started_desc": "Đã ghi nhận nhưng chưa bắt đầu", + "planned": "Đã lên kế hoạch", + "planned_desc": "Đã xác định và sẵn sàng để bắt đầu", + "in_progress": "Đang tiến hành", + "in_progress_desc": "Công việc đang diễn ra", + "waiting": "Đang chờ", + "waiting_desc": "Đang chờ thông tin từ bên ngoài", + "done": "Đã hoàn thành", + "done_desc": "Đã hoàn tất và xong", + "cancelled": "Đã hủy", + "cancelled_desc": "Sẽ không được hoàn thành" } -} \ No newline at end of file +} diff --git a/public/locales/zh/translation.json b/public/locales/zh/translation.json index a3045ac..dfbc840 100644 --- a/public/locales/zh/translation.json +++ b/public/locales/zh/translation.json @@ -151,7 +151,9 @@ "open": "打开", "completed": "已完成", "noCompletedTasksToday": "今天没有完成的任务。", - "markAsDone": "Mark as done" + "markAsDone": "Mark as done", + "notStarted": "未开始", + "done": "完成" }, "timeline": { "activityTimeline": "活动时间线", @@ -820,7 +822,8 @@ "active": "活动", "inactive": "非活动", "all": "所有", - "allAreas": "所有区域" + "allAreas": "所有区域", + "notCompleted": "未完成" }, "selectState": "选择状态", "state": "项目状态", @@ -1342,5 +1345,19 @@ "title": "注意:", "message": "电子邮件和推送通知即将推出。应用内和 Telegram 通知目前可用。" } + }, + "projectStatus": { + "not_started": "未开始", + "not_started_desc": "已捕获但尚未开始", + "planned": "已规划", + "planned_desc": "已确定范围并准备开始", + "in_progress": "进行中", + "in_progress_desc": "正在进行的工作", + "waiting": "等待中", + "waiting_desc": "等待外部输入", + "done": "已完成", + "done_desc": "已完成并结束", + "cancelled": "已取消", + "cancelled_desc": "将不会完成" } }