mirror of
https://github.com/ttusk/leif.git
synced 2026-07-22 08:32:51 +00:00
refactor: centralize wall-link id template in wallLinkKey
The '${contestId}-notice' / '${contestId}-exam' id template was
duplicated in WallTab and the Seeder. Extract wallLinkKey(contestId,
kind) in the Wall module, import it at both call sites, and add three
tests covering format stability (regression for the 'second save
replaces first save' behaviour the form relies on).
This commit is contained in:
parent
b16c42b3d3
commit
0e9f697c1b
5 changed files with 42 additions and 9 deletions
11
sample-vault/.obsidian/plugins/leif/main.js
vendored
11
sample-vault/.obsidian/plugins/leif/main.js
vendored
|
|
@ -1086,6 +1086,9 @@ var Wall = class {
|
|||
this.notes = notes;
|
||||
}
|
||||
};
|
||||
function wallLinkKey(contestId, kind) {
|
||||
return `${contestId}-${kind}`;
|
||||
}
|
||||
|
||||
// src/domain/entities/Contest.ts
|
||||
var Contest = class {
|
||||
|
|
@ -2244,10 +2247,10 @@ async function seedTceSpDemo(dataStore) {
|
|||
contestId: contest.id,
|
||||
wall: {
|
||||
noticeLinks: [
|
||||
{ id: `${contest.id}-notice`, label: contestSpec.wall.noticeLabel, url: contestSpec.wall.noticeUrl }
|
||||
{ id: wallLinkKey(contest.id, "notice"), label: contestSpec.wall.noticeLabel, url: contestSpec.wall.noticeUrl }
|
||||
],
|
||||
examLinks: [
|
||||
{ id: `${contest.id}-exam`, label: contestSpec.wall.examLabel, url: contestSpec.wall.examUrl }
|
||||
{ id: wallLinkKey(contest.id, "exam"), label: contestSpec.wall.examLabel, url: contestSpec.wall.examUrl }
|
||||
],
|
||||
subjectSnapshots: seededSubjects.map((subject, index) => ({
|
||||
subjectId: subject.id,
|
||||
|
|
@ -4280,14 +4283,14 @@ var WallTab = class {
|
|||
try {
|
||||
const noticeLink = noticeUrl.value ? [
|
||||
{
|
||||
id: `${activeContest.id}-notice`,
|
||||
id: wallLinkKey(activeContest.id, "notice"),
|
||||
label: noticeLabel.value || "Edital",
|
||||
url: noticeUrl.value
|
||||
}
|
||||
] : [];
|
||||
const examLink = examUrl.value ? [
|
||||
{
|
||||
id: `${activeContest.id}-exam`,
|
||||
id: wallLinkKey(activeContest.id, "exam"),
|
||||
label: examLabel.value || "Prova",
|
||||
url: examUrl.value
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,4 +41,18 @@ export class Wall {
|
|||
public readonly subjectSnapshots: WallSubjectSnapshot[] = [],
|
||||
public readonly notes?: string
|
||||
) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* The kinds of single-link slots the wall form manages.
|
||||
*/
|
||||
export type WallLinkKind = "notice" | "exam";
|
||||
|
||||
/**
|
||||
* Builds the stable identifier used for the wall's single notice/exam link.
|
||||
* The wall form overwrites the link on every save, so a deterministic id
|
||||
* keeps the array at length 0 or 1 instead of appending duplicates.
|
||||
*/
|
||||
export function wallLinkKey(contestId: string, kind: WallLinkKind): string {
|
||||
return `${contestId}-${kind}`;
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ import type { StudyItem } from "@/domain/entities/StudyItem";
|
|||
import { StudySessionType } from "@/domain/entities/StudySession";
|
||||
import type { Subject } from "@/domain/entities/Subject";
|
||||
import type { Topic } from "@/domain/entities/Topic";
|
||||
import { wallLinkKey } from "@/domain/entities/Wall";
|
||||
import { EntityRepositoryFactory } from "@/infrastructure/persistence/EntityRepositoryFactory";
|
||||
|
||||
export interface SeededContest {
|
||||
|
|
@ -469,10 +470,10 @@ export async function seedTceSpDemo(dataStore: PluginDataStore): Promise<SeededC
|
|||
contestId: contest.id,
|
||||
wall: {
|
||||
noticeLinks: [
|
||||
{ id: `${contest.id}-notice`, label: contestSpec.wall.noticeLabel, url: contestSpec.wall.noticeUrl }
|
||||
{ id: wallLinkKey(contest.id, "notice"), label: contestSpec.wall.noticeLabel, url: contestSpec.wall.noticeUrl }
|
||||
],
|
||||
examLinks: [
|
||||
{ id: `${contest.id}-exam`, label: contestSpec.wall.examLabel, url: contestSpec.wall.examUrl }
|
||||
{ id: wallLinkKey(contest.id, "exam"), label: contestSpec.wall.examLabel, url: contestSpec.wall.examUrl }
|
||||
],
|
||||
subjectSnapshots: seededSubjects.map((subject, index) => ({
|
||||
subjectId: subject.id,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import type { PluginDataStore } from "@/application/ports/PluginDataStore";
|
||||
import { UpdateContestWallUseCase } from "@/application/use-cases/UpdateContestWallUseCase";
|
||||
import type { LeifPluginData } from "@/domain/types/LeifPluginData";
|
||||
import { wallLinkKey } from "@/domain/entities/Wall";
|
||||
import { DomHelpers } from "@/ui/view/shared/DomHelpers";
|
||||
import { EntityRepositoryFactory } from "@/infrastructure/persistence/EntityRepositoryFactory";
|
||||
|
||||
|
|
@ -71,7 +72,7 @@ export class WallTab {
|
|||
const noticeLink = noticeUrl.value
|
||||
? [
|
||||
{
|
||||
id: `${activeContest.id}-notice`,
|
||||
id: wallLinkKey(activeContest.id, "notice"),
|
||||
label: noticeLabel.value || "Edital",
|
||||
url: noticeUrl.value
|
||||
}
|
||||
|
|
@ -81,7 +82,7 @@ export class WallTab {
|
|||
const examLink = examUrl.value
|
||||
? [
|
||||
{
|
||||
id: `${activeContest.id}-exam`,
|
||||
id: wallLinkKey(activeContest.id, "exam"),
|
||||
label: examLabel.value || "Prova",
|
||||
url: examUrl.value
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { Topic } from "@/domain/entities/Topic";
|
|||
import { StudySession } from "@/domain/entities/StudySession";
|
||||
import { QuestionNotebook } from "@/domain/entities/QuestionNotebook";
|
||||
import { ResourceReference } from "@/domain/entities/ResourceReference";
|
||||
import { WallLink, WallSubjectSnapshot, Wall } from "@/domain/entities/Wall";
|
||||
import { WallLink, WallSubjectSnapshot, Wall, wallLinkKey } from "@/domain/entities/Wall";
|
||||
import { ValidationError } from "@/domain/errors/DomainErrors";
|
||||
|
||||
describe("Entity Classes", () => {
|
||||
|
|
@ -142,6 +142,20 @@ describe("Entity Classes", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("wallLinkKey", () => {
|
||||
it("builds a stable notice-link id from the contest id", () => {
|
||||
expect(wallLinkKey("c-1", "notice")).toBe("c-1-notice");
|
||||
});
|
||||
|
||||
it("builds a stable exam-link id from the contest id", () => {
|
||||
expect(wallLinkKey("c-1", "exam")).toBe("c-1-exam");
|
||||
});
|
||||
|
||||
it("returns the same id for the same contest + kind", () => {
|
||||
expect(wallLinkKey("c-1", "notice")).toBe(wallLinkKey("c-1", "notice"));
|
||||
});
|
||||
});
|
||||
|
||||
describe("ContestState", () => {
|
||||
it("creates a valid state", () => {
|
||||
const state = new ContestState("c-1", "s-1", "i-1");
|
||||
|
|
|
|||
Loading…
Reference in a new issue