Skip to content
Open
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
12 changes: 12 additions & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,16 @@ module.exports = {
'jsdoc/require-jsdoc': 'off',
'vue/first-attribute-linebreak': 'off',
},
overrides: [
{
// @nextcloud/eslint-config uses @babel/eslint-parser for .vue files,
// which cannot parse TypeScript in <script setup lang="ts">.
// Override to use @typescript-eslint/parser as the inner parser.
files: ['**/*.vue'],
parser: 'vue-eslint-parser',
parserOptions: {
parser: '@typescript-eslint/parser',
},
},
],
}
5 changes: 5 additions & 0 deletions .stylelintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module.exports = {
extends: [
'@nextcloud/stylelint-config',
],
}
106 changes: 91 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,101 @@
# Office

A template to get started with Nextcloud app development.
A Nextcloud app that provides a dedicated hub for office documents. Users can browse,
filter, search, and create Documents, Spreadsheets, Presentations, and Diagrams from
a single page — without going through the Files app.

## Usage
---

- To get started easily use the [Appstore App generator](https://apps.nextcloud.com/developer/apps/generate) to
dynamically generate an App based on this repository with all the constants prefilled.
- Alternatively you can use the "Use this template" button on the top of this page to create a new repository based on
this repository. Afterwards adjust all the necessary constants like App ID, namespace, descriptions etc.
## Features

Once your app is ready follow the [instructions](https://nextcloudappstore.readthedocs.io/en/latest/developer.html) to
upload it to the Appstore.
- **Overview page** at `/apps/office` — categorised file list with sidebar navigation
- **Filters** — All / Mine / Shared with me
- **Search** — within the active category, with an "Open in Files" escape hatch
- **View toggle** — Grid (thumbnail previews) or List, persisted per user
- **Template creator** — create new files from editor-provided templates
- **Editor integration** — opens files directly in the configured office editor

## Resources
---

### Documentation for developers:
## Local development

- General documentation and tutorials: https://nextcloud.com/developer
- Technical documentation: https://docs.nextcloud.com/server/latest/developer_manual
### Requirements

### Help for developers:
- [nextcloud-docker-dev](https://github.com/juliushaertl/nextcloud-docker-dev)
- NC ≥ 33
- Node 24 / npm 11

- Official community chat: https://cloud.nextcloud.com/call/xs25tz5y
- Official community forum: https://help.nextcloud.com/c/dev/11
### 1. Mount the app into the container

Add to `nextcloud-docker-dev/docker-compose.override.yml`:

```yaml
services:
nextcloud:
volumes:
- /path/to/office:/var/www/html/apps-extra/office
```

Restart the container after saving.

### 2. Enable the app

```bash
docker exec -u www-data nextcloud-docker-dev-nextcloud-1 \
php occ app:enable office
```

### 3. Build the frontend

```bash
npm ci
npm run build # one-off build
npm run watch # rebuild on file changes
```

---

## Editor integration

The overview opens files using a URL provided by the backend at page load
(`editor-url` via NC initial state). The behaviour depends on which editor
is configured.

### With the WOPI backend

When the WOPI backend is active, `PageController` injects the editor's open
route. Clicking a file navigates directly to the full-page editor, and closing
the editor (`history.back()`) returns the user to the overview.

See the `feat/wopi-phase-4` branch for the WOPI backend implementation.

### With eurooffice (transitional)

When no WOPI backend is present, the app falls back to NC's file shortlink
(`/f/{fileid}`), which redirects to the Files app and triggers eurooffice's
default file action. The editor opens in the Files app context — closing it
returns the user to the Files app, not the overview.

To prevent eurooffice from intercepting opens during testing:

```bash
docker exec -u www-data nextcloud-docker-dev-nextcloud-1 \
php occ app:disable eurooffice
```

---

## Architecture

```
/apps/office
└── PageController::index() Renders the SPA shell; injects editor-url initial state
└── OfficeOverview.vue Full Vue 3 SPA
├── officeFiles.ts WebDAV file listing via @nextcloud/files
├── templates.ts Template discovery and file creation
└── config.ts User preference persistence (grid/list view)
```

The frontend reads `editor-url` from NC initial state on load. If null, it falls
back to the `/f/{fileid}` shortlink. The backend sets this value to the WOPI
editor route when the WOPI implementation is active.
2 changes: 1 addition & 1 deletion appinfo/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<category>office</category>
<bugs>https://github.com/nextcloud/office</bugs>
<dependencies>
<nextcloud min-version="31" max-version="32"/>
<nextcloud min-version="33" max-version="35"/>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

35, since we want to bundle with server release we will need a separate branch for each stable version (35 is against server master now).

We can branch off once this is merged then.

</dependencies>
<navigations>
<navigation>
Expand Down
5 changes: 4 additions & 1 deletion img/app-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 4 additions & 1 deletion img/app.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions lib/Controller/PageController.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,29 @@
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
use OCP\AppFramework\Http\Attribute\OpenAPI;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\AppFramework\Services\IInitialState;
use OCP\IRequest;

/**
* @psalm-suppress UnusedClass
*/
class PageController extends Controller {
public function __construct(
string $appName,
IRequest $request,
private IInitialState $initialState,
) {
parent::__construct($appName, $request);
}

#[NoCSRFRequired]
#[NoAdminRequired]
#[OpenAPI(OpenAPI::SCOPE_IGNORE)]
#[FrontpageRoute(verb: 'GET', url: '/')]
public function index(): TemplateResponse {
// Null until a WOPI backend branch provides a concrete editor route.
// The overview Vue component falls back to /f/{fileid} when this is null.
$this->initialState->provideInitialState('editor-url', null);
return new TemplateResponse(
Application::APP_ID,
'index',
Expand Down
Loading
Loading