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
37 changes: 21 additions & 16 deletions docs/dev/web/development/conventions.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
---
title: 'Conventions'
sidebar_position: 1
sidebar_position: 3
id: conventions
---



This is a collection of tips and conventions to follow when working on the [OpenCloud Web frontend](https://github.com/opencloud-eu/web).
Since it is a living document, please open a PR if you find something missing.

Expand All @@ -15,14 +13,12 @@ Everyone is invited to contribute. Simply fork the [codebase](https://github.com
check the [issues](https://github.com/opencloud-eu/web/issues?q=is%3Aopen%20is%3Aissue%20label%3AType%3AGood-First-Issue)
for a suitable one and open a pull request!

### Linting and Tests
### Formal checks

To make sure your pull request can be efficiently reviewed and won't need a lot of changes down the road, please run the linter and
the unit tests via `pnpm lint --fix` and `pnpm test:unit` locally. Our [CI](https://drone.opencloud.eu/opencloud/web) will run on
To make sure your pull request can be efficiently reviewed and won't need a lot of changes down the road, please run all formal checks (linter, formatter, type checks and unit tests) via `pnpm check:all` locally. Our [CI](https://ci.opencloud.eu/repos/6) will run on
pull requests and report back any problems after that. For a further introduction on how we handle testing, please head to
the [testing docs](./../testing/running-tests.md).


## Code Conventions

### Early Returns
Expand All @@ -31,20 +27,29 @@ We're trying to stick with early returns in our code to make it more performant

### Translations

Use the `v-text` directive in combination with `$gettext` (or a variation of it) inside HTML tags (instead of
a `<translate tag="h1">` or similar) in order to make reasoning about the DOM tree easier.
Use `$gettext` (or a variation of it) inside HTML tags (instead of a `<translate tag="h1">` or similar) in order to translate strings.

### TypeScript

We're using TypeScript, which allows us to catch bugs at transpile time. Clean types make sure our IDEs can support us
in reasoning about our (ever growing, complex) codebase.
We're using TypeScript which allows us to catch bugs at transpile time. Clean types make sure our IDEs can support us in reasoning about our ever-growing, complex codebase.

### Composition API and script setup

We prefer using Vue's Composition API in combination with [script setup](https://vuejs.org/api/sfc-script-setup) over the traditional options API. This integrates nicely with TypeScript and allows us to use composables and reactive APIs more effectively.

That being said, due to the fact that we are still in the process of migrating our codebase, you might find some files using the options API or even composition API without script setup. We are working on this and will eventually migrate all files.

### Composables

We make heavy use of composables to encapsulate reusable logic. This allows us to share code between components and keep our components clean and focused on their specific tasks.

### Split large components

If a component is getting too big, consider splitting it into smaller components. This will make it easier to read and maintain. A good rule of thumb is to keep components under 300 lines of code.

### Vue 3 and Composition API
### Services

We've migrated from Vue 2 to Vue 3 late in 2022 and since then have been investing continuous efforts to move away from the Vue options API
in favor of the Vue composition API. The `web-pkg` helper package provides quite some composables which will help you in
app & extension development, so we encourage you to make use of the Vue composition API as well, even outside of the
OpenCloud Web repository.
We try to avoid services when possible and rather use composables instead. If writing a service is necessary, it should be instantiated once via the `web-runtime` package and then made available via a `useYourService` composable.

### Dependencies

Expand Down
35 changes: 18 additions & 17 deletions docs/dev/web/development/repo-structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ sidebar_position: 2
id: repo-structure
---



## Repository Structure

From a developer's perspective, the most important parts of the [OpenCloud Web repo](https://github.com/opencloud-eu/web) are the following files and folders:
Expand All @@ -26,10 +24,7 @@ Having these packages side by side within the `/packages` folder of the repo is

### tests Folder

We're using [Playwright](https://playwright.dev) for UI testing. The UI tests are located in `/tests/e2e`.

You're more than welcome to make a pull request and adjust this section of the docs accordingly. :-)
You can read more about testing in our [testing section](./../testing/running-tests.md)
We're using [Playwright](https://playwright.dev) for UI testing. The UI tests are located in `/tests/e2e`. You can read more about testing in our [testing docs](./../testing/running-tests.md).

### package.json File

Expand All @@ -41,7 +36,7 @@ Each package in `/packages` can and most likely will contain another `package.js
We're working with [Vite](https://vitejs.dev) as a local development server and build tool. `vite.config.ts` is the main configuration file for that.
You can read more about the usage in our [tooling section](./../development/tooling.md).

## (Published) Packages
## Packages

Each package in the `/packages` folder can - not exclusively, but most commonly - consist of

Expand All @@ -61,18 +56,16 @@ Namely those packages are
- `/packages/eslint-config`
- `/packages/extension-sdk`
- `/packages/prettier-config`
- `/packages/tsconfig/`
- `/packages/tsconfig`

### OpenCloud Design System

The OpenCloud Design System (`/packages/design-system`) is a collection of components, design tokens and styles which ensure a
unique and consistent look and feel and branding throughout the OpenCloud Web ecosystem. We hope that you use it, too, so that your
very own apps and extensions will blend in with all the others. Documentation and code examples can be found in
the [design system documentation](https://opencloud.design).
the [design system documentation](https://docs.opencloud.eu/design-system/).

The OpenCloud Design System is a standalone project, but to make development easier we have the code in our mono repo.
We're planning to publish it on npmjs.com as [@opencloud-eu/design-system](https://www.npmjs.com/package/@opencloud-eu/design-system)
as soon as possible. Since it's bundled with OpenCloud Web, you should not bundle it with your app or extension.
The OpenCloud Design System is a standalone project that gets published on npmjs.com as [@opencloud-eu/design-system](https://www.npmjs.com/package/@opencloud-eu/design-system). Since it's bundled with OpenCloud Web, you should not bundle it with your app or extension. However, you can add it as a dev dependency for better IDE support.

### web-client

Expand Down Expand Up @@ -102,22 +95,30 @@ have more questions about this package, please write an issue in our [issue trac

### Standalone Core Apps

Both `web-app-admin-settings` and `web-app-files` are standalone apps which are bundled with the default OpenCloud Web release artifact.
The repo also includes some standalone apps which are bundled with the default OpenCloud Web release artifact.

- `web-app-activities`
- `web-app-admin-settings`
- `web-app-app-store`
- `web-app-files`
- `web-app-ocm`
- `web-app-search`
- `web-app-webfinger`

### Viewer and Editor Apps

Apps which fall into the categories `viewer` or `editor` can be opened from the context of a file or folder. This mostly happens from
within the `files` app. We currently bundle the following apps with the default OpenCloud Web release artifact:

- `web-app-epub-reader` a simple reader for `.epub` files
- `web-app-external` an iframe integration of all the apps coming from the [app provider](https://docs.opencloud.eu/services/app-provider/)
(e.g. OnlyOffice, Collabora Online and others)
- `web-app-external` an iframe integration of all the apps coming from the app provider
(e.g. Collabora Online, OnlyOffice and others)
- `web-app-pdf-viewer` a viewer for `.pdf` files, which relies on native PDF rendering support from the browser
- `web-app-preview` a viewer for various media files (audio / video / image formats)
- `web-app-text-editor` a simple editor for `.txt`, `.md` and other plain text files

If you're interested in writing your own viewer or editor app for certain file types, please get in touch with us for more info.
If you're interested in writing your own viewer or editor app for certain file types, please have a look at the [extension system docs](./../extension-system).

### Testing

Additional unit testing code lives in `test-helpers`.
Basic setup and helpers for unit testing lives in `web-test-helpers`. This package gets published on npmjs.com as [@opencloud-eu/web-test-helpers](https://www.npmjs.com/package/@opencloud-eu/web-test-helpers) to ensure its functionality can be used anywhere inside the OpenCloud Web ecosystem.
33 changes: 25 additions & 8 deletions docs/dev/web/development/tooling.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
---
title: 'Tooling'
sidebar_position: 3
sidebar_position: 1
id: tooling
---



## Packaging

Web is using [pnpm](https://pnpm.io/) as package manager and [vite](https://vitejs.dev/) as build tool. The latter is built on top of [rollup](https://rollupjs.org/) and brings some additional features such as instant hot-reloading.
Expand All @@ -14,29 +12,48 @@ Web is using [pnpm](https://pnpm.io/) as package manager and [vite](https://vite

### Prerequisites

Please make sure you have the following tools installed on your system:

- docker
- docker-compose (if not already included in your docker installation)
- pnpm
- node
- pnpm (we recommend the installation via `corepack` which is included in newer node versions)

:::note
If you’re not using Docker Desktop, you might have to modify your `/etc/hosts` and add `127.0.0.1 host.docker.internal` to make `host.docker.internal` links work.
:::

:::note
This setup currently doesn't work on Windows out of the box.

<details>
<summary>Workaround</summary>

One of our contributors has opened a PR to a dependency that prevents us from successfully bundling the frontend.
Feel free to check out [their changes](https://github.com/egoist/rollup-plugin-postcss/pull/384) and build them locally if you absolutely want to work on Windows.
</details>
:::

### Installing Dependencies

After cloning the source code, install the dependencies via `pnpm install`.

### Starting the Server

You can start the server by running `docker-compose up opencloud`.

Note that the container needs a short while to start because it is waiting for `tika` to be initialized. This is the case as soon as the `tika-service` container has stopped running.
You can start the OpenCloud server by running `docker-compose up opencloud -d`. If you want to run the full stack, you can run `docker-compose up -d` instead. This will also start the wopi service and an instance of Collabora.

### Building and Accessing Web

After the docker containers are running (and `tika` is being initialized), run `pnpm build:w` to build Web. This also includes hot-reloading after changes you make, although it will take a while to rebuild the project. See down below for some details on how to enable instant hot-reloading.
After starting the docker containers, you can build Web by running `pnpm build:w`. This command compiles the project and includes support for hot-reloading, allowing you to see changes as you make them. However, note that the rebuild process may take some time.

For a faster development experience, consider enabling instant hot-reloading. Details on how to set this up are provided below.

Now you can access Web via https://host.docker.internal:9200.

### Using Instant Hot-Reload via Vite

To work with instant hot-reloading, you can also build Web by running `pnpm vite`. The port to access Web is slightly different then: https://host.docker.internal:9201. Also note that the initial page load may take a bit longer than usual. This is normal and to be expected.

:::note
Make sure that you ran `pnpm build` once before starting the server with `pnpm vite`. Also, you need to accept the self-signed certificate in your browser for https://host.docker.internal:9200 _and_ https://host.docker.internal:9201.
:::
18 changes: 9 additions & 9 deletions docs/dev/web/embed-mode.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ title: 'Embed Mode'
sidebar_position: 4
---



The OpenCloud Web can be consumed by another application in a stripped down version called "Embed mode". This mode is supposed to be used in the context of selecting or sharing resources. If you're looking for even more minimalistic approach, you can take a look at the [File picker](https://docs.opencloud.eu/integration/file_picker/).
The OpenCloud Web can be consumed by another application in a stripped down version called "Embed mode". This mode is supposed to be used in the context of selecting or sharing resources.

## Getting started

Expand All @@ -27,11 +25,11 @@ By default, the `postMessage` method does not specify the `targetOrigin` paramet

To maintain uniformity and ease of handling, each event encapsulates the same structure within its payload: `{ name: string, data: any }`.

| Name | Data | Description |
| -------------------------- | ---------- | ------------------------------------------------------------------------------------- |
| **opencloud-embed:select** | Resource[] | Gets emitted when user selects resources or location via the select action |
| **opencloud-embed:share** | string[] | Gets emitted when user selects resources and shares them via the "Share links" action |
| **opencloud-embed:cancel** | null | Gets emitted when user attempts to close the embedded instance via "Cancel" action |
| Name | Data | Description |
| -------------------------- | ------------ | ------------------------------------------------------------------------------------- |
| **opencloud-embed:select** | `Resource[]` | Gets emitted when user selects resources or location via the select action |
| **opencloud-embed:share** | `string[]` | Gets emitted when user selects resources and shares them via the "Share links" action |
| **opencloud-embed:cancel** | `null` | Gets emitted when user attempts to close the embedded instance via "Cancel" action |

### Example

Expand Down Expand Up @@ -61,7 +59,9 @@ In special scenarios you also want the user to set a file name, this can be achi
### Example

```html
<iframe src="https://my-opencloud-web-instance?embed=true&embed-target=location"></iframe>
<iframe
src="https://my-opencloud-web-instance?embed=true&embed-target=location"
></iframe>

<script>
function selectEventHandler(event) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ sidebar_position: 1
id: action-extensions
---



## Action extension type

Actions are one of the possible extension types. Registered actions get rendered in various places across the UI, depending on their scope and targets.
Expand All @@ -23,13 +21,13 @@ interface ActionExtension {
}
```

For `id`, `type`, and `extensionPointIds`, please see [extension base section](./../index.md) in the top level docs.
For `id`, `type`, and `extensionPointIds`, please see [extension base section](./../#extension-base-configuration) in the top level docs.

#### Action

The most important configuration options are:

- `icon` - The icon to be displayed, can be picked from https://opencloud.design/#/Design%20Tokens/IconList
- `icon` - The icon to be displayed, can be picked from [Remix Icon](https://remixicon.com/)
- `name` - The name of the action (not displayed in the UI)
- `label` - The text to be displayed
- `route` - The string/route to navigate to. The nav item will be a `<router-link>` tag.
Expand All @@ -49,7 +47,7 @@ export const useDownloadFilesExtension = () => {

const extension = computed<ActionExtension>(() => ({
id: 'com.github.opencloud-eu.web.files.download-action',
scopes: ['resource'],
extensionPointIds: ['global.files.context-actions'],
type: 'action',
action: {
name: 'download-files',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ sidebar_position: 2
id: app-menu-item-extensions
---



## Extension Type AppMenuItem

This extension type allows apps to register links to internal or external pages within the application switcher menu on the top left.
Expand All @@ -29,7 +27,7 @@ interface AppMenuItemExtension {
}
```

For `id`, `type`, and `extensionPointIds`, please see [extension base section](./../index.md) in the top level docs.
For `id`, `type`, and `extensionPointIds`, please see [extension base section](./../#extension-base-configuration) in the top level docs.

A `handler` will result in a `<button>` element. This is necessary when an action should be performed when clicking the menu item (e.g. opening a file editor).

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ sidebar_position: 3
id: custom-component-extensions
---



## Extension Type CustomComponent

CustomComponent extensions need to define one or multiple `extensionPointId`s as render target. A `CustomComponentTarget` component for this very
Expand All @@ -25,7 +23,7 @@ interface CustomComponentExtension {
}
```

For `id`, `type`, and `extensionPointIds`, please see [extension base section](./../index.md) in the top level docs.
For `id`, `type`, and `extensionPointIds`, please see [extension base section](./../#extension-base-configuration) in the top level docs.

The `content` property specifies a render function or a Component for the target extension point.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ interface FolderViewExtension {
}
```

For `id`, `type`, and `extensionPointIds`, please see [extension base section](./../index.md) in the top level docs.
For `id`, `type`, and `extensionPointIds`, please see [extension base section](./../#extension-base-configuration) in the top level docs.

#### FolderView

For the folderView object, you have the following configuration options:

- `name` - The name of the action (not displayed in the UI)
- `label` - The text to be displayed to the user when switching between different FolderView options
- `icon` - Object, expecting an icon `name` and a corresponding `IconFillType`, see https://opencloud.design/#/Design%20Tokens/IconList for available options
- `icon` - Object, expecting an icon `name` and a corresponding `IconFillType`, see [Remix Icon](https://remixicon.com/) for available options
- `isScrollable` - Optional boolean, determines whether the user can scroll inside the component or it statically fills the viewport
- `component` - The Vue component to render the resources. It should expect a prop of type `Resource[]`
- `componentAttrs` - Optional additional configuration for the component mentioned above
Expand All @@ -45,7 +45,7 @@ export const useCustomFolderViewExtension = () => {
const extension = computed<FolderViewExtension>(() => ({
id: 'com.github.opencloud-eu.web.files.folder-view.custom',
type: 'folderView',
scopes: ['resource', 'space', 'favorite'],
extensionPointIds: ['app.files.folder-views.folder'],
folderView: {
name: 'custom-table',
label: $gettext('Switch to custom folder view'),
Expand Down
Loading