@@ -112,26 +100,9 @@ export default function TemplatesPage() {
- {showOrgTab && (
-
-
-
-
- Team
-
-
- Organisation
-
-
-
+ {showOrgFilter && (
+
+
)}
diff --git a/apps/remix/app/utils/templates-search-params.ts b/apps/remix/app/utils/templates-search-params.ts
new file mode 100644
index 000000000..1222921af
--- /dev/null
+++ b/apps/remix/app/utils/templates-search-params.ts
@@ -0,0 +1,15 @@
+import { parseAsInteger, parseAsStringLiteral } from 'nuqs';
+
+export const TEMPLATES_VIEW_VALUES = ['team', 'organisation'] as const;
+
+/**
+ * Shared nuqs parsers for the templates page URL state.
+ *
+ * Used by the templates page and its filter components so every consumer
+ * parses and serialises the params identically.
+ */
+export const templatesSearchParams = {
+ view: parseAsStringLiteral(TEMPLATES_VIEW_VALUES),
+ page: parseAsInteger,
+ perPage: parseAsInteger,
+};
diff --git a/packages/app-tests/e2e/templates/organisation-templates.spec.ts b/packages/app-tests/e2e/templates/organisation-templates.spec.ts
index 2322cf04d..dc846a067 100644
--- a/packages/app-tests/e2e/templates/organisation-templates.spec.ts
+++ b/packages/app-tests/e2e/templates/organisation-templates.spec.ts
@@ -98,10 +98,10 @@ const trpcMutation = async (page: Page, procedure: string, input: Record
{
- test('should show Team/Organisation tabs for non-personal orgs', async ({ page }) => {
+test.describe('Organisation Templates - UI View Filter', () => {
+ test('should show the view filter for non-personal orgs', async ({ page }) => {
const { ownerA, teamA } = await seedOrgTemplateScenario();
await apiSignin({
@@ -110,11 +110,10 @@ test.describe('Organisation Templates - UI Tabs', () => {
redirectPath: `/t/${teamA.url}/templates`,
});
- await expect(page.getByTestId('template-tab-team')).toBeVisible();
- await expect(page.getByTestId('template-tab-organisation')).toBeVisible();
+ await expect(page.getByTestId('templates-table-view-filter')).toBeVisible();
});
- test('should not show tabs for personal organisations', async ({ page }) => {
+ test('should not show the view filter for personal organisations', async ({ page }) => {
const { user, team } = await seedUser({ isPersonalOrganisation: true });
await apiSignin({
@@ -123,15 +122,14 @@ test.describe('Organisation Templates - UI Tabs', () => {
redirectPath: `/t/${team.url}/templates`,
});
- await expect(page.getByTestId('template-tab-team')).not.toBeVisible();
- await expect(page.getByTestId('template-tab-organisation')).not.toBeVisible();
+ await expect(page.getByTestId('templates-table-view-filter')).not.toBeVisible();
});
});
// ─── UI: Listing Organisation Templates ──────────────────────────────────────
test.describe('Organisation Templates - Listing', () => {
- test('should list org templates from other teams under the Organisation tab', async ({ page }) => {
+ test('should list org templates from other teams under the organisation view', async ({ page }) => {
const { memberB, teamB, orgTemplate } = await seedOrgTemplateScenario();
await apiSignin({
@@ -140,17 +138,18 @@ test.describe('Organisation Templates - Listing', () => {
redirectPath: `/t/${teamB.url}/templates`,
});
- // Team tab should show 0 (memberB has no templates on teamB).
- await expect(page.getByTestId('template-tab-team')).toBeVisible();
+ // Team view is active by default (memberB has no templates on teamB).
+ await expect(page.getByTestId('templates-table-view-filter')).toBeVisible();
- // Switch to Organisation tab.
- await page.getByTestId('template-tab-organisation').click();
+ // Switch to the organisation view.
+ await page.getByTestId('templates-table-view-filter').click();
+ await page.getByRole('option', { name: 'Organisation' }).click();
// Should see the org template from teamA.
await expect(page.getByText(orgTemplate.title)).toBeVisible();
});
- test('should not show private templates from other teams under Organisation tab', async ({ page }) => {
+ test('should not show private templates from other teams under the organisation view', async ({ page }) => {
const { ownerA, teamA, memberB, teamB } = await seedOrgTemplateScenario();
// Create a private template on teamA — should NOT appear in org tab.