From b1f3c10a0685ac4ae2aa2210db9b592d290c0b71 Mon Sep 17 00:00:00 2001 From: Ruben van der Linde Date: Mon, 14 Sep 2026 23:24:52 +0200 Subject: [PATCH 1/9] docs(openspec): adopt the connection registry for launchpad's six outside connections --- .../adopt-connection-registry/.openspec.yaml | 2 + .../adopt-connection-registry/design.md | 91 ++++++++++++ .../adopt-connection-registry/proposal.md | 49 +++++++ .../specs/app-connections/spec.md | 134 ++++++++++++++++++ .../adopt-connection-registry/tasks.md | 32 +++++ 5 files changed, 308 insertions(+) create mode 100644 openspec/changes/adopt-connection-registry/.openspec.yaml create mode 100644 openspec/changes/adopt-connection-registry/design.md create mode 100644 openspec/changes/adopt-connection-registry/proposal.md create mode 100644 openspec/changes/adopt-connection-registry/specs/app-connections/spec.md create mode 100644 openspec/changes/adopt-connection-registry/tasks.md diff --git a/openspec/changes/adopt-connection-registry/.openspec.yaml b/openspec/changes/adopt-connection-registry/.openspec.yaml new file mode 100644 index 00000000..a40cb63c --- /dev/null +++ b/openspec/changes/adopt-connection-registry/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-09-14 diff --git a/openspec/changes/adopt-connection-registry/design.md b/openspec/changes/adopt-connection-registry/design.md new file mode 100644 index 00000000..6686fe44 --- /dev/null +++ b/openspec/changes/adopt-connection-registry/design.md @@ -0,0 +1,91 @@ +# Design: adopt-connection-registry + +The contract is hydra `openspec/changes/connection-registry/design.md` (hydra#667, amended in hydra#673, hydra#674 and hydra#676). This file records how LaunchPad meets it and where it fits loosely. + +## D1. Which connections are declared + +Each candidate was checked against the code on `development`, not against its name. + +| Key | Declared as | Why | +|---|---|---| +| `dashboard-registry` | `requiredConfig: ["registry_url"]`, `settingsUrl` to the Sharing tab | OpenRegister's `GenericStoreService` reads `registry_url` and `registry_token` from LaunchPad's app config. `StoreService::search()` is the one caller. The token is optional, so only the URL is required. | +| `weather` | `reportedOnly: true` | `WeatherService` picks its source per placement. A placement with a location calls `weather_provider_url`. A placement without one reads Nextcloud's weather status app for the viewing user. So an empty URL is a working default for some widgets and a broken one for others, and only a fetch can tell. | +| `news-feeds` | `reportedOnly: true` | `NewsWidgetService` fetches the feed URLs each widget names. `news_widget_allowed_feed_hosts` is fail-open: an empty list allows every HTTPS host, so there is nothing to require. | +| `ics-calendars` | `reportedOnly: true` | `CalendarWidgetService` fetches the ICS URLs each widget names. `calendar_widget_allowed_ics_hosts` is fail-open like the news list. | +| `live-tiles` | `reportedOnly: true` | `LiveTileService` fetches the URL each tile names. `livetile_allowed_hosts` is fail-closed: an empty list refuses every host. | +| `health-ping` | `reportedOnly: true` | `HealthPingService` pings the URL each tile names, on a page load and from `HealthPingRefreshJob`. `healthping_allowed_hosts` is fail-closed like the live tile list. | + +**Why only the registry links to settings.** The weather provider and the four allow-lists have no admin screen; `docs/features` tells an admin to set them with `occ`. A link would open a page that cannot change them. The registry form on the Sharing tab now carries `id="section-dashboard-registry"`, and the link adds `?tab=sharing` because `BeheerTabs` renders only the active tab. + +**Why a fail-closed allow-list is not `requiredConfig`.** The value is a JSON list. An admin who has not set it holds `""`, which D4 reads as empty. An admin who cleared it holds `[]`, which D4 reads as filled. So rule 5 would call a list that allows nothing Configured. A report after a refused fetch says it instead. + +**Why each family is one row.** Every widget names its own address, which is the case D12 leaves out. Each row stands for the family and shows the last fetch. + +## D2. What the reports say + +`ConnectionReporter` sends the events. `ConnectionObservations` turns an outcome into a status and a message, and holds no state. Each caller hands over the outcome it already had; no call is added. + +| Row | Outcome | Status | Message | +|---|---|---|---| +| `dashboard-registry` | OpenRegister absent | `unavailable` | "OpenRegister is not enabled, so LaunchPad cannot reach a dashboard registry." | +| | `ok` | `configured` | "The dashboard registry at {host} answered the last search." | +| | `not_configured` | `unconfigured` | "No registry address is set. Set the registry URL on the Sharing tab of the LaunchPad settings." | +| | `store_unreachable` | `error` | "The last search could not reach the dashboard registry at {host}." | +| | `store_invalid_response` | `error` | "The dashboard registry at {host} answered, but not with a list of templates." | +| | `rate_limited` | `limited` | "The dashboard registry at {host} limited the last search." | +| `weather` | no provider URL | `unconfigured` | "A weather widget with a location found no provider URL. Set weather_provider_url with occ." | +| | URL not http or https | `error` | "The weather provider URL does not start with http or https. Set weather_provider_url with occ." | +| | 2xx without a temperature | `error` | "The weather provider at {host} answered, but not with a temperature LaunchPad can read." | +| any HTTP row | no answer | `error` | "The last call to the {name} at {host} got no answer." | +| | HTTP 401 or 403 | `error` | "The {name} at {host} refused the request (HTTP 401)." | +| | HTTP 429 | `limited` | "The {name} at {host} limited the last call (HTTP 429)." | +| | HTTP 502, 503 or 504 | `error` | "The {name} at {host} answered HTTP 503 on the last call." | +| | HTTP 2xx | `configured` | "The {name} at {host} answered the last call." | +| `live-tiles`, `health-ping` | host refused, and the list holds no host | `unconfigured` | "{configKey} holds no JSON list of hosts, so LaunchPad refused the last call. Set it with occ." | + +The HTTP rows are `weather` (weather provider), `news-feeds` (news feed), `ics-calendars` (calendar feed), `live-tiles` (live tile source) and `health-ping` (health ping target). + +Anything else sends nothing. A 404, a 400, a 500 or a 3xx is about one address. A host that a non-empty allow-list refuses is about one widget. A weather status reading depends on one user. Those would make a working connection read Error. + +A message names the host of the address, and nothing else from it. No path, query, user info or API key reaches the row. + +## D3. When it reports + +The report memory is one app-config value per connection, `connection_report_{key}`, holding the last status and its time. + +- A different status reports once five minutes have passed since the last report, so two widgets that disagree cannot write on every page load. +- The same status reports again after an hour, so `lastReport` stays newer than a stale probe. +- A registry save clears the registry's memory, so the next search reports at once. + +Without integriq the class check fails first: nothing is read, stored, sent or logged. Every report method catches everything, because it runs beside a widget response whose own answer is what the caller returns. + +**Why this is cheap enough.** Dashboard widgets fetch on page load. Every service already caches its fetch (weather 900 s, feeds 3600 s, calendars 1800 s, live tiles and pings per tile), so a report can only follow a real outbound call. A report costs a `class_exists` and one app-config read, which Nextcloud has already loaded for the request. A write and an event happen at most once per window per connection. The report never changes what the widget answers. + +## D4. The refresh + +`StoreService::updateRegistryConfig()` is the one writer of the registry keys; `StoreController::updateConfig()` calls it for the Sharing tab. After the write it hands the keys it wrote to `ConnectionReporter::refreshFromSave()`. When `registry_url`, `registry_register` or `registry_token` is among them, the reporter clears the registry's report memory and sends `ConnectionRefreshRequestedEvent('launchpad', 'dashboard-registry')`. + +The refresh goes first and any report after it. A save sends no report of its own; the next search does, and because the memory was cleared, that report lands at once instead of waiting out the window. Under hydra#674 the refresh retires older observations, so a save brings back rule 5 until that search reports. + +The other five rows have no save to hook. A key set with `occ` sends no event, and integriq's hourly resolver pass covers that (D12 amendment 3). + +## D5. The page + +- `src/manifest.d/connection-registry.json`: an `index` page `Integrations` at `/settings/integrations`, `requiresApp` integriq, `permission: admin`, `showAdd: false`, and the contract columns: connection, status, status message, last checked, settings. +- Its menu entry `IntegrationsMenu` sits in the settings gear with `query: {app: launchpad}`, `permission: admin` and `visibleIf.appInstalled: integriq`. +- `src/services/connectionRegistry.js` holds `connectionStatus`, `connectionSettingsLabel` and `openIntegriqConnections`. +- `src/customComponents.js` exposes the handler, and `App.vue` passes it with the formatters to `CnAppRoot`. CnIndexPage resolves a header action's handler against `customComponents`, not against the v2 `registry`. + +**Formatters.** The installed `@conduction/nextcloud-vue` 2.46.0 ships no `connectionStatus` built-in, so LaunchPad carries a local copy with all six labels, `limited` included. + +## D6. Contract misfits + +- **An allow-list is a JSON list.** D4 counts `""`, `false`, `0` and `null` as empty, not `[]`. A fail-closed list therefore cannot be `requiredConfig` (D1). +- **No settings surface.** Five of six rows are configured with `occ` only, so they carry no `settingsUrl`, and their unconfigured messages name the key. +- **A source chosen per widget.** The weather source depends on whether a placement has a location. `reportedOnly` plus outcome reports is the closest fit. +- **A family row shows one address.** The last fetch stands for every widget. The message names that host, so the reader can tell which one. + +## Risks + +- **A mixed dashboard flips a family row.** One dead feed among working ones moves the row between Configured and Error, at most every five minutes. +- **A busy instance writes app config at most every five minutes per connection.** That is six keys. diff --git a/openspec/changes/adopt-connection-registry/proposal.md b/openspec/changes/adopt-connection-registry/proposal.md new file mode 100644 index 00000000..615de8e2 --- /dev/null +++ b/openspec/changes/adopt-connection-registry/proposal.md @@ -0,0 +1,49 @@ +--- +kind: code +--- + +# Proposal: adopt-connection-registry + +## Why + +LaunchPad reaches six things outside its own code, and no screen says whether any of them works. + +- The dashboard registry. An admin saves a registry URL under Sharing. A search that cannot reach it shows an empty store and logs the reason. +- The weather provider. A weather widget with a set location calls the provider URL an admin set with `occ`. Without that URL the widget shows an error. +- News feeds, calendar feeds, live tiles and health pings. Each widget or tile names its own address. A failed fetch is a log line. +- Live tiles and health pings refuse every host until an admin sets an allow-list with `occ`. Nothing on a screen says so. + +Hydra change `connection-registry` (hydra#667, amended in hydra#673, hydra#674 and hydra#676) gives every app one page of its connections, backed by integriq. + +## What changes + +- New `lib/Settings/connections.json` with six connections: `dashboard-registry`, `weather`, `news-feeds`, `ics-calendars`, `live-tiles` and `health-ping`. +- The dashboard registry requires `registry_url` and links to a new `#section-dashboard-registry` anchor on the Sharing tab. The other five are reported only. +- An Integrations page under the settings gear, over integriq's `app_connection` schema, preset to `app=launchpad`, admin only, and only shown when integriq is installed. +- Add integration opens `/apps/integriq/connections?app=launchpad&link=1`. +- A registry settings save asks integriq to resolve the registry again. +- LaunchPad reports what a registry search, a weather reading, a feed fetch, a live tile fetch and a health ping met. It reports a change after five minutes, and the same status at most once an hour. +- Local `connectionStatus` and `connectionSettingsLabel` formatters with all six statuses, and the strings in English and Dutch. +- CI installs integriq, so the e2e spec can reach the page. + +## Not declared + +- **Nextcloud's weather status app.** A weather widget without a location reads it. Its reading depends on each user's own location, so a failure says nothing about the instance. +- **Live tiles in connector mode.** They call integriq on the same instance, which already shows its own sources. +- **Iframe embeds.** The browser loads the page, not LaunchPad, so LaunchPad sees no outcome. + +## Depends on + +- hydra `openspec/changes/connection-registry`, design D2, D4, D6, D8, D9 and D12. +- integriq on `development`: the `app_connection` schema, the declaration sync, both events and the Connections overview. + +Without integriq the menu entry is hidden, a deep link shows the missing-dependency screen, and nothing is sent. + +## Out of scope + +- Admin screens for the weather provider and the four allow-lists. They are set with `occ` today, so their rows carry no settings link. +- Per-widget rows. A static file cannot list them (design D12). + +## Rollback + +Revert the change. LaunchPad writes no rows of its own. Integriq removes the rows without a linked source on its next sync, and the report memory keys in app config stop being read. diff --git a/openspec/changes/adopt-connection-registry/specs/app-connections/spec.md b/openspec/changes/adopt-connection-registry/specs/app-connections/spec.md new file mode 100644 index 00000000..5656c424 --- /dev/null +++ b/openspec/changes/adopt-connection-registry/specs/app-connections/spec.md @@ -0,0 +1,134 @@ +# app-connections Specification Delta + +**Status**: proposed +**Scope**: launchpad +**OpenSpec changes**: +- [adopt-connection-registry](../../) + +## Purpose + +Admins see LaunchPad's outside connections on one page, with a status the app can back. + +## ADDED Requirements + +### Requirement: REQ-LP-CONN-001 LaunchPad declares its outside connections in one static file + +LaunchPad SHALL declare its outside connections in `lib/Settings/connections.json` in the shape of hydra connection-registry design D2 (hydra REQ-CONN-001). The file SHALL validate against integriq's `connections.schema.json`, and its `app` SHALL equal the id in `appinfo/info.xml`. It SHALL declare `dashboard-registry`, `weather`, `news-feeds`, `ics-calendars`, `live-tiles` and `health-ping`. `dashboard-registry` SHALL require `registry_url` and SHALL link to the `#section-dashboard-registry` anchor on the Sharing tab of the LaunchPad admin page, and that anchor SHALL exist. The other five SHALL be `reportedOnly`, SHALL carry no `requiredConfig` or `adapter`, and SHALL carry no `settingsUrl`, because no admin screen sets their keys. + +#### Scenario: The declaration names this app and passes integriq's schema +@e2e exclude A static file with no browser surface; tests/Unit/Settings/ConnectionsDeclarationTest.php validates it against the vendored schema, checks the app id, the unique keys and that every settings anchor exists. + +- **GIVEN** `lib/Settings/connections.json` +- **WHEN** it is validated against integriq's `connections.schema.json` +- **THEN** it SHALL validate +- **AND** its `app` SHALL equal the id in `appinfo/info.xml` +- **AND** every key SHALL be unique +- **AND** every `settingsUrl` anchor SHALL exist under `src/` + +#### Scenario: A saved registry URL reads configured +@e2e tests/e2e/integrations-page.spec.ts + +- **GIVEN** integriq has synced LaunchPad's declaration +- **WHEN** an admin saves a registry URL on the Sharing tab +- **THEN** the Dashboard registry row SHALL read Configured with "Required settings are filled." + +### Requirement: REQ-LP-CONN-002 A registry settings save asks integriq to look again + +When `StoreService::updateRegistryConfig()` writes `registry_url`, `registry_register` or `registry_token`, LaunchPad SHALL send `ConnectionRefreshRequestedEvent` with app `launchpad` and key `dashboard-registry` (hydra REQ-CONN-004), and SHALL clear the registry's report memory. The refresh SHALL be sent before any report that follows the save. A save that writes none of those keys SHALL send nothing. The event SHALL be named by string and sent only when the class exists. It SHALL NOT change the result of the save. + +#### Scenario: Saving the registry URL asks for a refresh +@e2e exclude The event is not observable from a browser; tests/Unit/Service/StoreServiceConnectionReportTest.php asserts the refresh and the written keys. + +- **GIVEN** integriq is installed +- **WHEN** an admin saves `registry_url` +- **THEN** LaunchPad SHALL send a refresh request for `dashboard-registry` + +#### Scenario: The refresh goes before the report that follows it +@e2e exclude Event order is not observable from a browser; tests/Unit/Service/StoreServiceConnectionReportTest.php asserts the order. + +- **GIVEN** a registry search reported `error` two minutes ago +- **WHEN** an admin saves `registry_url` and a user then searches the store +- **THEN** LaunchPad SHALL send the refresh request first +- **AND** it SHALL send the search's report after it, without waiting out the five minutes + +#### Scenario: A save that writes no registry key sends nothing +@e2e exclude The event is not observable from a browser; tests/Unit/Service/Connection/ConnectionReporterTest.php asserts that only registry keys refresh. + +- **GIVEN** integriq is installed +- **WHEN** the save writes no registry key +- **THEN** LaunchPad SHALL send no refresh request + +### Requirement: REQ-LP-CONN-003 LaunchPad reports what its outbound calls met + +LaunchPad SHALL report with `ConnectionStatusReportedEvent` what a registry search, a weather provider reading, a news feed fetch, a calendar feed fetch, a live tile fetch and a health ping met, mapped as in the change's design D2. It SHALL report only after a real outbound call or a refusal that says something about the instance, and SHALL NOT report outcomes about one address, one widget or one user. A message SHALL carry at most the host of an address. It SHALL report a different status only after five minutes have passed since the last report, and the same status only after an hour. Without integriq it SHALL read, store, send and log nothing. A report SHALL never throw into the call it observes or change the widget's response. + +#### Scenario: A registry that cannot be reached reads error +@e2e tests/e2e/integrations-page.spec.ts + +- **GIVEN** an admin saved a registry URL where nothing answers +- **WHEN** a user searches the dashboard store +- **THEN** LaunchPad SHALL report `dashboard-registry` as `error` with a message naming the host +- **AND** the search SHALL answer with the same outcome as before this change + +#### Scenario: A weather widget with a location and no provider URL reads unconfigured +@e2e exclude The CI instance sets no weather provider and no widget with a location; tests/Unit/Service/WeatherServiceConnectionReportTest.php asserts the report and the unchanged error response. + +- **GIVEN** `weather_provider_url` is empty +- **WHEN** a weather widget with a location asks for a reading +- **THEN** LaunchPad SHALL report `weather` as `unconfigured`, naming `weather_provider_url` + +#### Scenario: A feed fetch reports only the host +@e2e exclude A feed needs a host outside the instance; tests/Unit/Service/Connection/ConnectionObservationsTest.php and tests/Unit/Service/WidgetFetchConnectionReportTest.php assert the report and that no path, query or user info reaches it. + +- **GIVEN** a news widget names `https://user:secret@feeds.example.nl/rss?token=abc` +- **WHEN** the feed host answers HTTP 503 +- **THEN** LaunchPad SHALL report `news-feeds` as `error` naming `feeds.example.nl` +- **AND** the message SHALL NOT contain the path, the query or the user info + +#### Scenario: An empty fail-closed allow-list reads unconfigured +@e2e exclude The CI instance sets no live tile or health ping; tests/Unit/Service/WidgetFetchConnectionReportTest.php asserts the report for both lists and that a refusal by a non-empty list sends nothing. + +- **GIVEN** `healthping_allowed_hosts` holds no JSON list of hosts +- **WHEN** a tile's health ping is refused +- **THEN** LaunchPad SHALL report `health-ping` as `unconfigured`, naming `healthping_allowed_hosts` + +#### Scenario: Many widget fetches send one report per window +@e2e exclude Timing is not observable from a browser; tests/Unit/Service/Connection/ConnectionReporterTest.php drives the clock through a burst of fetches. + +- **GIVEN** a calendar feed fetch reported `configured` ten minutes ago +- **WHEN** fifty more fetches get an answer within the hour +- **THEN** LaunchPad SHALL send no report + +#### Scenario: Without integriq nothing is sent +@e2e exclude The CI instance installs integriq; tests/Unit/Service/Connection/ConnectionReporterTest.php asserts that nothing is sent, stored or logged when the class is absent. + +- **GIVEN** integriq is not installed +- **WHEN** a feed fetch runs or an admin saves `registry_url` +- **THEN** no event SHALL be sent and nothing SHALL be logged +- **AND** no report memory SHALL be written to app config + +### Requirement: REQ-LP-CONN-004 An admin reads the connections on an Integrations page + +LaunchPad SHALL render an `index` page at `/settings/integrations` over `integriq/app_connection`, reached from the settings gear and preset to `app` equal to `launchpad` through its menu entry's `query` (hydra REQ-CONN-006). The page and its menu entry SHALL be admin only. The page SHALL require Integriq, and the menu entry SHALL only render when integriq is installed. The status column SHALL name all six statuses, `limited` included. The page SHALL NOT offer a generic Add button. Its Add integration action SHALL open `/apps/integriq/connections?app=launchpad&link=1`. + +#### Scenario: The page lists only the rows of launchpad +@e2e tests/e2e/integrations-page.spec.ts + +- **GIVEN** launchpad and integriq are installed and integriq has synced the declaration +- **WHEN** an admin opens the Integrations page +- **THEN** the page SHALL list the six declared connections +- **AND** every listed row SHALL have `app` equal to `launchpad` + +#### Scenario: Add integration goes to integriq +@e2e tests/e2e/integrations-page.spec.ts + +- **GIVEN** the Integrations page +- **WHEN** the admin chooses Add integration +- **THEN** the browser SHALL open integriq's Connections overview with `app=launchpad` and `link=1` + +#### Scenario: A connection that works in part reads Limited +@e2e exclude No CI host rate-limits a call, so no row reads limited there; src/services/__tests__/connectionRegistry.spec.js asserts the label in English and Dutch. + +- **GIVEN** a row whose status is `limited` +- **WHEN** the page renders it +- **THEN** the cell SHALL read Limited, or Beperkt on a Dutch instance diff --git a/openspec/changes/adopt-connection-registry/tasks.md b/openspec/changes/adopt-connection-registry/tasks.md new file mode 100644 index 00000000..76fd6c2b --- /dev/null +++ b/openspec/changes/adopt-connection-registry/tasks.md @@ -0,0 +1,32 @@ +# adopt-connection-registry tasks + +## 1. Declare + +- [ ] 1.1 Write `lib/Settings/connections.json` with `dashboard-registry`, `weather`, `news-feeds`, `ics-calendars`, `live-tiles` and `health-ping`. +- [ ] 1.2 Vendor integriq's schema in `tests/Fixtures/Integriq/` and guard the file in `tests/Unit/Settings/ConnectionsDeclarationTest.php`. +- [ ] 1.3 Give the dashboard registry form the `section-dashboard-registry` id. + +## 2. Page + +- [ ] 2.1 Add `src/manifest.d/connection-registry.json` with the page and its settings-gear menu entry. +- [ ] 2.2 Add `src/services/connectionRegistry.js` with the two formatters and the Add integration handler. +- [ ] 2.3 Wire the formatters and the handler through `src/App.vue` and `src/customComponents.js`; register `PowerPlugOutline` in `src/icons.js`. +- [ ] 2.4 Add the strings to `l10n/en` and `l10n/nl`. +- [ ] 2.5 Cover it in `src/services/__tests__/connectionRegistry.spec.js`. + +## 3. Reports and refresh + +- [ ] 3.1 Add `lib/Service/Connection/ConnectionReporter.php` and `ConnectionObservations.php`. +- [ ] 3.2 Refresh from `StoreService::updateRegistryConfig()`, and wire the reporter into the hand-built `StoreService` in `Application.php`. +- [ ] 3.3 Report from `StoreService`, `WeatherService`, `NewsWidgetService`, `CalendarWidgetService`, `LiveTileService` and `HealthPingService`. +- [ ] 3.4 Add the integriq event stubs to `tests/Stubs`, `tests/bootstrap.php` and `psalm.xml`. +- [ ] 3.5 Cover it in unit tests, including a burst of widget fetches against the throttle. + +## 4. End to end + +- [ ] 4.1 Write `tests/e2e/integrations-page.spec.ts`. +- [ ] 4.2 Install integriq in the CI `additional-apps`. + +## 5. After an instance runs both apps + +- [ ] 5.1 Run the e2e spec against an instance with launchpad and integriq, then archive this change. From 17a56b850a95726d3046dfc993f94457e0521c58 Mon Sep 17 00:00:00 2001 From: Ruben van der Linde Date: Mon, 14 Sep 2026 23:26:43 +0200 Subject: [PATCH 2/9] feat(connections): declare launchpad's six outside connections for integriq --- lib/Settings/connections.json | 54 +++ .../admin/DashboardRegistrySettings.vue | 9 +- .../Fixtures/Integriq/connections.schema.json | 139 +++++++ .../Settings/ConnectionsDeclarationTest.php | 358 ++++++++++++++++++ 4 files changed, 559 insertions(+), 1 deletion(-) create mode 100644 lib/Settings/connections.json create mode 100644 tests/Fixtures/Integriq/connections.schema.json create mode 100644 tests/Unit/Settings/ConnectionsDeclarationTest.php diff --git a/lib/Settings/connections.json b/lib/Settings/connections.json new file mode 100644 index 00000000..647ee846 --- /dev/null +++ b/lib/Settings/connections.json @@ -0,0 +1,54 @@ +{ + "app": "launchpad", + "connections": [ + { + "key": "dashboard-registry", + "title": "Dashboard registry", + "description": "A registry of another instance, where you find and install dashboards other organisations published.", + "order": 10, + "settingsUrl": "/settings/admin/launchpad?tab=sharing#section-dashboard-registry", + "requiredConfig": ["registry_url"], + "unconfiguredMessage": "No registry address is set. Set the registry URL on the Sharing tab of the LaunchPad settings." + }, + { + "key": "weather", + "title": "Weather provider", + "description": "Weather widgets with a location read the provider URL an admin sets. Widgets without a location read Nextcloud's weather status app.", + "order": 20, + "reportedOnly": true, + "unconfiguredMessage": "Not checked yet. LaunchPad reports here after a weather widget with a location fetches a reading. Set weather_provider_url with occ." + }, + { + "key": "news-feeds", + "title": "News feeds", + "description": "News widgets fetch the RSS and Atom feeds they name. Each widget names its own address, so this row shows the last fetch.", + "order": 30, + "reportedOnly": true, + "unconfiguredMessage": "Not checked yet. LaunchPad reports here after a news widget fetches a feed." + }, + { + "key": "ics-calendars", + "title": "Calendar feeds", + "description": "Calendar widgets fetch the ICS feeds they name. Each widget names its own address, so this row shows the last fetch.", + "order": 40, + "reportedOnly": true, + "unconfiguredMessage": "Not checked yet. LaunchPad reports here after a calendar widget fetches an ICS feed." + }, + { + "key": "live-tiles", + "title": "Live tiles", + "description": "Live tiles fetch a value from the address they name. Only hosts in livetile_allowed_hosts are fetched.", + "order": 50, + "reportedOnly": true, + "unconfiguredMessage": "Not checked yet. LaunchPad reports here after a live tile fetches its value. Set livetile_allowed_hosts with occ." + }, + { + "key": "health-ping", + "title": "Health ping", + "description": "Tiles check whether the service they link to answers. Only hosts in healthping_allowed_hosts are pinged.", + "order": 60, + "reportedOnly": true, + "unconfiguredMessage": "Not checked yet. LaunchPad reports here after a tile pings its service. Set healthping_allowed_hosts with occ." + } + ] +} diff --git a/src/components/admin/DashboardRegistrySettings.vue b/src/components/admin/DashboardRegistrySettings.vue index 867ee0b5..07b97117 100644 --- a/src/components/admin/DashboardRegistrySettings.vue +++ b/src/components/admin/DashboardRegistrySettings.vue @@ -4,7 +4,14 @@ -->