diff --git a/backend/handlers/cardstags.go b/backend/handlers/cardstags.go index 1079368..eb66729 100644 --- a/backend/handlers/cardstags.go +++ b/backend/handlers/cardstags.go @@ -78,8 +78,9 @@ func CreateCardTag(c *fiber.Ctx) error { } publish(fiber.Map{ - "object": "cardtag", + "object": "cardTag", "action": "create", + "card_id": cardID, "data": cardtag, "X-Request-Source": source, }); @@ -172,9 +173,10 @@ func DeleteCardTag(c *fiber.Ctx) error { } publish(fiber.Map{ - "object": "cardtag", + "object": "cardTag", "action": "delete", - "id": cardID, + "card_id": cardID, + "tag_id": tagID, "X-Request-Source": source, }); @@ -272,7 +274,7 @@ func UpdateCardTag(c *fiber.Ctx) error { } publish(fiber.Map{ - "object": "cardtag", + "object": "cardTag", "action": "update", "card_id": cardID, "tag_id": tagID, diff --git a/backend/handlers/tags.go b/backend/handlers/tags.go index 3b0653e..a7807cc 100644 --- a/backend/handlers/tags.go +++ b/backend/handlers/tags.go @@ -48,7 +48,7 @@ func CreateTag(c *fiber.Ctx) error { } publish(fiber.Map{ - "object": "tag", + "object": "projectTag", "action": "create", "data": tag, "X-Request-Source": source, @@ -106,7 +106,7 @@ func DeleteTag(c *fiber.Ctx) error { } publish(fiber.Map{ - "object": "tag", + "object": "projectTag", "action": "delete", "id": id, "X-Request-Source": source, @@ -149,7 +149,7 @@ func UpdateTag(c *fiber.Ctx) error { } publish(fiber.Map{ - "object": "tag", + "object": "projectTag", "action": "update", "id": id, "changes": tag, @@ -202,7 +202,7 @@ func CreateTagOption(c *fiber.Ctx) error { } publish(fiber.Map{ - "object": "tagoption", + "object": "tagOption", "action": "create", "data": option, "X-Request-Source": source, @@ -284,7 +284,7 @@ func DeleteTagOption(c *fiber.Ctx) error { } publish(fiber.Map{ - "object": "tagoption", + "object": "tagOption", "action": "delete", "tag_id": tagID, "option_id": optionID, @@ -344,7 +344,7 @@ func UpdateTagOption(c *fiber.Ctx) error { } publish(fiber.Map{ - "object": "tagoption", + "object": "tagOption", "action": "update", "tag_id": tagID, "option_id": optionID, diff --git a/frontend/src/lib/types/Card.ts b/frontend/src/lib/types/Card.ts index 8608e7b..5c03b30 100644 --- a/frontend/src/lib/types/Card.ts +++ b/frontend/src/lib/types/Card.ts @@ -152,7 +152,7 @@ export default class Card { return true; } - updateFromDict(dict: any) { + parseUpdate(dict: any) { if (dict.project_id && dict.project_id !== this._project.id) { this._project = Project.fromId(dict.project_id) as Project; } @@ -160,6 +160,31 @@ export default class Card { if (dict.content) this._content = dict.content; } + static parseDelete(id: any) { + cards.update((cards) => cards.filter((c) => c.id !== id)); + } + + parseTag(dict: any) { + const cardTag = CardTag.parse(dict, this); + if (!cardTag) return; + + this._cardTags = [...this._cardTags, cardTag]; + } + + parseTagUpdate(dict: any) { + const cardTag = this._cardTags.find((ct) => ct.projectTag.id === dict.tag_id); + if (!cardTag) { + toastAlert('Failed to parse card tag update: card tag not found'); + return; + } + + cardTag.parseUpdate(dict); + } + + parseTagDelete(id: any) { + this._cardTags = this._cardTags.filter((ct) => ct.projectTag.id !== id); + } + static parse(json: any): Card | null; static parse(json: any, project: Project | null | undefined): Card | null; diff --git a/frontend/src/lib/types/CardTag.ts b/frontend/src/lib/types/CardTag.ts index 10be45f..4680369 100644 --- a/frontend/src/lib/types/CardTag.ts +++ b/frontend/src/lib/types/CardTag.ts @@ -71,6 +71,35 @@ export default class CardTag { return true; } + parseUpdate(dict: any) { + if (dict.card_id && dict.card_id !== this._card.id) { + toastAlert('Failed to parse card tag update: card id mismatch'); + return; + } + + if (dict.tag_id && dict.tag_id !== this._projectTag.id) { + toastAlert('Failed to parse card tag update: projectTag id mismatch'); + return; + } + + if (dict.option_id) { + const option = this._projectTag.options.find((option) => option.id === dict.option_id); + if (!option) { + toastAlert('Failed to parse card tag update: option not found'); + return; + } + this._option = option; + } else if (this._option) { + this._option = null; + } + + if (dict.value) { + this._value = dict.value; + } else if (this._value) { + this._value = null; + } + } + static parse(json: any): CardTag | null; static parse(json: any, card: Card | null | undefined): CardTag | null; diff --git a/frontend/src/lib/types/Project.ts b/frontend/src/lib/types/Project.ts index 0068997..9eac673 100644 --- a/frontend/src/lib/types/Project.ts +++ b/frontend/src/lib/types/Project.ts @@ -65,10 +65,14 @@ export default class Project { return true; } - updateFromDict(dict: any) { + parseUpdate(dict: any) { if (dict.title) this._title = dict.title; } + static parseDelete(id: any) { + projects.update((projects) => projects.filter((project) => project.id !== id)); + } + static parse(json: any): Project | null { if (!json) return null; diff --git a/frontend/src/lib/utils/webSocketManager.ts b/frontend/src/lib/utils/webSocketManager.ts index 96d81ea..7dcf8ec 100644 --- a/frontend/src/lib/utils/webSocketManager.ts +++ b/frontend/src/lib/utils/webSocketManager.ts @@ -1,4 +1,5 @@ import Card, { cards } from '$lib/types/Card'; +import CardTag from '$lib/types/CardTag'; import Project, { projects } from '$lib/types/Project'; import ProjectTag, { projectTags } from '$lib/types/ProjectTag'; import View, { views } from '$lib/types/View'; @@ -78,77 +79,99 @@ export default class WebSocketManager { } function applyMessage(data: any) { - switch (data.object) { - case 'project': - applyProject(data); - break; - case 'card': - applyCard(data); - break; - case 'view': - applyView(data); - break; - case 'projectTag': - applyProjectTag(data); - break; - default: - console.log('Unknown object:', data); + console.debug('WebSocket message:', data); + if (!data.object) { + toastWarning('Failed to parse WebSocket message: missing object'); + return; } + + if (!data.action) { + toastWarning('Failed to parse WebSocket message: missing action'); + return; + } + + if (data.object === 'project') applyProject(data); + else if (data.object === 'cardTag') applyCardTag(data); + else if (data.object === 'card') applyCard(data); + else if (data.object === 'view') applyView(data); + else if (data.object === 'projectTag') applyProjectTag(data); + else if (data.object === 'filter') applyFilter(data); + else toastWarning('Failed to parse WebSocket message: unknown object'); } function applyProject(data: any) { - switch (data.action) { - case 'create': - Project.parse(data.data); - case 'update': - get(projects) - .find((p) => p.id === data.id) - ?.updateFromDict(data.changes); - projects.reload(); - break; - case 'delete': - projects.set(get(projects).filter((p) => p.id !== data.id)); - break; + if (data.action === 'create') { + Project.parse(data.data); + return; } + if (data.action === 'delete') { + Project.parseDelete(data.id); + return; + } + + const project = Project.fromId(data.id); + if (!project) { + toastWarning('Failed to parse project update: project not found'); + return; + } + + if (data.action !== 'update') { + toastWarning('Failed to parse project update: unknown action'); + return; + } + + project.parseUpdate(data.changes); + projects.reload(); } function applyCard(data: any) { - switch (data.action) { - case 'create': - Card.parse(data.data); - break; - case 'update': - get(cards) - .find((c) => c.id === data.id) - ?.updateFromDict(data.changes); - cards.reload(); - break; - case 'delete': - cards.set(get(cards).filter((c) => c.id !== data.id)); - break; + if (data.action === 'create') { + Card.parse(data.data); + return; } + if (data.action === 'delete') { + Card.parseDelete(data.id); + return; + } + + const card = Card.fromId(data.id); + if (!card) { + toastWarning('Failed to parse card update: card not found'); + return; + } + + if (data.action !== 'update') { + toastWarning('Failed to parse card update: unknown action'); + return; + } + + card.parseUpdate(data.changes); + cards.reload(); } -function applyView(data: any) { - switch (data.action) { - case 'create': - case 'update': - View.parse(data.value); - break; - case 'delete': - views.set(get(views).filter((v) => v.id !== data.id)); - break; +function applyCardTag(data: any) { + const card = Card.fromId(data.card_id); + if (!card) { + toastWarning('Failed to parse card tag update: card not found'); + return; } + + if (data.action === 'create') { + card.parseTag(data.data); + } else if (data.action === 'update') { + card.parseTagUpdate(data.changes); + } else if (data.action === 'delete') { + card.parseTagDelete(data.tag_id); + } else { + toastWarning('Failed to parse card tag update: unknown action'); + return; + } + + cards.reload(); } -function applyProjectTag(data: any) { - switch (data.action) { - case 'create': - case 'update': - ProjectTag.parse(data.value); - break; - case 'delete': - projectTags.set(get(projectTags).filter((t) => t.id !== data.id)); - break; - } -} +function applyView(data: any) {} + +function applyProjectTag(data: any) {} + +function applyFilter(data: any) {}