Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions client-v3/e2e/tests/06-show-config-characters.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,62 @@ test('deletes a character', async () => {
});
});

// ── Rows per page selector ─────────────────────────────────────────────────

test('rows per page selector is hidden when row count does not exceed minimum', async () => {
// Only Hamlet exists (1 row) — controls hidden when totalRows ≤ 10 (smallest option)
await expect(page.locator('select#character-table-per-page')).not.toBeVisible();
});

test('creates enough characters for pagination controls to appear', async () => {
for (const name of [
'Alice',
'Bob',
'Carol',
'Dave',
'Eve',
'Frank',
'Grace',
'Henry',
'Iris',
'Jack',
]) {
await page.getByRole('button', { name: 'New Character', exact: true }).click();
await waitForModal(page, 'New Character');
await page.fill('.modal.show input[type="text"]', name);
await confirmModal(page);
await waitForModalClosed(page);
}
// 11 characters total (Hamlet + 10) — controls should now appear
await expect(page.locator('select#character-table-per-page')).toBeVisible();
});

test('rows per page selector has correct default', async () => {
await expect(page.locator('label[for="character-table-per-page"]')).toBeVisible();
await expect(page.locator('select#character-table-per-page')).toHaveValue('15');
});

test('rows per page selector has all expected options', async () => {
const options = await page
.locator('select#character-table-per-page')
.locator('option')
.allTextContents();
expect(options).toEqual(expect.arrayContaining(['10', '15', '25', '50', 'All']));
});

test('pagination nav shows when rows exceed per-page and hides on All', async () => {
// 11 rows, default perPage=15: nav hidden (11 ≤ 15)
await expect(page.locator('button[aria-controls="character-table"]').first()).not.toBeVisible();
// Change to 10 rows/page: nav appears (11 > 10)
await page.locator('select#character-table-per-page').selectOption('10');
await expect(page.locator('button[aria-controls="character-table"]').first()).toBeVisible();
// Select All: nav disappears
await page.locator('select#character-table-per-page').selectOption('0');
await expect(page.locator('button[aria-controls="character-table"]').first()).not.toBeVisible();
// Reset to default
await page.locator('select#character-table-per-page').selectOption('15');
});

// ── Character Merge ────────────────────────────────────────────────────────

test('Merge button is visible for each character row', async () => {
Expand Down
67 changes: 67 additions & 0 deletions client-v3/e2e/tests/10-show-config-script.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,73 @@ test('saves a dialogue line to the script', async () => {
).toBeVisible({ timeout: 10_000 });
});

// ── Cut mode ──────────────────────────────────────────────────────────────

test('enters cut mode', async () => {
await page.goto(`${UI_BASE}/show-config/script`);
await waitForAppReady(page);
await page.click('button:has-text("Cuts")');
await expect(page.locator('button:has-text("Stop Editing")')).toBeVisible({ timeout: 10_000 });
});

test('dialogue line becomes clickable in cut mode', async () => {
await expect(
page.locator('a.viewable-line-cut').filter({ hasText: 'To be or not to be' })
).toBeVisible({ timeout: 5_000 });
});

test('clicking a line toggles cut styling', async () => {
await page.locator('a.viewable-line-cut').filter({ hasText: 'To be or not to be' }).click();
await expect(
page.locator('.cut-line-part').filter({ hasText: 'To be or not to be' })
).toBeVisible({ timeout: 3_000 });
});

test('saves cuts', async () => {
await page.getByRole('button', { name: 'Save', exact: true }).click();
await expect(page.locator('.v-toast__text').filter({ hasText: /saved/i })).toBeVisible({
timeout: 5_000,
});
});

test('stops cut mode without blank-page flash', async () => {
// In cut mode the line is an anchor (.viewable-line-cut); verify it exists before stopping
await expect(
page.locator('.viewable-line-cut').filter({ hasText: 'To be or not to be' })
).toBeVisible();

await page.click('button:has-text("Stop Editing")');

// Edit button reappears
await expect(page.getByRole('button', { name: 'Edit', exact: true })).toBeVisible({
timeout: 10_000,
});
// The saved line is still visible (no reload / blank flash)
await expect(
page.locator('.viewable-line').filter({ hasText: 'To be or not to be' })
).toBeVisible();
// No edit controls are shown after stopping
await expect(page.locator('.script-edit-controls')).not.toBeVisible();
});

test('cut styling persists after re-entering cut mode', async () => {
await page.click('button:has-text("Cuts")');
await expect(page.locator('button:has-text("Stop Editing")')).toBeVisible({ timeout: 10_000 });
await expect(
page.locator('.cut-line-part').filter({ hasText: 'To be or not to be' })
).toBeVisible({ timeout: 5_000 });
// Clean up: un-cut the line so later tests start from a known state
await page.locator('a.viewable-line-cut').filter({ hasText: 'To be or not to be' }).click();
await page.getByRole('button', { name: 'Save', exact: true }).click();
await expect(page.locator('.v-toast__text').filter({ hasText: /saved/i })).toBeVisible({
timeout: 5_000,
});
await page.click('button:has-text("Stop Editing")');
await expect(page.getByRole('button', { name: 'Edit', exact: true })).toBeVisible({
timeout: 10_000,
});
});

// ── Stage Direction Styles ────────────────────────────────────────────────

test('switches to Stage Direction Styles sub-tab', async () => {
Expand Down
4 changes: 2 additions & 2 deletions client-v3/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion client-v3/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "client-v3",
"version": "0.31.1",
"version": "0.31.2",
"description": "DigiScript front end (Vue 3)",
"author": "DreamTeamProd",
"private": true,
Expand Down
14 changes: 6 additions & 8 deletions client-v3/src/components/config/ConfigShows.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
id="shows-table"
:items="availableShows"
:fields="showFields"
:per-page="rowsPerPage"
:per-page="perPage"
:current-page="currentPage"
>
<template #head(btn)>
Expand Down Expand Up @@ -37,13 +37,11 @@
</BButtonGroup>
</template>
</BTable>
<BPagination
v-show="availableShows.length > rowsPerPage"
v-model="currentPage"
<PaginationControls
v-model:per-page="perPage"
v-model:current-page="currentPage"
:total-rows="availableShows.length"
:per-page="rowsPerPage"
aria-controls="shows-table"
class="justify-content-center"
/>
</BCol>
</BRow>
Expand Down Expand Up @@ -129,6 +127,7 @@ import { makeURL } from '@/js/utils';
import { useSystemStore } from '@/stores/system';
import { useShowStore } from '@/stores/show';
import { useConfirm } from '@/composables/useConfirm';
import { usePagination } from '@/composables/usePagination';
import { toast } from '@/js/toast';
import type { Show } from '@/types/api/show';

Expand All @@ -144,8 +143,7 @@ const isSubmittingLoad = ref(false);
const isSubmittingShow = ref(false);
const isDeleting = ref(false);
const deletingId = ref<number | null>(null);
const currentPage = ref(1);
const rowsPerPage = 15;
const { perPage, currentPage } = usePagination();

const showFields = [
{ key: 'id', label: 'ID' },
Expand Down
11 changes: 5 additions & 6 deletions client-v3/src/components/config/ConfigSystem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,11 @@
:current-page="currentPage"
small
/>
<BPagination
v-model="currentPage"
<PaginationControls
v-model:per-page="perPage"
v-model:current-page="currentPage"
:total-rows="connectedSessions.length"
:per-page="perPage"
aria-controls="connected-clients-table"
class="justify-content-center"
/>
</BModal>
</div>
Expand All @@ -92,15 +91,15 @@ import { ref, computed, onMounted, onBeforeUnmount } from 'vue';
import { storeToRefs } from 'pinia';
import { BModal } from 'bootstrap-vue-next';
import { useSystemStore } from '@/stores/system';
import { usePagination } from '@/composables/usePagination';
import { toast } from '@/js/toast';

const systemStore = useSystemStore();
const { connectedSessions, versionStatus, serverInfo } = storeToRefs(systemStore);

const loading = ref(true);
const isCheckingVersion = ref(false);
const currentPage = ref(1);
const perPage = 5;
const { perPage, currentPage } = usePagination();
const clientsModal = ref<InstanceType<typeof BModal>>();

const clientFields = [
Expand Down
55 changes: 55 additions & 0 deletions client-v3/src/components/shared/PaginationControls.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<template>
<div
v-if="totalRows > minPerPageOption"
class="d-flex align-items-center justify-content-center gap-3 mt-2 mb-3"
>
<div class="d-flex align-items-center gap-2">
<label class="mb-0 text-nowrap" :for="selectId">Rows per page</label>
<BFormSelect
:id="selectId"
v-model="perPage"
:options="PER_PAGE_OPTIONS"
size="sm"
style="width: auto"
/>
</div>
<BPagination
v-show="perPage > 0 && totalRows > perPage"
v-model="currentPage"
:total-rows="totalRows"
:per-page="perPage"
:aria-controls="ariaControls"
class="mb-0"
/>
</div>
</template>

<script setup lang="ts">
import { computed } from 'vue';
import { PER_PAGE_OPTIONS } from '@/composables/usePagination';

const props = withDefaults(
defineProps<{
totalRows: number;
ariaControls?: string;
}>(),
{ ariaControls: undefined }
);

const perPage = defineModel<number>('perPage', { required: true });
const currentPage = defineModel<number>('currentPage', { required: true });

const selectId = computed(() =>
props.ariaControls ? `${props.ariaControls}-per-page` : 'per-page-select'
);

const minPerPageOption = Math.min(
...PER_PAGE_OPTIONS.filter((o) => o.value > 0).map((o) => o.value)
);
</script>

<style scoped>
:deep(.pagination) {
margin-bottom: 0;
}
</style>
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
id="acts-table"
:items="actTableItems"
:fields="actFields"
:per-page="rowsPerPage"
:per-page="perPage"
:current-page="currentPage"
show-empty
>
Expand Down Expand Up @@ -46,13 +46,11 @@
</BButtonGroup>
</template>
</BTable>
<BPagination
v-show="actTableItems.length > rowsPerPage"
v-model="currentPage"
<PaginationControls
v-model:per-page="perPage"
v-model:current-page="currentPage"
:total-rows="actTableItems.length"
:per-page="rowsPerPage"
aria-controls="acts-table"
class="justify-content-center"
/>

<BModal
Expand Down Expand Up @@ -136,15 +134,15 @@ import log from 'loglevel';
import { useSystemStore } from '@/stores/system';
import { useShowStore } from '@/stores/show';
import { useConfirm } from '@/composables/useConfirm';
import { usePagination } from '@/composables/usePagination';
import type { Act } from '@/types/api/show';

const systemStore = useSystemStore();
const showStore = useShowStore();
const { confirm } = useConfirm();

const loading = ref(true);
const rowsPerPage = 15;
const currentPage = ref(1);
const { perPage, currentPage } = usePagination();
const submittingNewAct = ref(false);
const submittingEditAct = ref(false);
const deletingAct = ref(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
id="scene-table"
:items="sceneTableItems"
:fields="sceneFields"
:per-page="rowsPerPage"
:per-page="perPage"
:current-page="currentPage"
show-empty
>
Expand Down Expand Up @@ -49,13 +49,11 @@
</BButtonGroup>
</template>
</BTable>
<BPagination
v-show="sceneTableItems.length > rowsPerPage"
v-model="currentPage"
<PaginationControls
v-model:per-page="perPage"
v-model:current-page="currentPage"
:total-rows="sceneTableItems.length"
:per-page="rowsPerPage"
aria-controls="scene-table"
class="justify-content-center"
/>
</BCol>
<BCol cols="4">
Expand Down Expand Up @@ -200,15 +198,15 @@ import log from 'loglevel';
import { useSystemStore } from '@/stores/system';
import { useShowStore } from '@/stores/show';
import { useConfirm } from '@/composables/useConfirm';
import { usePagination } from '@/composables/usePagination';
import type { Scene } from '@/types/api/show';

const systemStore = useSystemStore();
const showStore = useShowStore();
const { confirm } = useConfirm();

const loading = ref(true);
const rowsPerPage = 15;
const currentPage = ref(1);
const { perPage, currentPage } = usePagination();
const submittingNewScene = ref(false);
const submittingEditScene = ref(false);
const submittingFirstScene = ref(false);
Expand Down
Loading
Loading