From 9f36be4e25dbb3367bae25bc58d928c4a4875476 Mon Sep 17 00:00:00 2001 From: Jannik Stehle Date: Mon, 21 Sep 2026 14:33:57 +0200 Subject: [PATCH 1/2] docs(dev): overhaul web extension system docs --- .../advanced-topics/_category_.json | 4 + .../advanced-topics/configuration.md | 57 ++++ .../advanced-topics/styling.md | 59 ++++ .../advanced-topics/testing.md | 41 +++ .../advanced-topics/translations.md | 138 ++++++++++ .../web/extension-system/build-and-publish.md | 104 +++++++ .../extension-system/extension-types/index.md | 6 - .../left-sidebar-menu-item-extensions.md | 92 ------- .../extensions/_category_.json | 4 + .../extensions/extension-points.md | 204 ++++++++++++++ .../extension-types/_category_.json | 0 .../extension-types/account-extensions.md | 46 ++++ .../extension-types/action-extensions.md | 6 +- .../app-menu-item-extensions.md | 6 +- .../custom-component-extensions.md | 7 +- .../floating-action-button-extensions.md | 17 +- .../extension-types/folder-view-extensions.md | 9 +- .../extensions/extension-types/index.md | 25 ++ .../left-sidebar-menu-item-extensions.md | 93 +++++++ .../resource-indicator-extensions.md | 85 ++++++ .../right-sidebar-panel-extensions.md | 6 +- .../extension-types/search-extensions.md | 8 +- .../extension-types/vault-extensions.md | 123 +++++++++ .../web/extension-system/extensions/index.md | 133 +++++++++ .../web/extension-system/getting-started.md | 172 ++++++++++++ docs/dev/web/extension-system/index.md | 197 ++------------ docs/dev/web/extension-system/packages.md | 21 ++ .../viewer-editor-apps/_category_.json | 4 + .../collaborative-editing.md | 255 ++++++++++++++++++ .../index.md} | 26 +- docs/dev/web/getting-started.md | 28 +- .../advanced-topics/_category_.json | 4 + .../advanced-topics/configuration.md | 56 ++++ .../advanced-topics/styling.md | 52 ++++ .../advanced-topics/testing.md | 41 +++ .../advanced-topics/translations.md | 138 ++++++++++ .../web/extension-system/build-and-publish.md | 102 +++++++ .../extension-system/extension-types/index.md | 6 - .../left-sidebar-menu-item-extensions.md | 92 ------- .../extensions/_category_.json | 4 + .../extensions/extension-points.md | 201 ++++++++++++++ .../extension-types/_category_.json | 0 .../extension-types/account-extensions.md | 46 ++++ .../extension-types/action-extensions.md | 10 +- .../app-menu-item-extensions.md | 8 +- .../custom-component-extensions.md | 7 +- .../floating-action-button-extensions.md | 16 +- .../extension-types/folder-view-extensions.md | 11 +- .../extensions/extension-types/index.md | 23 ++ .../left-sidebar-menu-item-extensions.md | 94 +++++++ .../right-sidebar-panel-extensions.md | 8 +- .../extension-types/search-extensions.md | 10 +- .../web/extension-system/extensions/index.md | 133 +++++++++ .../web/extension-system/getting-started.md | 178 ++++++++++++ .../dev/web/extension-system/index.md | 197 ++------------ .../dev/web/extension-system/packages.md | 21 ++ .../viewer-editor-apps/_category_.json | 4 + .../index.md} | 30 +-- .../version-7.2/dev/web/getting-started.md | 28 +- 59 files changed, 2801 insertions(+), 695 deletions(-) create mode 100644 docs/dev/web/extension-system/advanced-topics/_category_.json create mode 100644 docs/dev/web/extension-system/advanced-topics/configuration.md create mode 100644 docs/dev/web/extension-system/advanced-topics/styling.md create mode 100644 docs/dev/web/extension-system/advanced-topics/testing.md create mode 100644 docs/dev/web/extension-system/advanced-topics/translations.md create mode 100644 docs/dev/web/extension-system/build-and-publish.md delete mode 100644 docs/dev/web/extension-system/extension-types/index.md delete mode 100644 docs/dev/web/extension-system/extension-types/left-sidebar-menu-item-extensions.md create mode 100644 docs/dev/web/extension-system/extensions/_category_.json create mode 100644 docs/dev/web/extension-system/extensions/extension-points.md rename docs/dev/web/extension-system/{ => extensions}/extension-types/_category_.json (100%) create mode 100644 docs/dev/web/extension-system/extensions/extension-types/account-extensions.md rename docs/dev/web/extension-system/{ => extensions}/extension-types/action-extensions.md (92%) rename {versioned_docs/version-7.2/dev/web/extension-system => docs/dev/web/extension-system/extensions}/extension-types/app-menu-item-extensions.md (91%) rename {versioned_docs/version-7.2/dev/web/extension-system => docs/dev/web/extension-system/extensions}/extension-types/custom-component-extensions.md (80%) rename docs/dev/web/extension-system/{ => extensions}/extension-types/floating-action-button-extensions.md (76%) rename {versioned_docs/version-7.2/dev/web/extension-system => docs/dev/web/extension-system/extensions}/extension-types/folder-view-extensions.md (85%) create mode 100644 docs/dev/web/extension-system/extensions/extension-types/index.md create mode 100644 docs/dev/web/extension-system/extensions/extension-types/left-sidebar-menu-item-extensions.md create mode 100644 docs/dev/web/extension-system/extensions/extension-types/resource-indicator-extensions.md rename {versioned_docs/version-7.2/dev/web/extension-system => docs/dev/web/extension-system/extensions}/extension-types/right-sidebar-panel-extensions.md (95%) rename {versioned_docs/version-7.2/dev/web/extension-system => docs/dev/web/extension-system/extensions}/extension-types/search-extensions.md (93%) create mode 100644 docs/dev/web/extension-system/extensions/extension-types/vault-extensions.md create mode 100644 docs/dev/web/extension-system/extensions/index.md create mode 100644 docs/dev/web/extension-system/getting-started.md create mode 100644 docs/dev/web/extension-system/packages.md create mode 100644 docs/dev/web/extension-system/viewer-editor-apps/_category_.json create mode 100644 docs/dev/web/extension-system/viewer-editor-apps/collaborative-editing.md rename docs/dev/web/extension-system/{viewer-editor-apps.md => viewer-editor-apps/index.md} (73%) create mode 100644 versioned_docs/version-7.2/dev/web/extension-system/advanced-topics/_category_.json create mode 100644 versioned_docs/version-7.2/dev/web/extension-system/advanced-topics/configuration.md create mode 100644 versioned_docs/version-7.2/dev/web/extension-system/advanced-topics/styling.md create mode 100644 versioned_docs/version-7.2/dev/web/extension-system/advanced-topics/testing.md create mode 100644 versioned_docs/version-7.2/dev/web/extension-system/advanced-topics/translations.md create mode 100644 versioned_docs/version-7.2/dev/web/extension-system/build-and-publish.md delete mode 100644 versioned_docs/version-7.2/dev/web/extension-system/extension-types/index.md delete mode 100644 versioned_docs/version-7.2/dev/web/extension-system/extension-types/left-sidebar-menu-item-extensions.md create mode 100644 versioned_docs/version-7.2/dev/web/extension-system/extensions/_category_.json create mode 100644 versioned_docs/version-7.2/dev/web/extension-system/extensions/extension-points.md rename versioned_docs/version-7.2/dev/web/extension-system/{ => extensions}/extension-types/_category_.json (100%) create mode 100644 versioned_docs/version-7.2/dev/web/extension-system/extensions/extension-types/account-extensions.md rename versioned_docs/version-7.2/dev/web/extension-system/{ => extensions}/extension-types/action-extensions.md (86%) rename {docs/dev/web/extension-system => versioned_docs/version-7.2/dev/web/extension-system/extensions}/extension-types/app-menu-item-extensions.md (88%) rename {docs/dev/web/extension-system => versioned_docs/version-7.2/dev/web/extension-system/extensions}/extension-types/custom-component-extensions.md (80%) rename versioned_docs/version-7.2/dev/web/extension-system/{ => extensions}/extension-types/floating-action-button-extensions.md (79%) rename {docs/dev/web/extension-system => versioned_docs/version-7.2/dev/web/extension-system/extensions}/extension-types/folder-view-extensions.md (83%) create mode 100644 versioned_docs/version-7.2/dev/web/extension-system/extensions/extension-types/index.md create mode 100644 versioned_docs/version-7.2/dev/web/extension-system/extensions/extension-types/left-sidebar-menu-item-extensions.md rename {docs/dev/web/extension-system => versioned_docs/version-7.2/dev/web/extension-system/extensions}/extension-types/right-sidebar-panel-extensions.md (92%) rename {docs/dev/web/extension-system => versioned_docs/version-7.2/dev/web/extension-system/extensions}/extension-types/search-extensions.md (89%) create mode 100644 versioned_docs/version-7.2/dev/web/extension-system/extensions/index.md create mode 100644 versioned_docs/version-7.2/dev/web/extension-system/getting-started.md create mode 100644 versioned_docs/version-7.2/dev/web/extension-system/packages.md create mode 100644 versioned_docs/version-7.2/dev/web/extension-system/viewer-editor-apps/_category_.json rename versioned_docs/version-7.2/dev/web/extension-system/{viewer-editor-apps.md => viewer-editor-apps/index.md} (73%) diff --git a/docs/dev/web/extension-system/advanced-topics/_category_.json b/docs/dev/web/extension-system/advanced-topics/_category_.json new file mode 100644 index 000000000..c1aec597f --- /dev/null +++ b/docs/dev/web/extension-system/advanced-topics/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Advanced topics", + "position": 3 +} diff --git a/docs/dev/web/extension-system/advanced-topics/configuration.md b/docs/dev/web/extension-system/advanced-topics/configuration.md new file mode 100644 index 000000000..31436976a --- /dev/null +++ b/docs/dev/web/extension-system/advanced-topics/configuration.md @@ -0,0 +1,57 @@ +--- +title: 'Configuration' +sidebar_position: 1 +--- + +This page describes how to add configuration options to your app. Administrators can then change the behaviour of your +app. + +## Manifest and defaults + +Put static metadata of your app into `src/manifest.json`. It ends up in the `manifest.json` of your build, together with +the `name`, `version`, `description`, `license` and `author` fields of your `package.json`, and the entry point of your +app. + +Default values for the app config belong under the `config` key: + +```json title="src/manifest.json" +{ + "config": { + "maxFileSize": 10485760, + "showPreview": true + } +} +``` + +## Overriding values + +There are two ways to override the defaults: + +- During development, put your values into `src/config.json`. The file is merged on top of the `config` key of + `src/manifest.json`. Don't commit values that only apply to your machine. +- In a real deployment, administrators override them via the `apps.yaml` file, see the + [web applications admin docs](../../../../admin/configuration/web-applications). + +```json title="src/config.json" +{ + "showPreview": false +} +``` + +## Reading values in your app + +The merged config is passed to the `setup` function of your app definition as `applicationConfig`: + +```typescript title="src/index.ts" +import { defineWebApplication } from '@opencloud-eu/web-pkg'; + +export default defineWebApplication({ + setup({ applicationConfig }) { + const showPreview = applicationConfig?.showPreview ?? true; + + // ... + } +}); +``` + +Always provide a fallback value. The config can be empty, and an administrator can set any value. diff --git a/docs/dev/web/extension-system/advanced-topics/styling.md b/docs/dev/web/extension-system/advanced-topics/styling.md new file mode 100644 index 000000000..5d53fe175 --- /dev/null +++ b/docs/dev/web/extension-system/advanced-topics/styling.md @@ -0,0 +1,59 @@ +--- +title: 'Styling' +sidebar_position: 2 +--- + +This page describes how to style your app so that it fits into OpenCloud Web. + +## Design system components + +The `@opencloud-eu/design-system` package contains the components that OpenCloud Web is built with, for example buttons, +inputs and modals. Use them where possible. Your app then follows the platform look and inherits accessibility and +theming for free. See the [design system documentation](../../design-system) for the list of components. + +## Color roles + +OpenCloud Web exposes its colors as CSS variables with the `--oc-role-` prefix, for example `--oc-role-surface` or +`--oc-role-on-surface`. Always use these variables instead of fixed color values. They change with the active theme and +with the color scheme, so your app stays readable in light and dark mode. + +```css +.my-panel { + background-color: var(--oc-role-surface-container); + color: var(--oc-role-on-surface); +} +``` + +See [the defaults](https://github.com/opencloud-eu/web/blob/main/packages/design-system/src/styles/defaults.css) for a +complete list of color roles. + +## Tailwind CSS + +The `@opencloud-eu/extension-sdk` package ships a preconfigured [Tailwind CSS](https://tailwindcss.com/) setup. Import +its stylesheet in your entrypoint (typically `src/index.ts`) to use it: + +```typescript title="src/index.ts" +import '@opencloud-eu/extension-sdk/tailwind.css'; +``` + +Tailwind classes need the `ext:` prefix in apps. The prefix avoids style conflicts with the OpenCloud Web runtime. + +```html +
...
+``` + +The setup maps the color roles to Tailwind color utilities, so `--oc-role-surface` is available as `bg-role-surface`, +`text-role-on-surface` and so on: + +```html +
...
+``` + +It also sets the OpenCloud font family, a spacing unit of `4px`, the breakpoints `xs`, `sm`, `md`, `lg` and `xl`, and a +`dark` variant. The `dark` variant follows the color scheme of OpenCloud Web, not the browser setting: + +```html +
...
+``` + +In most cases you do not need the `dark` variant, because the color roles already handle both color schemes. diff --git a/docs/dev/web/extension-system/advanced-topics/testing.md b/docs/dev/web/extension-system/advanced-topics/testing.md new file mode 100644 index 000000000..5a8094d4c --- /dev/null +++ b/docs/dev/web/extension-system/advanced-topics/testing.md @@ -0,0 +1,41 @@ +--- +title: 'Testing' +sidebar_position: 4 +--- + +This page describes how to test your app. + +## Unit tests + +The [web-app-skeleton repository](https://github.com/opencloud-eu/web-app-skeleton) comes with a +[vitest](https://vitest.dev/) setup. Run the unit tests with: + +```bash +pnpm test:unit +``` + +## Test helpers + +The `@opencloud-eu/web-test-helpers` package provides utilities for mounting components with a mocked OpenCloud Web +context. Without them, every component that uses a composable of `web-pkg` fails to mount. + +```typescript title="tests/unit/App.spec.ts" +import { defaultPlugins, mount } from '@opencloud-eu/web-test-helpers'; +import App from '../../src/App.vue'; + +describe('App', () => { + it('renders the title', () => { + const wrapper = mount(App, { global: { plugins: [...defaultPlugins()] } }); + expect(wrapper.text()).toContain('My app'); + }); +}); +``` + +For details, please refer to the package's +[README.md](https://github.com/opencloud-eu/web/blob/main/packages/web-test-helpers/README.md). + +## End to end tests + +For end to end tests with [Playwright](https://playwright.dev/), the +[web](https://github.com/opencloud-eu/web) and [web-extensions](https://github.com/opencloud-eu/web-extensions) +repositories contain working examples. diff --git a/docs/dev/web/extension-system/advanced-topics/translations.md b/docs/dev/web/extension-system/advanced-topics/translations.md new file mode 100644 index 000000000..0485a2686 --- /dev/null +++ b/docs/dev/web/extension-system/advanced-topics/translations.md @@ -0,0 +1,138 @@ +--- +title: 'Translations' +sidebar_position: 3 +--- + +OpenCloud Web uses [gettext](https://www.gnu.org/software/gettext/) for translations, via the +[vue3-gettext](https://jshmrtn.github.io/vue3-gettext/) library. Your app brings its own translations and hands them to +the Web runtime. The language that the user picked in OpenCloud is then also used for your app. + +Translations are optional. An app without them simply shows its original strings. + +## Marking strings + +In a script or a composable, get `$gettext` from `useGettext`: + +```typescript +import { useGettext } from 'vue3-gettext'; + +const { $gettext } = useGettext(); + +const title = $gettext('Your application name'); +``` + +In a template, `$gettext` is globally available: + +```html + +``` + +Pass variables as an object. Use the `%{name}` syntax in the string, never string concatenation, because the word order +changes between languages: + +```typescript +$gettext('Open «%{resource}»', { resource: resource.name }); +``` + +For plurals, use `$ngettext` with the singular form, the plural form, the count, and the variables: + +```typescript +const { $ngettext } = useGettext(); + +$ngettext( + 'Delete the selected resource?', + 'Delete %{amount} selected resources?', + resources.length, + { amount: resources.length.toString() } +); +``` + +:::warning +The extraction tool reads your source code, not your runtime values. Always pass a plain string literal to `$gettext`. +A variable or a template literal cannot be extracted. +::: + +## Setting up the workflow + +Add [vue3-gettext](https://jshmrtn.github.io/vue3-gettext/) as a dev-dependency. It ships the `vue-gettext-extract` and +`vue-gettext-compile` commands. + +Create a `gettext.config.cjs` in the root of your app. It defines which files are scanned and which languages you +support: + +```javascript title="gettext.config.cjs" +module.exports = { + input: { + path: './src', + include: ['**/*.js', '**/*.ts', '**/*.vue'] + }, + output: { + locales: ['de', 'es', 'fr', 'it'], + path: './l10n/locale', + potPath: '../template.pot', + jsonPath: '../translations.json', + flat: false, + linguas: false + } +}; +``` + +Add two scripts to your `package.json`: + +```json title="package.json" +{ + "scripts": { + "l10n:extract": "vue-gettext-extract", + "l10n:compile": "vue-gettext-compile" + } +} +``` + +`l10n:extract` collects all marked strings into `l10n/template.pot` and creates one `.po` file per language under +`l10n/locale`. Run it whenever you add or change a string. + +`l10n:compile` turns the `.po` files into a single `l10n/translations.json`. Run it after the translated `.po` files +come back. Commit `translations.json`, because the build imports it. + +How the `.po` files get translated is up to you. The OpenCloud repositories use +[Transifex](https://www.transifex.com/), but any gettext based service or a manual workflow works as well. + +## Registering translations + +Import `translations.json` and return it from your app definition. The Web runtime merges it into the global +translations when your app is loaded. + +```typescript title="src/index.ts" +import { defineWebApplication } from '@opencloud-eu/web-pkg'; +import { useGettext } from 'vue3-gettext'; +import translations from '../l10n/translations.json'; + +export default defineWebApplication({ + setup() { + const { $gettext } = useGettext(); + + return { + appInfo: { + name: $gettext('Your application name'), + id: 'your-app' + }, + translations + }; + } +}); +``` + +The file is a map of language key to message map: + +```json title="l10n/translations.json" +{ + "de": { + "No files here": "Keine Dateien hier" + }, + "fr": { + "No files here": "Aucun fichier ici" + } +} +``` diff --git a/docs/dev/web/extension-system/build-and-publish.md b/docs/dev/web/extension-system/build-and-publish.md new file mode 100644 index 000000000..238c63a6c --- /dev/null +++ b/docs/dev/web/extension-system/build-and-publish.md @@ -0,0 +1,104 @@ +--- +title: 'Build and publish' +sidebar_position: 2 +--- + +This page describes how to build your app for production and how to publish it in the OpenCloud app store. + +## Building an app + +Run a production build: + +```bash +pnpm build +``` + +The build writes your app into the `dist` folder. Static assets from a `public` folder are copied over as is. The result +contains: + +- `js/-.mjs` - the entry point of your app, plus its chunks. +- `manifest.json` - the metadata that OpenCloud uses to discover and load your app. +- any static assets of your app. + +The generated `manifest.json` merges your `src/manifest.json` with the `name`, `version`, `description`, `license` and +`author` fields of your `package.json`. The `entrypoint` key is set by the build. + +```json title="dist/manifest.json" +{ + "name": "my-app", + "version": "1.0.0", + "description": "My OpenCloud app", + "license": "Apache-2.0", + "author": "Me", + "entrypoint": "js/my-app-a1b2c3d4.mjs" +} +``` + +## Publishing in the app store + +Apps in the OpenCloud app store are listed in the +[awesome-apps repository](https://github.com/opencloud-eu/awesome-apps). Publishing means adding your app to its +`webApps/apps.json` file via a pull request. + +### Requirements + +- Your app must be downloadable as a `.zip` file from a stable URL, for example a GitHub release asset. +- The zip must contain a `manifest.json` in its root, next to your built files. A production build produces this + already, so zip the content of your `dist` folder, not the folder itself. + +### apps.json entry + +Add one entry under the `apps` key. The schema is defined in the +[app store types](https://github.com/opencloud-eu/web/blob/main/packages/web-app-app-store/src/types.ts). + +```json title="webApps/apps.json" +{ + "id": "com.github.my-org.my-repo.my-app", + "name": "My App", + "subtitle": "One short line about what the app does.", + "description": "A longer description.", + "license": "Apache-2.0", + "versions": [ + { + "version": "1.0.0", + "minOpenCloud": "8.0.0", + "url": "https://github.com/my-org/my-repo/releases/download/v1.0.0/my-app-1.0.0.zip" + } + ], + "authors": [{ "name": "My Organization", "url": "https://example.org" }], + "tags": ["editor", "viewer"], + "coverImage": { + "url": "https://raw.githubusercontent.com/opencloud-eu/awesome-apps/main/webApps/my-org/my-repo/cover.png" + }, + "screenshots": [ + { + "url": "https://raw.githubusercontent.com/opencloud-eu/awesome-apps/main/webApps/my-org/my-repo/screenshots/1.png", + "caption": "What this screenshot shows" + } + ], + "resources": [ + { "url": "https://github.com/my-org/my-repo", "label": "Source code", "icon": "github" } + ] +} +``` + +Notes on the fields: + +- `versions` must be sorted from newest to oldest. `minOpenCloud` is the lowest OpenCloud version your app supports. +- `badge` is optional and accepts a `label` and a `color` of `primary`, `success` or `danger`. +- `screenshots` and `resources` are optional. + +### Assets + +Cover image and screenshots are stored in the awesome-apps repository. Use a 3:2 aspect ratio and prefer PNG or JPEG. + +Follow this folder structure: + +- `webApps///cover.png` +- `webApps///screenshots/1.png` + +If your repository hosts several apps, add the app name to the path, for example +`webApps////cover.png`. + +Make sure the license of your assets allows us to keep them in the repository and to show them in the app store. If you +are not sure about the license of an asset, do not add it. diff --git a/docs/dev/web/extension-system/extension-types/index.md b/docs/dev/web/extension-system/extension-types/index.md deleted file mode 100644 index a6f04677d..000000000 --- a/docs/dev/web/extension-system/extension-types/index.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: 'Extension Types' ---- - -This section is a guide about the different predefined extension types of OpenCloud Web. Please refer to the respective -subpages to learn more about the individual extension types. diff --git a/docs/dev/web/extension-system/extension-types/left-sidebar-menu-item-extensions.md b/docs/dev/web/extension-system/extension-types/left-sidebar-menu-item-extensions.md deleted file mode 100644 index 7d7e171e0..000000000 --- a/docs/dev/web/extension-system/extension-types/left-sidebar-menu-item-extensions.md +++ /dev/null @@ -1,92 +0,0 @@ ---- -title: 'Left sidebar menu item extensions' -sidebar_position: 5 -id: left-sidebar-menu-item-extensions ---- - -## Left sidebar menu item extension type - -One possible extension type is left sidebar menu items. Registered left sidebar menu items get rendered in the left sidebar, as long as there is more than one available. - -### Configuration - -To define a left sidebar menu item, you implement the SidebarNavExtension interface. -It looks like this: - -```typescript -interface SidebarNavExtension { - id: string - type: 'sidebarNav' - extensionPointIds?: string[] - navItem: AppNavigationItem // Please check the AppNavigationItem section below - } -} -``` - -For `id`, `type`, and `extensionPointIds`, please see [extension base section](../#extension-base-configuration) in the top level docs. - -#### AppNavigationItem - -The most important configuration options are: - -- `icon` - The icon to be displayed, can be picked from [Remix Icon](https://remixicon.com/) -- `name` - The text to be displayed -- `route` - The string/route to navigate to, if the nav item should be a `` (Mutually exclusive with `handler`) -- `handler` - The action to perform upon click, if the nav item should be a `