Fix workflow gitea action pour e2e (tests automatisés via playwright) + correction d'une incohérence dans l'API coté java. Ajout d'autres tests utilisateur
Some checks failed
E2E Tests / e2e (push) Failing after 2m31s
Some checks failed
E2E Tests / e2e (push) Failing after 2m31s
This commit is contained in:
@@ -41,9 +41,20 @@ jobs:
|
||||
run: |
|
||||
docker compose -f docker-compose.yml -f docker-compose.e2e.yml up -d --build
|
||||
|
||||
- name: Attach runner to compose network
|
||||
run: |
|
||||
NET=$(docker network ls --format '{{.Name}}' | grep -E '(^|_)loremind(_|$)' | grep -i default | head -1)
|
||||
if [ -z "$NET" ]; then
|
||||
echo "Compose network not found" >&2
|
||||
docker network ls
|
||||
exit 1
|
||||
fi
|
||||
echo "Connecting $(hostname) to network $NET"
|
||||
docker network connect "$NET" "$(hostname)"
|
||||
|
||||
- name: Wait for web to be ready
|
||||
run: |
|
||||
timeout 180 bash -c 'until curl -sf http://localhost:8081 > /dev/null; do echo "waiting..."; sleep 3; done'
|
||||
timeout 180 bash -c 'until curl -sf http://web/ > /dev/null; do echo "waiting..."; sleep 3; done'
|
||||
|
||||
- name: Install web deps
|
||||
working-directory: web
|
||||
@@ -56,7 +67,7 @@ jobs:
|
||||
- name: Run Playwright tests
|
||||
working-directory: web
|
||||
env:
|
||||
E2E_BASE_URL: http://localhost:8081
|
||||
E2E_BASE_URL: http://web
|
||||
CI: 'true'
|
||||
run: npm run e2e
|
||||
|
||||
|
||||
@@ -40,17 +40,11 @@ public class ArcController {
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public ResponseEntity<List<ArcDTO>> getAllArcs() {
|
||||
List<Arc> arcs = arcService.getAllArcs();
|
||||
List<ArcDTO> arcDTOs = arcs.stream()
|
||||
.map(arcMapper::toDTO)
|
||||
.collect(Collectors.toList());
|
||||
return ResponseEntity.ok(arcDTOs);
|
||||
}
|
||||
|
||||
@GetMapping("/campaign/{campaignId}")
|
||||
public ResponseEntity<List<ArcDTO>> getArcsByCampaignId(@PathVariable String campaignId) {
|
||||
List<Arc> arcs = arcService.getArcsByCampaignId(campaignId);
|
||||
public ResponseEntity<List<ArcDTO>> getAllArcs(
|
||||
@RequestParam(value = "campaignId", required = false) String campaignId) {
|
||||
List<Arc> arcs = (campaignId != null && !campaignId.isBlank())
|
||||
? arcService.getArcsByCampaignId(campaignId)
|
||||
: arcService.getAllArcs();
|
||||
List<ArcDTO> arcDTOs = arcs.stream()
|
||||
.map(arcMapper::toDTO)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
@@ -40,17 +40,11 @@ public class ChapterController {
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public ResponseEntity<List<ChapterDTO>> getAllChapters() {
|
||||
List<Chapter> chapters = chapterService.getAllChapters();
|
||||
List<ChapterDTO> chapterDTOs = chapters.stream()
|
||||
.map(chapterMapper::toDTO)
|
||||
.collect(Collectors.toList());
|
||||
return ResponseEntity.ok(chapterDTOs);
|
||||
}
|
||||
|
||||
@GetMapping("/arc/{arcId}")
|
||||
public ResponseEntity<List<ChapterDTO>> getChaptersByArcId(@PathVariable String arcId) {
|
||||
List<Chapter> chapters = chapterService.getChaptersByArcId(arcId);
|
||||
public ResponseEntity<List<ChapterDTO>> getAllChapters(
|
||||
@RequestParam(value = "arcId", required = false) String arcId) {
|
||||
List<Chapter> chapters = (arcId != null && !arcId.isBlank())
|
||||
? chapterService.getChaptersByArcId(arcId)
|
||||
: chapterService.getAllChapters();
|
||||
List<ChapterDTO> chapterDTOs = chapters.stream()
|
||||
.map(chapterMapper::toDTO)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
@@ -40,17 +40,11 @@ public class SceneController {
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public ResponseEntity<List<SceneDTO>> getAllScenes() {
|
||||
List<Scene> scenes = sceneService.getAllScenes();
|
||||
List<SceneDTO> sceneDTOs = scenes.stream()
|
||||
.map(sceneMapper::toDTO)
|
||||
.collect(Collectors.toList());
|
||||
return ResponseEntity.ok(sceneDTOs);
|
||||
}
|
||||
|
||||
@GetMapping("/chapter/{chapterId}")
|
||||
public ResponseEntity<List<SceneDTO>> getScenesByChapterId(@PathVariable String chapterId) {
|
||||
List<Scene> scenes = sceneService.getScenesByChapterId(chapterId);
|
||||
public ResponseEntity<List<SceneDTO>> getAllScenes(
|
||||
@RequestParam(value = "chapterId", required = false) String chapterId) {
|
||||
List<Scene> scenes = (chapterId != null && !chapterId.isBlank())
|
||||
? sceneService.getScenesByChapterId(chapterId)
|
||||
: sceneService.getAllScenes();
|
||||
List<SceneDTO> sceneDTOs = scenes.stream()
|
||||
.map(sceneMapper::toDTO)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
@@ -79,7 +79,7 @@ class ArcControllerTest {
|
||||
@Test
|
||||
void getByCampaign_pathVariant() throws Exception {
|
||||
arcRepository.save(Arc.builder().campaignId(campaignId).name("A").order(0).build());
|
||||
mockMvc.perform(get("/api/arcs/campaign/{id}", campaignId))
|
||||
mockMvc.perform(get("/api/arcs").param("campaignId", campaignId))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$").isArray());
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ class ChapterControllerTest {
|
||||
@Test
|
||||
void getByArc_pathVariant() throws Exception {
|
||||
chapterRepository.save(Chapter.builder().arcId(arcId).name("A").order(0).build());
|
||||
mockMvc.perform(get("/api/chapters/arc/{id}", arcId))
|
||||
mockMvc.perform(get("/api/chapters").param("arcId", arcId))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$").isArray());
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ class SceneControllerTest {
|
||||
@Test
|
||||
void getByChapter_pathVariant() throws Exception {
|
||||
sceneRepository.save(Scene.builder().chapterId(chapterId).name("A").order(0).build());
|
||||
mockMvc.perform(get("/api/scenes/chapter/{id}", chapterId))
|
||||
mockMvc.perform(get("/api/scenes").param("chapterId", chapterId))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$").isArray());
|
||||
}
|
||||
|
||||
@@ -36,6 +36,42 @@ export async function deleteLore(request: APIRequestContext, loreId: string): Pr
|
||||
await request.delete(`/api/lores/${loreId}`).catch(() => undefined);
|
||||
}
|
||||
|
||||
export async function getLoreById(
|
||||
request: APIRequestContext,
|
||||
loreId: string,
|
||||
): Promise<{ id: string; name: string; description: string }> {
|
||||
const res = await request.get(`/api/lores/${loreId}`);
|
||||
expect(res.ok(), `GET /api/lores/${loreId} -> ${res.status()}`).toBeTruthy();
|
||||
return res.json();
|
||||
}
|
||||
|
||||
export async function getArcsForCampaign(
|
||||
request: APIRequestContext,
|
||||
campaignId: string,
|
||||
): Promise<Array<{ id: string; name: string; campaignId: string }>> {
|
||||
const res = await request.get(`/api/arcs?campaignId=${campaignId}`);
|
||||
expect(res.ok(), `GET /api/arcs -> ${res.status()}`).toBeTruthy();
|
||||
return res.json();
|
||||
}
|
||||
|
||||
export async function getChaptersForArc(
|
||||
request: APIRequestContext,
|
||||
arcId: string,
|
||||
): Promise<Array<{ id: string; name: string; arcId: string }>> {
|
||||
const res = await request.get(`/api/chapters?arcId=${arcId}`);
|
||||
expect(res.ok(), `GET /api/chapters -> ${res.status()}`).toBeTruthy();
|
||||
return res.json();
|
||||
}
|
||||
|
||||
export async function getScenesForChapter(
|
||||
request: APIRequestContext,
|
||||
chapterId: string,
|
||||
): Promise<Array<{ id: string; name: string; chapterId: string }>> {
|
||||
const res = await request.get(`/api/scenes?chapterId=${chapterId}`);
|
||||
expect(res.ok(), `GET /api/scenes -> ${res.status()}`).toBeTruthy();
|
||||
return res.json();
|
||||
}
|
||||
|
||||
export async function getTemplatesForLore(
|
||||
request: APIRequestContext,
|
||||
loreId: string,
|
||||
|
||||
50
web/e2e/tests/campaign/arc-create.spec.ts
Normal file
50
web/e2e/tests/campaign/arc-create.spec.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import {
|
||||
seedCampaign,
|
||||
deleteCampaign,
|
||||
getArcById,
|
||||
type SeededCampaign,
|
||||
} from '../../fixtures/api';
|
||||
|
||||
test.describe('Arc creation', () => {
|
||||
let campaign: SeededCampaign;
|
||||
|
||||
test.beforeEach(async ({ request }) => {
|
||||
campaign = await seedCampaign(request);
|
||||
});
|
||||
|
||||
test.afterEach(async ({ request }) => {
|
||||
if (campaign?.id) await deleteCampaign(request, campaign.id);
|
||||
});
|
||||
|
||||
test('creates an arc and redirects to its view', async ({ page, request }) => {
|
||||
const arcName = `Arc ${Date.now()}`;
|
||||
const description = 'Synopsis test';
|
||||
|
||||
await page.goto(`/campaigns/${campaign.id}/arcs/create`);
|
||||
await expect(page.getByRole('heading', { name: /Créer un nouvel arc/i })).toBeVisible();
|
||||
|
||||
await page.getByLabel(/Nom de l'arc/i).fill(arcName);
|
||||
await page.getByLabel(/Description/i).fill(description);
|
||||
|
||||
await page.getByRole('button', { name: /^Créer l'arc$/i }).click();
|
||||
|
||||
await expect(page).toHaveURL(new RegExp(`/campaigns/${campaign.id}/arcs/\\d+$`));
|
||||
|
||||
const createdId = page.url().match(/\/arcs\/(\d+)$/)?.[1];
|
||||
expect(createdId).toBeTruthy();
|
||||
const persisted = await getArcById(request, createdId!);
|
||||
expect(persisted.name).toBe(arcName);
|
||||
expect(persisted.description).toBe(description);
|
||||
});
|
||||
|
||||
test('submit is disabled when name is empty', async ({ page }) => {
|
||||
await page.goto(`/campaigns/${campaign.id}/arcs/create`);
|
||||
|
||||
const submit = page.getByRole('button', { name: /^Créer l'arc$/i });
|
||||
await expect(submit).toBeDisabled();
|
||||
|
||||
await page.getByLabel(/Nom de l'arc/i).fill('Quelque chose');
|
||||
await expect(submit).toBeEnabled();
|
||||
});
|
||||
});
|
||||
54
web/e2e/tests/campaign/chapter-create.spec.ts
Normal file
54
web/e2e/tests/campaign/chapter-create.spec.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import {
|
||||
seedCampaign,
|
||||
seedArc,
|
||||
deleteCampaign,
|
||||
getChapterById,
|
||||
type SeededCampaign,
|
||||
type SeededArc,
|
||||
} from '../../fixtures/api';
|
||||
|
||||
test.describe('Chapter creation', () => {
|
||||
let campaign: SeededCampaign;
|
||||
let arc: SeededArc;
|
||||
|
||||
test.beforeEach(async ({ request }) => {
|
||||
campaign = await seedCampaign(request);
|
||||
arc = await seedArc(request, { campaignId: campaign.id });
|
||||
});
|
||||
|
||||
test.afterEach(async ({ request }) => {
|
||||
if (campaign?.id) await deleteCampaign(request, campaign.id);
|
||||
});
|
||||
|
||||
test('creates a chapter and redirects to its view', async ({ page, request }) => {
|
||||
const chapterName = `Chapitre ${Date.now()}`;
|
||||
|
||||
await page.goto(`/campaigns/${campaign.id}/arcs/${arc.id}/chapters/create`);
|
||||
await expect(page.getByRole('heading', { name: /Créer un nouveau chapitre/i })).toBeVisible();
|
||||
|
||||
await page.getByLabel(/Nom du chapitre/i).fill(chapterName);
|
||||
await page.getByLabel(/Description/i).fill('Synopsis du chapitre');
|
||||
|
||||
await page.getByRole('button', { name: /^Créer le chapitre$/i }).click();
|
||||
|
||||
await expect(page).toHaveURL(
|
||||
new RegExp(`/campaigns/${campaign.id}/arcs/${arc.id}/chapters/\\d+$`),
|
||||
);
|
||||
|
||||
const createdId = page.url().match(/\/chapters\/(\d+)$/)?.[1];
|
||||
expect(createdId).toBeTruthy();
|
||||
const persisted = await getChapterById(request, createdId!);
|
||||
expect(persisted.name).toBe(chapterName);
|
||||
});
|
||||
|
||||
test('submit is disabled when name is empty', async ({ page }) => {
|
||||
await page.goto(`/campaigns/${campaign.id}/arcs/${arc.id}/chapters/create`);
|
||||
|
||||
const submit = page.getByRole('button', { name: /^Créer le chapitre$/i });
|
||||
await expect(submit).toBeDisabled();
|
||||
|
||||
await page.getByLabel(/Nom du chapitre/i).fill('OK');
|
||||
await expect(submit).toBeEnabled();
|
||||
});
|
||||
});
|
||||
64
web/e2e/tests/campaign/scene-create.spec.ts
Normal file
64
web/e2e/tests/campaign/scene-create.spec.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import {
|
||||
seedCampaign,
|
||||
seedArc,
|
||||
seedChapter,
|
||||
deleteCampaign,
|
||||
getSceneById,
|
||||
type SeededCampaign,
|
||||
type SeededArc,
|
||||
type SeededChapter,
|
||||
} from '../../fixtures/api';
|
||||
|
||||
test.describe('Scene creation', () => {
|
||||
let campaign: SeededCampaign;
|
||||
let arc: SeededArc;
|
||||
let chapter: SeededChapter;
|
||||
|
||||
test.beforeEach(async ({ request }) => {
|
||||
campaign = await seedCampaign(request);
|
||||
arc = await seedArc(request, { campaignId: campaign.id });
|
||||
chapter = await seedChapter(request, { arcId: arc.id });
|
||||
});
|
||||
|
||||
test.afterEach(async ({ request }) => {
|
||||
if (campaign?.id) await deleteCampaign(request, campaign.id);
|
||||
});
|
||||
|
||||
test('creates a scene and redirects to its view', async ({ page, request }) => {
|
||||
const sceneName = `Scène ${Date.now()}`;
|
||||
|
||||
await page.goto(
|
||||
`/campaigns/${campaign.id}/arcs/${arc.id}/chapters/${chapter.id}/scenes/create`,
|
||||
);
|
||||
await expect(page.getByRole('heading', { name: /Créer une nouvelle scène/i })).toBeVisible();
|
||||
|
||||
await page.getByLabel(/Nom de la scène/i).fill(sceneName);
|
||||
await page.getByLabel(/Description/i).fill('Résumé rapide de la scène.');
|
||||
|
||||
await page.getByRole('button', { name: /^Créer la scène$/i }).click();
|
||||
|
||||
await expect(page).toHaveURL(
|
||||
new RegExp(
|
||||
`/campaigns/${campaign.id}/arcs/${arc.id}/chapters/${chapter.id}/scenes/\\d+$`,
|
||||
),
|
||||
);
|
||||
|
||||
const createdId = page.url().match(/\/scenes\/(\d+)$/)?.[1];
|
||||
expect(createdId).toBeTruthy();
|
||||
const persisted = await getSceneById(request, createdId!);
|
||||
expect(persisted.name).toBe(sceneName);
|
||||
});
|
||||
|
||||
test('submit is disabled when name is empty', async ({ page }) => {
|
||||
await page.goto(
|
||||
`/campaigns/${campaign.id}/arcs/${arc.id}/chapters/${chapter.id}/scenes/create`,
|
||||
);
|
||||
|
||||
const submit = page.getByRole('button', { name: /^Créer la scène$/i });
|
||||
await expect(submit).toBeDisabled();
|
||||
|
||||
await page.getByLabel(/Nom de la scène/i).fill('OK');
|
||||
await expect(submit).toBeEnabled();
|
||||
});
|
||||
});
|
||||
70
web/e2e/tests/lore/lore-detail-edit.spec.ts
Normal file
70
web/e2e/tests/lore/lore-detail-edit.spec.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { seedLoreWithFolder, deleteLore, getLoreById, type SeededLore } from '../../fixtures/api';
|
||||
|
||||
test.describe('Lore inline edit (on detail page)', () => {
|
||||
let seeded: SeededLore;
|
||||
|
||||
test.beforeEach(async ({ request }) => {
|
||||
seeded = await seedLoreWithFolder(request);
|
||||
});
|
||||
|
||||
test.afterEach(async ({ request }) => {
|
||||
if (seeded?.id) await deleteLore(request, seeded.id);
|
||||
});
|
||||
|
||||
test('renames the lore inline and persists the change', async ({ page, request }) => {
|
||||
const newName = `${seeded.name} renamed`;
|
||||
const newDescription = 'Nouvelle description éditée via UI';
|
||||
|
||||
await page.goto(`/lore/${seeded.id}`);
|
||||
|
||||
await expect(page.locator('.detail-header h1')).toHaveText(seeded.name);
|
||||
|
||||
await page.getByRole('button', { name: /^Modifier$/i }).click();
|
||||
|
||||
const nameInput = page.getByLabel(/^Nom$/);
|
||||
const descInput = page.getByLabel(/^Description$/);
|
||||
await expect(nameInput).toHaveValue(seeded.name);
|
||||
|
||||
await nameInput.fill(newName);
|
||||
await descInput.fill(newDescription);
|
||||
|
||||
await page.getByRole('button', { name: /^Sauvegarder$/i }).click();
|
||||
|
||||
// Sortie du mode édition : le header bascule en mode lecture avec la nouvelle valeur.
|
||||
await expect(page.locator('.detail-header h1')).toHaveText(newName);
|
||||
await expect(page.locator('.detail-header .description')).toHaveText(newDescription);
|
||||
|
||||
const persisted = await getLoreById(request, seeded.id);
|
||||
expect(persisted.name).toBe(newName);
|
||||
expect(persisted.description).toBe(newDescription);
|
||||
});
|
||||
|
||||
test('save button is disabled when name is emptied during edit', async ({ page }) => {
|
||||
await page.goto(`/lore/${seeded.id}`);
|
||||
await page.getByRole('button', { name: /^Modifier$/i }).click();
|
||||
|
||||
const saveBtn = page.getByRole('button', { name: /^Sauvegarder$/i });
|
||||
await expect(saveBtn).toBeEnabled();
|
||||
|
||||
await page.getByLabel(/^Nom$/).fill('');
|
||||
await expect(saveBtn).toBeDisabled();
|
||||
|
||||
await page.getByLabel(/^Nom$/).fill(' ');
|
||||
await expect(saveBtn).toBeDisabled();
|
||||
});
|
||||
|
||||
test('cancel discards the in-flight edits', async ({ page, request }) => {
|
||||
await page.goto(`/lore/${seeded.id}`);
|
||||
await page.getByRole('button', { name: /^Modifier$/i }).click();
|
||||
|
||||
await page.getByLabel(/^Nom$/).fill('Name jamais sauvegardé');
|
||||
await page.getByRole('button', { name: /^Annuler$/i }).click();
|
||||
|
||||
// Retour en mode lecture avec le nom d'origine.
|
||||
await expect(page.locator('.detail-header h1')).toHaveText(seeded.name);
|
||||
|
||||
const persisted = await getLoreById(request, seeded.id);
|
||||
expect(persisted.name).toBe(seeded.name);
|
||||
});
|
||||
});
|
||||
@@ -7,8 +7,9 @@
|
||||
<form [formGroup]="form" (ngSubmit)="submit()" class="arc-form">
|
||||
|
||||
<div class="field">
|
||||
<label>Nom de l'arc *</label>
|
||||
<label for="arc-create-name">Nom de l'arc *</label>
|
||||
<input
|
||||
id="arc-create-name"
|
||||
type="text"
|
||||
formControlName="name"
|
||||
placeholder="Ex: L'Ombre du Nord"
|
||||
@@ -17,8 +18,9 @@
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label>Description</label>
|
||||
<label for="arc-create-description">Description</label>
|
||||
<textarea
|
||||
id="arc-create-description"
|
||||
formControlName="description"
|
||||
placeholder="Décrivez l'arc narratif principal..."
|
||||
rows="5">
|
||||
|
||||
@@ -8,8 +8,9 @@
|
||||
<form [formGroup]="form" (ngSubmit)="submit()" class="chapter-form">
|
||||
|
||||
<div class="field">
|
||||
<label>Nom du chapitre *</label>
|
||||
<label for="chapter-create-name">Nom du chapitre *</label>
|
||||
<input
|
||||
id="chapter-create-name"
|
||||
type="text"
|
||||
formControlName="name"
|
||||
placeholder="Ex: Chapitre 1: Les Disparitions"
|
||||
@@ -18,8 +19,9 @@
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label>Description</label>
|
||||
<label for="chapter-create-description">Description</label>
|
||||
<textarea
|
||||
id="chapter-create-description"
|
||||
formControlName="description"
|
||||
placeholder="Décrivez ce chapitre..."
|
||||
rows="5">
|
||||
|
||||
@@ -8,8 +8,9 @@
|
||||
<form [formGroup]="form" (ngSubmit)="submit()" class="scene-form">
|
||||
|
||||
<div class="field">
|
||||
<label>Nom de la scène *</label>
|
||||
<label for="scene-create-name">Nom de la scène *</label>
|
||||
<input
|
||||
id="scene-create-name"
|
||||
type="text"
|
||||
formControlName="name"
|
||||
placeholder="Ex: Arrivée au village"
|
||||
@@ -18,8 +19,9 @@
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label>Description</label>
|
||||
<label for="scene-create-description">Description</label>
|
||||
<textarea
|
||||
id="scene-create-description"
|
||||
formControlName="description"
|
||||
placeholder="Décrivez la scène, les événements clés, les PNJ présents..."
|
||||
rows="6">
|
||||
|
||||
@@ -21,12 +21,12 @@
|
||||
<!-- ============ Header : mode édition inline ============ -->
|
||||
<div class="detail-header edit-mode" *ngIf="editing">
|
||||
<div class="field">
|
||||
<label>Nom</label>
|
||||
<input type="text" [(ngModel)]="editName" name="editName" required />
|
||||
<label for="lore-detail-edit-name">Nom</label>
|
||||
<input id="lore-detail-edit-name" type="text" [(ngModel)]="editName" name="editName" required />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Description</label>
|
||||
<textarea [(ngModel)]="editDescription" name="editDescription" rows="3"></textarea>
|
||||
<label for="lore-detail-edit-description">Description</label>
|
||||
<textarea id="lore-detail-edit-description" [(ngModel)]="editDescription" name="editDescription" rows="3"></textarea>
|
||||
</div>
|
||||
<div class="header-actions">
|
||||
<button type="button" class="btn-primary" (click)="saveEdit()" [disabled]="!editName.trim()">
|
||||
|
||||
@@ -60,7 +60,8 @@ export class CampaignService {
|
||||
|
||||
// ========== ARC ==========
|
||||
getArcs(campaignId: string): Observable<Arc[]> {
|
||||
return this.http.get<Arc[]>(`/api/arcs/campaign/${campaignId}`);
|
||||
const params = new HttpParams().set('campaignId', campaignId);
|
||||
return this.http.get<Arc[]>('/api/arcs', { params });
|
||||
}
|
||||
|
||||
getArcById(id: string): Observable<Arc> {
|
||||
@@ -85,7 +86,8 @@ export class CampaignService {
|
||||
|
||||
// ========== CHAPTER ==========
|
||||
getChapters(arcId: string): Observable<Chapter[]> {
|
||||
return this.http.get<Chapter[]>(`/api/chapters/arc/${arcId}`);
|
||||
const params = new HttpParams().set('arcId', arcId);
|
||||
return this.http.get<Chapter[]>('/api/chapters', { params });
|
||||
}
|
||||
|
||||
getChapterById(id: string): Observable<Chapter> {
|
||||
@@ -110,7 +112,8 @@ export class CampaignService {
|
||||
|
||||
// ========== SCENE ==========
|
||||
getScenes(chapterId: string): Observable<Scene[]> {
|
||||
return this.http.get<Scene[]>(`/api/scenes/chapter/${chapterId}`);
|
||||
const params = new HttpParams().set('chapterId', chapterId);
|
||||
return this.http.get<Scene[]>('/api/scenes', { params });
|
||||
}
|
||||
|
||||
getSceneById(id: string): Observable<Scene> {
|
||||
|
||||
Reference in New Issue
Block a user