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
2 changes: 1 addition & 1 deletion .github/workflows/documentation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ jobs:
deploy:
uses: ConductionNL/.github/.github/workflows/documentation.yml@main
with:
cname: mydash.app
cname: mydash.conduction.nl
12 changes: 11 additions & 1 deletion docs/docusaurus.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
const config = {
title: 'MyDash',
tagline: 'Your customizable dashboard for Nextcloud',
url: 'https://mydash.app',
url: 'https://mydash.conduction.nl',
baseUrl: '/',

// GitHub pages deployment config
Expand All @@ -14,6 +14,7 @@ const config = {

onBrokenLinks: 'warn',
onBrokenMarkdownLinks: 'warn',
onBrokenAnchors: 'warn',

i18n: {
defaultLocale: 'en',
Expand Down Expand Up @@ -105,6 +106,15 @@ const config = {
}),
markdown: {
mermaid: true,
// Tutorial pages reference screenshots that are populated by
// `tests/e2e/docs-screenshots.spec.ts`. The Playwright capture run is
// separate from the docs build, so the build needs to succeed even
// when a fresh checkout doesn't have every PNG yet. Warn instead of
// failing — the absence is visible at preview time and the capture
// spec brings everything back on demand.
hooks: {
onBrokenMarkdownImages: 'warn',
},
},
themes: ['@docusaurus/theme-mermaid'],
};
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion docs/static/CNAME
Original file line number Diff line number Diff line change
@@ -1 +1 @@
mydash.app
mydash.conduction.nl
11 changes: 11 additions & 0 deletions docs/tutorials/_category_.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"label": "Tutorials",
"position": 2,
"collapsible": true,
"collapsed": false,
"link": {
"type": "generated-index",
"title": "MyDash tutorials",
"description": "Step-by-step walkthroughs for everyday MyDash tasks. The user track covers personal-dashboard workflows; the admin track covers org-wide configuration and policy."
}
}
63 changes: 63 additions & 0 deletions docs/tutorials/admin/01-toggle-personal-dashboards.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
---
sidebar_position: 1
title: Enable or disable personal dashboards
description: Allow or prevent end users from creating their own personal dashboards across the instance.
---

# Enable or disable personal dashboards

The `allow_user_dashboards` flag is the master kill-switch for end-user dashboard creation. When off, MyDash hides the **+ Add dashboard** button, blocks `POST /api/dashboard`, and shows users a localised explainer in the empty state.

## Goal

Toggle the flag on or off and verify the user UI reflects the change.

## Prerequisites

- You must be a Nextcloud admin.

## Steps

### 1. Open MyDash admin settings

Settings menu (avatar) → **Administration settings** → **MyDash** in the left nav.

![MyDash admin settings page](../../screenshots/tutorials/admin/01-admin-settings.png)

### 2. Find the **Personal dashboards** section

The section is near the top of the page. The toggle is labelled **Allow users to create personal dashboards**.

![Personal dashboards toggle](../../screenshots/tutorials/admin/01-toggle.png)

### 3. Flip the toggle

The change persists immediately — no Save button. The flag is stored in `oc_mydash_admin_settings` (key `allow_user_dashboards`).

### 4. Verify on the user side

Open MyDash as a non-admin user.

- **Toggle on** → **+ Add dashboard** is visible in the sidebar; the empty state shows the standard "Create your first dashboard" CTA.
- **Toggle off** → button hidden; empty state shows "Personal dashboards are not enabled by your administrator."

![User UI when disabled](../../screenshots/tutorials/admin/01-user-disabled.png)

## Behaviour notes

- **Existing personal dashboards survive.** Disabling doesn't delete user dashboards — they remain accessible. Only creation is blocked.
- **Backend enforcement.** Even if a curl request bypasses the UI, the `POST /api/dashboard` controller calls `assertPersonalDashboardsAllowed()` and responds with `403 personal_dashboards_disabled` when the flag is off.
- **Group-shared dashboards are unaffected.** Admin templates and group defaults render regardless.

## Common issues

| Symptom | Fix |
|---|---|
| Toggle is missing | Confirm the user is actually a Nextcloud admin (`occ user:info <name>`). |
| Users still see + Add after disable | Apache `apc` cache. `docker exec nextcloud apache2ctl graceful` to refresh. |
| Newly-created users land on no-dashboard | Either the toggle is off, OR no admin template applies — see [Create an admin template](02-admin-templates.md). |

## Reference

- [Admin settings feature reference](../../features/admin-settings.md)
- [Permissions reference](../../features/permissions.md)
82 changes: 82 additions & 0 deletions docs/tutorials/admin/02-admin-templates.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
---
sidebar_position: 2
title: Create an admin template dashboard
description: Build a dashboard centrally and roll it out to every user (or to a specific group) on first login.
---

# Create an admin template dashboard

An **admin template** is a dashboard the admin authors and assigns to one or more groups. The first time a member of an assigned group opens MyDash, they get a personal copy of the template's layout. Their copy is independent — they can edit, add, and remove widgets without affecting the template or other users.

## When to use this

- You want every member of a group to start with the same dashboard (KPIs, mandatory tools, brand tiles).
- You're rolling out MyDash for the first time and don't want users to face an empty grid.
- You manage a multi-tenant Nextcloud where each tenant gets a different starting layout.

## Goal

Author a template, assign it to a group, and verify a member of that group lands on a fresh copy on first login.

## Prerequisites

- You must be a Nextcloud admin.
- The target group exists in Nextcloud (`occ group:add my-group` if not).

## Steps

### 1. Open MyDash admin settings

Avatar → **Administration settings** → **MyDash**.

### 2. Scroll to **Admin templates**

The section lists every existing template with name, assigned groups, and edit / delete actions.

![Admin templates list](../../screenshots/tutorials/admin/02-templates-list.png)

### 3. Click **Create template**

The template-create modal opens. Required fields:

- **Name** — internal label for admins. Not user-visible (the user sees a regular dashboard with whatever name you set there).
- **Group order priority** — comma-separated group ids in priority order. The resolver picks the first group in this list that the user belongs to.

![Create template modal](../../screenshots/tutorials/admin/02-template-create.png)

Optional fields:

- **Compulsory widgets** — list of widget IDs that users cannot remove from their copy. Useful for mandatory KPI cards.
- **Lock layout** — when on, users get `view_only` permission on their copy (no drag/resize/add/remove). They still see all the data, just can't reshape it.

### 4. Save and edit the template's layout

Saving creates the template row. Click **Edit layout** on the new template — MyDash opens a regular dashboard editor scoped to the template. Add widgets, position them, configure them — exactly like editing a personal dashboard.

![Edit template layout](../../screenshots/tutorials/admin/02-template-edit.png)

### 5. Verify with a test user

`occ user:add testuser` (or pick an existing member of the assigned group). Log in as that user and open MyDash. The first visit clones the template into a personal dashboard named **My Dashboard** (default) — visible in **MY DASHBOARDS** in the sidebar.

![Test user lands on cloned template](../../screenshots/tutorials/admin/02-test-user-view.png)

## Behaviour notes

- **One-shot clone, not a live link.** The user's copy diverges from the template the moment either side changes. Editing the template later doesn't push changes to existing copies — only new users get the latest.
- **Compulsory widgets stay compulsory across the clone.** They render with a small lock icon in the user's view; **Remove** is greyed out.
- **Multiple groups → priority list wins.** A user in groups `engineering` and `marketing` with priorities `[engineering, marketing]` gets the engineering template even if marketing's was created later.
- **No matching group → fallback resolver.** Users who match no template land on the seven-step default-resolution chain: pin → group default → admin defaults → first available.

## Common issues

| Symptom | Fix |
|---|---|
| Test user sees the empty state, not the template | The user isn't actually in the assigned group, or the group isn't in the priority list. Check `occ user:info`. |
| Template's compulsory widget shows up but user can remove it | Check the compulsory flag is set on that placement (`isCompulsory=1` in `oc_mydash_widget_placements`). |
| Template edits aren't propagating | Expected. Templates are clone-on-first-login, not live. |

## Reference

- [Admin templates feature reference](../../features/admin-templates.md)
- [Permissions reference](../../features/permissions.md)
59 changes: 59 additions & 0 deletions docs/tutorials/admin/03-group-defaults.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
---
sidebar_position: 3
title: Mark a group's default dashboard
description: Pin a shared dashboard so it's the landing page for everyone in a Nextcloud group.
---

# Mark a group's default dashboard

While [admin templates](02-admin-templates.md) clone a layout into each user's personal space, **group defaults** keep a shared dashboard visible to everyone in a group. Group defaults appear in the user's sidebar under the **DEFAULT** section and are read-only by default.

## Goal

Mark an existing dashboard as the default for a Nextcloud group, and verify members of that group see it under **DEFAULT**.

## Prerequisites

- A dashboard already exists (created by an admin in the admin context, not a personal user dashboard).
- The dashboard is shared with the target group via the group-share flow (see admin templates above for the share-with-group path).
- You must be a Nextcloud admin.

## Steps

### 1. Find the dashboard you want to default

Open MyDash as the admin and navigate to the group dashboard. Open its cog menu.

![Group dashboard cog menu](../../screenshots/tutorials/admin/03-group-cog.png)

### 2. Click **Set as default for &lt;group&gt;**

This is admin-only. The action issues `POST /api/dashboards/group/<group>/default` with the dashboard's UUID. The service flips the previous group default off and the new one on **in a single transaction** (REQ-DASH-015), so members never see a flash with no default.

![Set as default for group](../../screenshots/tutorials/admin/03-set-group-default.png)

### 3. Verify on a member's view

Log in as a member of the group. Their sidebar's **DEFAULT** section now lists the dashboard you marked.

![Member view — DEFAULT section](../../screenshots/tutorials/admin/03-member-default.png)

## Behaviour notes

- **One default per group.** Marking a new default for a group automatically clears the previous one — atomic via a database transaction. There's no "two defaults" risk.
- **Cross-group safety.** If you accidentally try to mark a dashboard as default for a group it isn't shared with, the service rejects with 404 (existence is not leaked across group boundaries — REQ-DASH-015 scenario).
- **The user's personal pin still wins.** A user who manually pinned their own dashboard via [Set a default dashboard](../user/07-set-default.md) lands on their pin, not the group default. The group default is the fallback when no personal pin exists.
- **Cleared default → resolver fallback.** If you clear a group default without setting a new one, members land on the org-wide default-group default (or further down the chain).

## Common issues

| Symptom | Fix |
|---|---|
| The action is missing from the cog menu | The dashboard isn't shared with the group, or you're not an admin. |
| Members see no change after marking | OPcache. `docker exec nextcloud apache2ctl graceful` (the dashboard list is cached per-request). |
| "Cross-group default" error | The dashboard's `groupId` doesn't match the target group. Reshare it first. |

## Reference

- [Dashboards feature reference](../../features/dashboards.md)
- API: `POST /api/dashboards/group/{groupId}/default`
74 changes: 74 additions & 0 deletions docs/tutorials/admin/04-restrict-widgets.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
---
sidebar_position: 4
title: Restrict widgets per role
description: Limit which widget types a group of users can see and add.
---

# Restrict widgets per role

The role-based-content feature (RFP) lets an admin define an allow-list of widget IDs per role, where a role is a Nextcloud group plus a per-feature permission set. Members of restricted roles see a filtered widget picker and a filtered AddWidgetModal type list.

## When to use this

- You want to keep certain widgets out of specific groups (e.g. hide HR-Notes from engineering).
- You want to enforce a minimal widget set for compliance / security reasons.
- You're rolling out MyDash to non-technical users and want to reduce cognitive load by hiding rarely-used widgets.

## Goal

Define a role with a widget allow-list, assign it to a group, and verify members see only the allowed widgets.

## Prerequisites

- You must be a Nextcloud admin.
- The target group exists.

## Steps

### 1. Open MyDash admin settings → **Roles**

![Roles tab in admin settings](../../screenshots/tutorials/admin/04-roles-tab.png)

### 2. Click **Create role**

Required fields:

- **Name** — internal label.
- **Group** — Nextcloud group id this role applies to.
- **Allowed widgets** — multi-select of widget IDs (e.g. `recommendations`, `activity`, `tile`, `files`, `text`).

![Create role modal](../../screenshots/tutorials/admin/04-role-create.png)

Leave the allow-list empty to mean "no restriction" (the default for users not in any role).

### 3. Save

The role row appears in the list. The allow-list is persisted in `oc_mydash_roles` and surfaced via `RoleFeaturePermissionService::getAllowedWidgetIds(userId)`.

### 4. Verify on a member's view

As a member of the assigned group, open MyDash and the widget picker:

![Filtered widget picker](../../screenshots/tutorials/admin/04-filtered-picker.png)

Only the allowed widget IDs appear. Existing placements of disallowed widgets keep rendering — the filter only applies to **adding new** widgets.

## Behaviour notes

- **Permissive default.** Users with no matching role see the full widget catalogue. No role assignment ⇒ no restriction.
- **Multiple groups, multiple roles → union.** A user in groups `eng` and `pm` with roles defining different allow-lists sees the **union** of all their roles' allowed widgets.
- **Role changes take effect on next page load.** The allow-list is baked into initial state, not refetched live.
- **Backend enforcement is on display only.** The RFP allow-list is filtering the picker, not blocking the API. A determined user could still POST a placement with a disallowed widgetId — that's by design (the backend doesn't gate on widget type for placement creation, only on dashboard permission). If you need hard backend enforcement, file an issue.

## Common issues

| Symptom | Fix |
|---|---|
| Member still sees all widgets | Reload the page. Allow-list is read on initial state, not live. |
| Allow-list empty but member sees nothing | Empty list = "no restriction" (full catalogue). If you want to show *nothing*, that's not a supported state — use admin templates with `view_only` instead. |
| Two roles conflict | Multi-role membership is a union. There's no priority / override. |

## Reference

- [Role-based content feature reference](../../role-based-content.md)
- [Permissions reference](../../features/permissions.md)
Loading
Loading