[Intum Pomoc](https://intum.pl/pomoc.md) / [API](https://intum.pl/pomoc/toolkit/api.md)

# [Pulpity (Dashboard)](https://intum.pl/pomoc/toolkit/api/pulpit.md)

Zapisane pulpity z kafelkami. Pulpit to nazwany układ kafelków dla jednego **miejsca** (`context`):

| `context` | Gdzie się wyświetla |
|-----------|---------------------|
| `main` | zakładka **Dashboard** na stronie głównej (`/`) - domyślne |
| `crm` | strona startowa `/crm` (moduł CRM musi być włączony) |
| `cms` | strona startowa `/cms` (moduł CMS musi być włączony) |
| `organize` | strona startowa `/organize` (moduł Organizacja) |
| `mail` | strona startowa `/mail` (moduł Mail) |
| `kb` | strona startowa `/kb` (moduł Baza wiedzy) |
| `marketing` | strona startowa `/marketing` (moduł Marketing) |
| `account` | strona startowa `/account` (Konto) |

Są dwa rodzaje pulpitów:

- **własny pulpit** - widzi i zmienia go tylko jego autor
- **pulpit firmy** (`shared: true`) - widzą go wszyscy, tworzy/zmienia/usuwa tylko użytkownik
  z uprawnieniem do ustawień konta. W każdym miejscu jeden pulpit firmy może być **domyślny**
  (`is_default`) - widzą go wszyscy, którzy w tym miejscu nic nie wybrali

Każdy użytkownik wybiera osobno w każdym miejscu, który pulpit ogląda (`/toolkit/dashboards/select`).
Kolejność: wybrany pulpit, potem domyślny pulpit firmy, na końcu standardowy układ (`builtin`) -
na `main` kafelki `module_header` (z `"module": "main", "frame": "box"` - nagłówek Intum) i `module_icons` (ikony modułów), na `crm` kafelki `module_header` (z `"module": "crm"`),
`crm_stats`, `crm_deals`, `crm_clients`, `crm_contacts`, `crm_notes`, na `cms`
kafelki `module_header` (z `"module": "cms"`), `cms_stats`, `cms_sites`, `cms_domains`, `cms_pages`, `cms_change_log` (dawny pulpit CMS), na `organize` kafelki `module_header` (z `"module": "organize", "frame": "box"`)
i `module_icons` (z `"icons": "organize", "title": "hide"`), na `mail` kafelki `module_header` (z `"module": "mail", "frame": "box"`)
i `module_icons` (z `"icons": "mail", "title": "hide"`), na `kb` kafelki `module_header` (z `"module": "kb"`), `kb_stats`,
`kb_knowledge_bases`, `kb_comments`, `kb_entries`, `kb_entry_urls`, na `marketing` kafelki `module_header`
(z `"module": "marketing"`), `marketing_stats`, `marketing_campaigns`, na `account` kafelki `module_header`
(z `"module": "account", "frame": "box"`) i `module_icons` (z `"icons": "account", "title": "hide"`).

**Pulpity widać tylko z włączonym modułem Toolkit (`toolkit`)** - domyślnie jest wyłączony, wtedy
`/`, `/crm`, `/cms`, `/organize`, `/mail`, `/kb`, `/marketing` i `/account` pokazują zwykłe ikony modułów. Endpointy poniżej działają także z wyłączonym
modułem, więc pulpity można przygotować wcześniej. Po włączeniu pulpit widzi każdy user konta (bez
uprawnień), a tworzenie i zmiana pulpitów wymaga uprawnienia `dashboard_advanced`. Włączenie modułu
(po uzgodnieniu z użytkownikiem - zmienia stronę startową całego konta):

```
POST /account/set_field.json?key=account.settings.modules&action_type=add&value=toolkit
```

albo w UI: `/account/modules` (kafelek **Toolkit**).

**Autoryzacja:** `Authorization: Bearer TOKEN`
**Content-Type:** `application/json; charset=utf-8`

## API Endpoints

| Metoda | Ścieżka | Opis |
|--------|---------|------|
| GET | `/toolkit/dashboards.json` | Pulpity, które użytkownik widzi (firmy + własne), opcjonalnie `?context=crm` |
| GET | `/toolkit/dashboards/:id.json` | Jeden pulpit |
| POST | `/toolkit/dashboards.json` | Nowy pulpit - od razu staje się wybranym w swoim miejscu |
| PATCH | `/toolkit/dashboards/:id.json` | Zmiana układu, nazwy albo `is_default` |
| DELETE | `/toolkit/dashboards/:id.json` | Usunięcie pulpitu |
| PATCH | `/toolkit/dashboards/select.json` | Wybór pulpitu w miejscu: `{"context": "crm", "dashboard_id": 12}`, `"builtin"` albo `""` (domyślny firmy) |
| GET | `/toolkit/dashboards/widgets.json?context=crm` | Wyświetlany pulpit: `current_id`, `layout` po odfiltrowaniu niedostępnych kafelków, `dashboards` do wyboru |
| GET | `/toolkit/dashboards/widget.json?key=inbox` | Czy kafelek jest dostępny dla użytkownika (404 = niedostępny); zwraca `key`, `name`, `settings` (ustawienia kafelka: `options`, `default`, `multiple`, `text`) i `config` |

Pola pulpitu w POST/PATCH idą w kluczu `dashboard` (`{"dashboard": {...}}`). `select` przyjmuje
`context` i `dashboard_id` na najwyższym poziomie.

## Pola pulpitu

| Pole | Typ | Wymagane | Opis |
|------|-----|----------|------|
| `name` | string | tak | Nazwa widoczna na liście wyboru, max 100 znaków |
| `context` | string | nie | Tylko przy POST: `main` (domyślnie), `crm`, `cms`. Później nie da się zmienić |
| `layout` | array | nie | Kafelki w kolejności: `[{"id": "inbox", "key": "inbox", "size": "half"}]`, opcjonalnie z `config` (ustawienia kafelka). Bez niego przy POST - standardowy układ miejsca |
| `shared` | boolean | nie | Tylko przy POST: `true` = pulpit firmy (wymaga uprawnienia do ustawień konta, inaczej 403) |
| `is_default` | boolean | nie | Tylko pulpit firmy: startowy dla wszystkich w tym miejscu. Ustawienie go zdejmuje flagę z poprzedniego |

Odpowiedź zawiera też `id`, `shared`, `editable` (czy bieżący użytkownik może go zmienić) i `updated_at`.

### Kafelki (`key`)

Każdy kafelek można postawić na pulpicie w każdym miejscu.

`module_header` (nagłówek modułu: nazwa, opis, pigułki szybkich akcji, pomoc i AI button - moduł
w `config.module`), `module_icons` (ikony modułów - standardowy pulpit `main`, z `"icons": "crm"` / `"icons": "cms"` ikony
menu CRM / CMS), `kpi` (liczniki), `quick_actions`, `inbox` (Wspólny Inbox: zadania + maile), `activity`, `tasks`, `mail`, `chats`,
`todo` (wymaga uprawnienia do TODO), `ai_request`, kafelki CRM ze standardowego pulpitu `crm` (moduł CRM): `crm_stats` (liczniki: klienci,
kontakty, otwarte interesy, notatki), `crm_deals` (ostatnio zmieniane interesy), `crm_clients` (ostatni klienci),
`crm_contacts` (ostatnie kontakty), `crm_notes` (najnowsze notatki, wymaga uprawnienia `crm_notes_index`), `cms_pages` (Strony CMS: ostatnio edytowane
strony i artykuły razem, moduł CMS), kafelki CMS ze standardowego pulpitu `cms` (moduł CMS): `cms_stats` (liczniki modułu),
`cms_sites` (ostatnio ruszane witryny),
`cms_change_log` (rejestr zmian BIP), `cms_domains` (domeny konta), kafelki Organizacji ze standardowego pulpitu `organize`
(moduł Organizacja): `organize_stats` (liczniki: moje otwarte i zaległe zadania, aktywne projekty, mój czas pracy w tym tygodniu),
`organize_projects` (ostatnio zmieniane projekty), `organize_workinfos` (moje ostatnie wpisy czasu pracy) - kafelki Organizacji nie stoją
w standardowym układzie `organize`, da się je dołożyć, kafelki Bazy wiedzy (moduł KB): `kb_stats`
(liczniki: bazy wiedzy, wpisy, kategorie, komentarze do akceptacji, helplinki, adresy URL), `kb_knowledge_bases` (bazy wiedzy
z liczbą wpisów i kategorii, bazy, którymi użytkownik może zarządzać), `kb_entries` (ostatnio zmieniane wpisy), `kb_comments`
(komentarze czekające na akceptację), `kb_entry_urls` (aliasy URL-i wpisów, od ostatnio odwiedzanych), kafelki Marketingu (moduł Marketing):
`marketing_stats` (liczniki: kampanie, wysłane maile, odsetek otwarć i kliknięć - liczony tylko z kampanii ze śledzeniem,
aktywni subskrybenci, wypisani; duże liczby jako „10 000+”), `marketing_campaigns` (ostatnie kampanie ze statusem i wynikami), `noe_app:<id>` (aplikacja Noe - w UI na liście „Dodaj kafelki” tylko apki z `dashboard_widget: true`, ustawianym przez API aplikacji Noe; przez API pulpitu da się postawić każdą aktywną). Rozmiary (`size`): `quarter`, `half`,
`three_quarters`, `full`; nieznany rozmiar = domyślny kafelka.

Ten sam kafelek może stać na pulpicie **kilka razy** (np. dwa `tasks` z różnym `config`), dlatego
każda pozycja ma własne `id`: 1-32 znaki `a-z`, `0-9`, `_`, `-`, unikalne w układzie. Pozycja bez `id`
(albo z powtórzonym/niepoprawnym) dostaje je automatycznie (`tasks`, `tasks-2`, ...). Przy zmianie
układu odsyłaj `id` pozycji, które zostają - odpowiedź zawsze je zawiera.

### Ustawienia kafelka (`config`)

Część kafelków ma ustawienia, zapisywane osobno na każdym pulpicie w pozycji układu:

| Kafelek | Ustawienie | Wartości |
|---------|------------|----------|
| `activity` | `scope` | `all` (cała firma, domyślnie), `mine` (tylko zdarzenia użytkownika) |
| `tasks` | `scope` | `all` (domyślnie), `mine` (zadania, za które odpowiada użytkownik) |
| `tasks` | `filter` | `all` (domyślnie), `overdue` (zaległe) |
| `mail` | `scope` / `filter` | `all`/`mine`; `all`/`unread` (nieprzeczytane wątki) |
| `chats` | `scope` / `filter` | `all`/`mine`; `all`/`unread` |
| `crm_clients`, `crm_contacts`, `crm_deals` | `scope` | `all`/`mine` (rekordy, za które odpowiada użytkownik) |
| `organize_projects` | `scope` / `filter` | `all`/`mine` (projekty, za które odpowiada użytkownik); `open` (aktywne, domyślnie)/`all` |
| `organize_stats` | `hidden_counters` | **lista ukrytych** liczników: `organize_my_tasks`, `organize_overdue_tasks`, `organize_projects`, `organize_week_hours` |
| `crm_deals` | `filter` | `open` (otwarte interesy, domyślnie), `all` (także wygrane i przegrane) |
| `crm_stats` | `hidden_counters` | **lista ukrytych** liczników: `crm_clients`, `crm_contacts`, `crm_deals_open`, `crm_notes` |
| `inbox` | `scope` | `mine` (domyślnie), `mine_unassigned` (moje + bez odpowiedzialnego), `unassigned`, `all` |
| `inbox` | `source` | `all` (zadania i maile, domyślnie), `tasks`, `emails` |
| `activity`, `tasks`, `mail`, `chats`, `crm_clients`, `crm_deals`, `crm_contacts`, `crm_notes`, `cms_pages`, `cms_change_log`, `cms_domains`, `organize_projects`, `organize_workinfos`, `inbox` | `limit` | `"5"`, `"10"`, `"15"`, `"20"` - liczba pozycji (domyślnie `"5"`, `inbox` i `cms_domains` `"10"`) |
| `kb_entries` | `limit` | `"5"`, `"10"`, `"15"`, `"20"` (domyślnie `"10"`) |
| `kb_comments`, `kb_entry_urls`, `marketing_campaigns` | `limit` | `"5"`, `"10"`, `"15"`, `"20"` (domyślnie `"5"`) |
| `kb_knowledge_bases` | `limit` | `"2"`, `"4"`, `"6"`, `"8"` - liczba baz (domyślnie `"6"`) |
| `kb_stats` | `hidden_counters` | **lista ukrytych** liczników: `kb_knowledge_bases`, `kb_entries`, `kb_categories`, `kb_comments`, `kb_helplinks`, `kb_entry_urls` |
| `marketing_stats` | `hidden_counters` | **lista ukrytych** liczników: `marketing_campaigns`, `marketing_sent`, `marketing_open_rate`, `marketing_click_rate`, `marketing_subscribers`, `marketing_unsubscribes` |
| `cms_sites` | `limit` | `"2"`, `"4"`, `"6"`, `"8"` - liczba witryn (domyślnie `"4"`) |
| `cms_stats` | `hidden_counters` | **lista ukrytych** liczników: `cms_sites`, `cms_pages`, `cms_articles`, `cms_layouts`, `cms_paragraphs`, `cms_assets` |
| `module_icons` | `icons` | `main` (ikony modułów z licznikami i TODO, domyślnie), `crm` (ikony CRM, moduł CRM), `cms` (ikony CMS, moduł CMS), `organize` (ikony Organizacji, moduł Organizacja), `mail` (ikony Maila, moduł Mail), `kb` (ikony Bazy wiedzy, moduł KB), `marketing` (ikony Marketingu, moduł Marketing), `account` (ikony Konta) - bez modułu `main` |
| `module_icons` | `title` | `show` (nazwa modułu nad ikonami, domyślnie), `hide` (bez nazwy - gdy wyżej stoi `module_header`) |
| `module_header` | `module` | `main` (nagłówek Intum strony głównej: pomoc pulpitów, Ustawienia konta z uprawnieniem `account`, AI `main_dashboard`; bez wymaganego modułu), `cms` (nagłówek CMS: Nowa witryna, Ustawienia, AI `cms_new`; domyślnie, moduł CMS), `crm` (nagłówek CRM: Nowy interes, Nowy klient, Ustawienia, AI `crm_dashboard`; moduł CRM), `organize` (nagłówek Organizacji: Dodaj Workinfo, Dodaj zadanie, Ustawienia, AI `organize_dashboard`; moduł Organizacja), `mail` (nagłówek Maila: Nowy mail z uprawnieniem `emails`, Ustawienia, AI `mail_dashboard`; moduł Mail), `kb` (nagłówek Bazy wiedzy: Dodaj wpis, Ustawienia, AI `kb_edit` z bazą roboczą; moduł KB), `marketing` (nagłówek Marketingu: Nowa kampania, Ustawienia, AI `marketing_dashboard`; moduł Marketing), `account` (nagłówek Konta z nazwą konta: Dodaj użytkownika z uprawnieniem `user_settings/all`, Ustawienia z uprawnieniem `account`, AI `account_dashboard`) - bez modułu kafelek jest pusty. Przycisk Ustawienia stoi zawsze tuż przed okrągłym przyciskiem AI |
| `module_header` | `frame` | `none` (bez ramki, jak pasek strony; domyślnie), `box` (w karcie z obramowaniem i większą ikoną; standardowe pulpity `main`, `organize`, `mail` i `account`) |
| `kpi` | `hidden_counters` | **lista ukrytych** liczników: `open_tasks`, `overdue_tasks`, `unread_emails`, `unread_chats`, `clients_this_month` |
| `quick_actions` | `hidden_actions` | **lista ukrytych** akcji: `new_task`, `new_project`, `new_email`, `new_client`, `new_contact`, `new_deal`, `new_note`, `new_ticket`, `new_cms_page` |
| `quick_actions` | `custom_name`, `custom_url` | tekst: własny przycisk (nazwa max 60 znaków, adres `https://...`, `http://...` albo ścieżka `/...` w aplikacji, max 500) - pokazuje się, gdy oba są podane |

Listy (`hidden_counters`, `hidden_actions`) to tablice tego, czego **nie** pokazywać - pusta/brak =
wszystko widać (akcje i liczniki wyłączonych modułów i tak się nie pokazują).

Przykład: `{"id": "a1", "key": "activity", "size": "half", "config": {"scope": "mine", "limit": "10"}}`.
Nieznane ustawienia i niedozwolone wartości (także adres `javascript:` albo `//host`) są usuwane,
wartości domyślne pomijane. Aktualną listę ustawień kafelka
zwraca `GET /toolkit/dashboards/widget.json?key=<key>` w polu `settings`.

Zasady:

- Nieznane klucze są usuwane, max 60 kafelków (powtórzenia kafelka są dozwolone - rozróżnia je `id`)
- Własny pulpit może zawierać tylko kafelki dostępne dla użytkownika. Pulpit firmy może mieć kafelki
  modułów, których autor nie widzi - każdy zobaczy z nich tylko te, do których ma dostęp
- Cudzy własny pulpit zwraca 404, zmiana pulpitu firmy bez uprawnień - 403
- Usunięcie pulpitu cofa wybór - użytkownik wraca do domyślnego pulpitu firmy / standardowego

## Przykłady

```json
POST /toolkit/dashboards.json
{"dashboard": {"name": "Sprzedaż", "context": "crm", "shared": true, "is_default": true,
 "layout": [{"id": "clients", "key": "crm_clients", "size": "half", "config": {"scope": "mine"}},
            {"id": "inbox", "key": "inbox", "size": "half", "config": {"scope": "mine_unassigned", "limit": "15"}},
            {"id": "my-overdue", "key": "tasks", "size": "half", "config": {"scope": "mine", "filter": "overdue"}},
            {"id": "all-tasks", "key": "tasks", "size": "half"},
            {"id": "actions", "key": "quick_actions", "size": "full",
             "config": {"hidden_actions": ["new_cms_page", "new_ticket"], "custom_name": "Raporty", "custom_url": "/insight"}}]}}
```

```json
PATCH /toolkit/dashboards/12.json
{"dashboard": {"name": "Sprzedaż - zespół"}}
```

```json
PATCH /toolkit/dashboards/select.json
{"context": "main", "dashboard_id": "builtin"}
```