1
0
mirror of https://github.com/owncloud/ocis.git synced 2026-10-23 23:29:02 +03:00

[full-ci] chore: [OCISDEV-5] merge and relicense ownCloud Web into oCIS (#12491)

* chore: [OCISDEV-5] Merge and relicense ownCloud Web into oCIS

Consolidate the ownCloud Web frontend into this repository as a single
product with one contribution surface and one license. The web/ source
is imported as-is from the final standalone owncloud/web release
(v12.5.0 / last-agpl-release @ b16a34fdf5569d2fd63b1ff3c575c1a4ee569ad3);
the archived owncloud/web repository remains the historical record for
everything at and before that commit.

Relicensing:
- All web/ contributors have signed the ownCloud CLA, granting ownCloud
  GmbH the right to relicense their contributions.
- web/LICENSE (AGPL-3.0) removed; the repository root LICENSE
  (Apache-2.0) now governs web/ as well, matching how the rest of the
  repo is already licensed.
- All 25 web/packages/*/package.json license fields flipped to
  Apache-2.0; root NOTICE added documenting the relicensing provenance.
- Added REUSE.toml + LICENSES/ so the whole repository (including
  vendored Go dependencies) is REUSE 3.3 compliant.

CI/build:
- services/web/Makefile now builds web assets from the in-tree source
  instead of downloading a release tarball from owncloud/web; license
  checking/saving likewise runs against the in-tree source.
- ci.env and tests/acceptance/run-e2e.py no longer clone owncloud/web
  for Playwright e2e tests.
- Added the app-provider and ocm e2e suites to acceptance-tests.yml's
  matrix, closing a coverage gap where they were silently excluded;
  ported the Collabora/OnlyOffice/federated-instance orchestration
  web's old CI used to run them.
- Added web-tests.yml (typecheck/format/lint/unit-test), a
  check-licenses.yml, commit-message.yml, and release-npm-packages.yml
  for the @ownclouders/* packages, replacing web's old standalone CI.
- Removed dead CI tooling inherited from the standalone repo
  (web/tests/drone, web/tests/actions, web/.github, and an orphaned
  ci.env-dependent cache-check script).

Docs:
- Rewrote docs/services/web/releasing.md and web/docs/releasing to
  describe the in-tree build/release process.
- Updated remaining references to github.com/owncloud/web across docs,
  services/web/README.md, and the deployment example to point at the
  in-tree web/ directory.

Signed-off-by: Lukas Hirt <info@hirt.cz>

* ci: sync web/ translations via Transifex

web/ is a pnpm workspace nested inside the repo, so it isn't covered by
the existing translation-sync job (sub_path: ., no package.json at the
repo root). Add a second sync-web job invoking the same reusable
workflow with sub_path: web and package_manager: pnpm, so its l10n-read/
push/pull/write targets actually install web's dependencies instead of
silently running against an empty node_modules. Sequenced after the
existing sync job since both push to the same hardcoded
chore/translations-update branch.

* ci: fix pnpm cache setup order in web-tests and check-licenses

actions/setup-node's cache: pnpm input shells out to pnpm to resolve
the cache directory, so pnpm must already be on PATH when that step
runs. Both workflows ran `corepack enable` *after* setup-node, which
still failed: corepack writes its pnpm shim into the currently active
Node installation's bin dir, and setup-node had already swapped PATH
to the newly-installed Node version by that point, leaving the shim
behind. Use pnpm/action-setup instead, which installs a standalone
pnpm binary independent of the Node version, before setup-node runs.

Also set cache-dependency-path explicitly: the lockfile lives at
web/pnpm-lock.yaml, and cache-dependency-path resolves relative to
GITHUB_WORKSPACE regardless of the job's working-directory default
(that default only applies to run: steps, not to setup-node itself).

* fix(web): resolve 19 HIGH trivy findings in pnpm-lock.yaml

All 19 findings had fixes available upstream, so per this repo's own
.trivyignore policy (reserved for cases with no fix available), these
get fixed rather than suppressed.

vite (7.3.2 -> 7.3.5) is a direct dependency, bumped directly in every
package.json that pins it.

The other 8 (@xmldom/xmldom, flatted, form-data, immutable, js-cookie,
linkify-it, minimatch, ws) are purely transitive. Verified empirically
that `pnpm update <pkg>` silently no-ops on packages not declared in
any workspace manifest, even when a parent's semver range would allow
the fix (e.g. glob@10.5.0's `^9.0.4` covers 9.0.7) -- so pnpm.overrides
is genuinely required here, not just convenient.

minimatch is overridden with a version-range key
(minimatch@>=9.0.0 <9.0.7) rather than a blanket override, since 6
different major versions of minimatch coexist in the tree for
different consumers (3.x/5.x/10.x elsewhere); a blanket override would
have forced all of them to 9.0.7 and likely broken callers expecting a
different major's API.

* fix(web): unify @types/node resolution to stop duplicate vite types

The previous vite 7.3.2 -> 7.3.5 bump caused pnpm to resolve two
different @types/node versions (25.7.0 and 26.1.0) as vite's optional
peer across different workspace packages. vue-tsc then saw two
structurally-different copies of vite's types (e.g. Plugin, HotUpdateOptions)
and failed with TS2769 in design-system, web-client, web-pkg and
web-test-helpers' vite.config.ts files.

Force a single resolution via pnpm.overrides, pinned to 24.13.2 to
match the Node 24 runtime (engines/volta) rather than an arbitrary
newer major.

* fix(tests): fix ocm/app-provider e2e suites' oCIS orchestration

Both suites were newly wired up by the previous merge-web-repo commit
and hadn't run against real CI yet, so their setup had two latent bugs:

e2e-ocm: the federated instance's env only offset *_DEBUG_ADDR ports,
leaving the actual service ports (e.g. gateway's default
127.0.0.1:9142) unset. The federated "ocis server" process then
crashed trying to bind the same ports the primary instance already
held. run-github.py's Behat apiOcm suite already solved this with a
canonical tests/config/local/.env-federation port map (proven working,
since apiOcm passes) -- reuse it instead of the ad-hoc offset. Also
adds OCIS_ADD_RUN_SERVICES=ocm/OCIS_ENABLE_OCM, missing from the
primary instance too.

e2e-app-provider: tests/config/ci/app-registry.yaml maps its one
mimetype to "FakeOffice" (the stub used by apiCollaboration) and has
no docx entry at all, so the real Collabora/OnlyOffice containers this
suite drives never appeared in the web UI's "New file" menu. Add a
dedicated app-registry mapping both odt->Collabora and docx->OnlyOffice
with allow_creation, and use it only when COLLABORATION_NEEDED is set.

Signed-off-by: Lukas Hirt <info@hirt.cz>

* fix(tests): trust federated oCIS cert, register office templates by target_ext

e2e-ocm: the primary and federated instances each generate their own
self-signed proxy cert. Only the primary's was ever added to the
system CA trust store, so Chromium refused the federated instance's
TLS handshake ("tls: unknown certificate") once federation began.
Trust the federated cert too, and thread OCIS_BASE_DATA_PATH through
its `ocis init` call (previously only set for the running server),
since that's where the cert actually gets written.

e2e-app-provider: reproduced the suite locally (real Collabora/
OnlyOffice containers + `ocis collaboration server`) and diffed
`/app/list` before/after. allow_creation and default_app alone don't
make the web UI's "New file" menu show an entry -- it additionally
requires app_providers[].target_ext, which reva's app-provider only
stamps onto a hardcoded set of "-template" mimetypes
(vendor/github.com/owncloud/reva/v2/.../appprovider/templates.go), not
the plain document mimetypes the previous config used. Existing odt/
docx files still open fine without a static entry, since Collabora/
OnlyOffice register their full supported mimetype list dynamically via
WOPI discovery -- it's specifically file *creation* that needs this.

Signed-off-by: Lukas Hirt <info@hirt.cz>

* fix(changelog): shorten title over the 80-char lint limit

changelog/unreleased/bugfix-personal-space-fail-closed.md landed on
master (#12442) with a 97-char title, which changelog-lint rejects.
GitHub tests PRs against a merge with the current master tip, so this
started failing build-and-test on every open PR once master picked up
that commit -- unrelated to this branch's own changes. Fixing it here
since master needed to be merged in anyway.

* fix(tests): load web apps the ocm/app-provider e2e suites depend on

Both suites drive the web UI, and web only loads the web apps listed in
its UI config's "apps" array. run-e2e.py reuses
tests/config/ci/ocis-config.json, which predates the playwright suites
and lists neither app they need, so both failed deterministically while
the API-only Behat suites (apiOcm, apiCollaboration) kept passing:

e2e-ocm: the "open-cloud-mesh" app menu item can never render because
"ocm" was missing, so web-app-ocm was never loaded. Add it for the
federated suite. Behind that sat a second bug: the invite flow embeds
token@<BASE_URL_OCIS host> (127.0.0.1:9200) into invite codes, but the
federated instance authorizes providers against
tests/config/local/providers.json, which only lists localhost:9200.
Address the primary as https://localhost:9200 when federated, mirroring
run-github.py's passing apiOcm setup (the self-signed cert covers both
hosts; other suites keep 127.0.0.1).

e2e-app-provider: web-runtime only builds the per-provider Collabora/
OnlyOffice editor apps -- including their "New file" menu entries --
when web-app-external is loaded (web/packages/web-runtime/src/index.ts
gates on applicationStore.has('web-app-external')), and "external" was
missing. This also falsifies the previous target_ext theory: the
template-mimetype registry was active in the failing run and the menu
still never appeared, because the New-file menu needs only
allow_creation plus a registered provider
(web-app-external/src/index.ts). Revert the app registry to the plain
odt->Collabora / docx->OnlyOffice mimetypes web's own e2e CI proved out
(web/dev/docker/ocis/app-registry.yaml). Create-from-template still
works without static entries: reva stamps target_ext onto the -template
mimetypes the providers register via WOPI discovery.

Signed-off-by: Lukas Hirt <info@hirt.cz>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* ci: upload playwright traces and a11y report from e2e suites

Port the two upload-artifact steps the standalone web repo's e2e
workflow had: playwright error contexts/report output on failure, and
the a11y report on any non-cancelled run. Paths are prefixed with web/
since the web repo now lives in that subdirectory, artifact names use
the suite name instead of the job index, and the action pin matches the
one already used in this workflow.

Signed-off-by: Lukas Hirt <info@hirt.cz>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(tests): allow office editor iframes in the e2e proxy CSP

The app-provider suite got past file creation but every office test
then timed out waiting for the editor to render: ocis's default proxy
CSP only allows frame-src 'self' (exact scheme+host+port), so the
browser refused to embed the Collabora/OnlyOffice iframes served on
other ports. The COLLABORA_DOMAIN/ONLYOFFICE_DOMAIN env vars do nothing
on their own -- they are only substituted into a custom CSP file, which
is why the pre-merge web CI always set PROXY_CSP_CONFIG_FILE_LOCATION
(tests/drone/csp.yaml there). The localStorage SecurityError seen in
the logs was a downstream symptom: the CSP-blocked frame ends up with
an opaque origin where storage access throws.

Add the two editor domains to tests/config/ci/csp.yaml's frame-src and
img-src (mirroring web's proven csp.yaml) and point the collaboration
suite at it. The keycloak suite shares this file; for it the new
entries fall back to nonexistent default hosts and are inert.

Signed-off-by: Lukas Hirt <info@hirt.cz>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(licenses): attribute REUSE.toml copyright to ownCloud contributors

The web/ tree carries community contributions dating back to 2016; the
CLA grants a relicensing right, not a copyright transfer, so declaring
sole 2020-2026 ownCloud GmbH authorship was inaccurate.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* fix(tests): trust the Keycloak cert in e2e TLS setup

The Keycloak cert had no SAN, and NODE_EXTRA_CA_CERTS only ever pointed
at the oCIS cert, so any node-fetch/axios call made directly against
Keycloak (admin token fetch, user provisioning) failed TLS validation
and aborted the keycloak/mfa matrix jobs before a spec could run.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* fix(web): don't wipe assets/ before a successful build

build-assets ran `git clean -xfd assets` before the pnpm build; a failed
typecheck or vite build left assets/core/ empty, so the next Go embed or
docker deployment served no web UI. Clean only after the build succeeds.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* ci: fail clearly when a release tag matches no known package

If the tag-prefix loop found no match, the workflow silently fell
through to a jq lookup against "packages//package.json", failing with a
confusing path error instead of naming the problem.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* ci: drop duplicate dependency-license-check job

web-tests.yml already enforces the license allow-list via
`pnpm licenses:check` (license-checker-rseidelsohn) on every PR.
check-licenses.yml's dependency-license-check ran a second, differently
configured tool (npx license-checker, GPL/AGPL deny-list only), which
could disagree with the first without adding coverage.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Signed-off-by: Lukas Hirt <info@hirt.cz>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Lukas Hirt
2026-07-07 10:37:00 +02:00
committed by GitHub
parent d5964f64a9
commit 6bad03d364
4894 changed files with 215751 additions and 354 deletions

View File

@@ -64,7 +64,7 @@ jobs:
node-version: "24"
- name: Enable pnpm
run: corepack enable && corepack prepare pnpm@10.28.1 --activate
run: corepack enable && corepack prepare pnpm@10.33.3 --activate
- uses: shivammathur/setup-php@f3e473d116dcccaddc5834248c87452386958240 # v2.37.2
with:
@@ -428,6 +428,12 @@ jobs:
- suite: oidc-iframe
args: "--type playwright specs/oidc/iframeTokenRenewal.spec.ts"
oidc_iframe: true
- suite: app-provider
args: "--type playwright --suites app-provider"
collaboration: true
- suite: ocm
args: "--type playwright --suites ocm"
federated: true
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
@@ -437,7 +443,7 @@ jobs:
node-version: "24.15.0"
- name: Enable pnpm
run: |
corepack enable && corepack prepare pnpm@10.28.1 --activate
corepack enable && corepack prepare pnpm@10.33.3 --activate
pnpm config set store-dir ./.pnpm-store
- name: Install libvips runtime
@@ -458,7 +464,7 @@ jobs:
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ~/.cache/ms-playwright
key: playwright-chromium-${{ hashFiles('ci.env') }}
key: playwright-chromium-${{ hashFiles('web/pnpm-lock.yaml') }}
# --- Tika (search suite only) ---
- name: Start Tika
@@ -476,7 +482,8 @@ jobs:
openssl req -x509 -newkey rsa:2048 \
-keyout keycloak-certs/keycloakkey.pem \
-out keycloak-certs/keycloakcrt.pem \
-nodes -days 365 -subj '/CN=keycloak'
-nodes -days 365 -subj '/CN=keycloak' \
-addext 'subjectAltName=DNS:localhost,IP:127.0.0.1'
chmod -R 777 keycloak-certs
- name: Start Postgres
@@ -526,6 +533,44 @@ jobs:
|| (echo "=== keycloak logs ===" && docker logs keycloak --tail 80 && exit 1)
echo "keycloak ready."
# --- Collabora + OnlyOffice (app-provider suite only) ---
- name: Start Collabora
if: matrix.collaboration == true
run: |
docker run -d \
--name collabora \
--network host \
--entrypoint bash \
-e DONT_GEN_SSL_CERT=set \
-e "extra_params=--o:ssl.enable=true --o:ssl.termination=true --o:welcome.enable=false --o:net.frame_ancestors=https://127.0.0.1:9200" \
collabora/code:25.04.7.3.1 \
-c "coolconfig generate-proof-key && bash /start-collabora-online.sh"
timeout 150 bash -c 'until curl -kfsSL https://localhost:9980/hosting/discovery > /dev/null; do sleep 5; done'
echo "collabora ready."
- name: Start OnlyOffice
if: matrix.collaboration == true
run: |
sudo systemctl stop postgresql || true
docker run -d \
--name onlyoffice \
--network host \
-e WOPI_ENABLED=true \
-e USE_UNAUTHORIZED_STORAGE=true \
-v "${{ github.workspace }}/tests/config/ci/only-office.json:/tmp/local.json:ro" \
--entrypoint /bin/sh \
onlyoffice/documentserver:9.2.1 \
-c "set -e
cp /tmp/local.json /etc/onlyoffice/documentserver/local.json
openssl req -x509 -newkey rsa:4096 -keyout onlyoffice.key -out onlyoffice.crt -sha256 -days 365 -batch -nodes
mkdir -p /var/www/onlyoffice/Data/certs
cp onlyoffice.key /var/www/onlyoffice/Data/certs/
cp onlyoffice.crt /var/www/onlyoffice/Data/certs/
chmod 400 /var/www/onlyoffice/Data/certs/onlyoffice.key
/app/ds/run-document-server.sh"
timeout 150 bash -c 'until curl -kfsSL https://localhost:443/hosting/discovery > /dev/null; do sleep 5; done'
echo "onlyoffice ready."
- name: Run e2e-${{ matrix.suite }}
run: E2E_ARGS="${{ matrix.args }}" python3 tests/acceptance/run-e2e.py
env:
@@ -534,6 +579,24 @@ jobs:
MFA_NEEDED: ${{ matrix.mfa == true && 'true' || 'false' }}
OIDC_NEEDED: ${{ matrix.oidc == true && 'true' || 'false' }}
OIDC_IFRAME_NEEDED: ${{ matrix.oidc_iframe == true && 'true' || 'false' }}
COLLABORATION_NEEDED: ${{ matrix.collaboration == true && 'true' || 'false' }}
FEDERATED_NEEDED: ${{ matrix.federated == true && 'true' || 'false' }}
- name: Upload tracing result
if: failure()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: playwright-traces-${{ matrix.suite }}-${{ github.run_attempt }}
path: web/reports/e2e
retention-days: 7
- name: Upload a11y result
if: ${{ !cancelled() }}
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: playwright-a11y-result-${{ matrix.suite }}-${{ github.run_attempt }}
path: web/reports/e2e/a11y-report.json
retention-days: 7
litmus:
name: litmus

18
.github/workflows/check-licenses.yml vendored Normal file
View File

@@ -0,0 +1,18 @@
name: Check licenses
on:
pull_request:
push:
branches: [master, stable-*]
jobs:
license-check:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Install REUSE tool
run: pip install reuse
- name: Run REUSE lint
run: reuse lint

12
.github/workflows/commit-message.yml vendored Normal file
View File

@@ -0,0 +1,12 @@
name: Validate commit message
on:
pull_request:
branches: [master, stable-*]
permissions:
contents: read
jobs:
validate:
uses: owncloud/reusable-workflows/.github/workflows/semantic-git-message.yml@main

View File

@@ -0,0 +1,84 @@
name: Release NPM packages
on:
push:
tags:
- "babel-preset-v*"
- "design-system-v*"
- "eslint-config-v*"
- "extension-sdk-v*"
- "prettier-config-v*"
- "tsconfig-v*"
- "web-client-v*"
- "web-pkg-v*"
- "web-test-helpers-v*"
jobs:
release-npm:
name: Publish NPM package
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
defaults:
run:
working-directory: web
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 24.15.0
registry-url: "https://registry.npmjs.org"
- name: Setup pnpm
run: corepack enable && corepack prepare pnpm@10.33.3 --activate
- name: Install dependencies
run: pnpm install
- name: Determine package
id: package
run: |
TAG="${{ github.ref_name }}"
PACKAGES="babel-preset design-system eslint-config extension-sdk prettier-config tsconfig web-client web-pkg web-test-helpers"
for pkg in $PACKAGES; do
if [[ "$TAG" == "${pkg}-v"* ]]; then
echo "name=$pkg" >> "$GITHUB_OUTPUT"
echo "version=${TAG#${pkg}-v}" >> "$GITHUB_OUTPUT"
exit 0
fi
done
echo "tag '$TAG' does not match any known package prefix: $PACKAGES"
exit 1
- name: Verify package version
run: |
PKG="${{ steps.package.outputs.name }}"
VERSION="${{ steps.package.outputs.version }}"
ACTUAL_VERSION=$(jq -r '.version' < "packages/${PKG}/package.json")
echo "Build ${PKG} ${VERSION} package.json: ${ACTUAL_VERSION}"
if [ "${ACTUAL_VERSION}" != "${VERSION}" ]; then
echo "git tag does not match version in web/packages/${PKG}/package.json"
exit 1
fi
- name: Build tokens
run: pnpm build:tokens
- name: Build package
run: |
PKG="${{ steps.package.outputs.name }}"
case "$PKG" in
design-system|web-client|web-pkg|web-test-helpers)
pnpm --filter "@ownclouders/${PKG}" vite build
;;
esac
- name: Publish to NPM
run: |
pnpm publish \
--no-git-checks --filter "@ownclouders/${{ steps.package.outputs.name }}" \
--access public --tag latest

View File

@@ -20,3 +20,22 @@ jobs:
TX_TOKEN: ${{ secrets.TX_TOKEN }}
TRANSLATION_APP_ID: ${{ secrets.TRANSLATION_APP_ID }}
TRANSLATION_APP_PRIVATE_KEY: ${{ secrets.TRANSLATION_APP_PRIVATE_KEY }}
# web/ is a pnpm workspace nested inside the repo, not covered by the
# root-level L10N_MODULES/sub_path: . sync above (that job has no
# package.json at the repo root, so a pnpm install there would be a
# no-op/fail). Run it as its own invocation scoped to sub_path: web,
# sequenced after `sync` since the reusable workflow always pushes to
# the same hardcoded chore/translations-update branch.
sync-web:
needs: sync
uses: owncloud/reusable-workflows/.github/workflows/translation-sync.yml@main
with:
mode: make
package_manager: pnpm
reviewers: kobergj,mmattel
sub_path: web
secrets:
TX_TOKEN: ${{ secrets.TX_TOKEN }}
TRANSLATION_APP_ID: ${{ secrets.TRANSLATION_APP_ID }}
TRANSLATION_APP_PRIVATE_KEY: ${{ secrets.TRANSLATION_APP_PRIVATE_KEY }}

105
.github/workflows/web-tests.yml vendored Normal file
View File

@@ -0,0 +1,105 @@
name: Web Tests
on:
pull_request:
push:
branches: [master, stable-*]
jobs:
detect-web-changes:
name: detect-web-changes
runs-on: ubuntu-latest
outputs:
web-changed: ${{ steps.check.outputs.web-changed }}
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- name: Check if web/ changed
id: check
run: |
if [[ "${{ github.event_name }}" == "push" ]]; then
echo "web-changed=true" >> "$GITHUB_OUTPUT"
exit 0
fi
PR_TITLE="${{ github.event.pull_request.title }}"
if echo "$PR_TITLE" | grep -qi "\[full-ci\]"; then
echo "web-changed=true" >> "$GITHUB_OUTPUT"
exit 0
fi
CHANGED_FILES=$(git diff --name-only "${{ github.event.pull_request.base.sha }}" "${{ github.sha }}" 2>/dev/null || git diff --name-only HEAD~1)
WEB_CHANGED=false
while IFS= read -r file; do
case "$file" in
web/*) WEB_CHANGED=true; break ;;
.github/workflows/web-tests.yml) WEB_CHANGED=true; break ;;
esac
done <<< "$CHANGED_FILES"
echo "web-changed=$WEB_CHANGED" >> "$GITHUB_OUTPUT"
echo "web/ changed: $WEB_CHANGED"
web-build-test:
name: web-build-test
needs: [detect-web-changes]
if: needs.detect-web-changes.outputs.web-changed == 'true'
runs-on: ubuntu-latest
defaults:
run:
working-directory: web
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup pnpm
uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
with:
version: 10.33.3
- name: Setup Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 24.15.0
cache: pnpm
cache-dependency-path: web/pnpm-lock.yaml
- name: Install dependencies
run: pnpm install
- name: Check licenses
run: pnpm licenses:check
- name: Save licenses
run: pnpm licenses:csv && pnpm licenses:save
- name: Check types
run: pnpm check:types
- name: Check format
run: pnpm check:format
- name: Lint
run: pnpm lint
- name: Run unit tests
run: pnpm test:unit --coverage
- name: Build
run: pnpm build
web-tests-passed:
name: web-tests-passed
needs: [detect-web-changes, web-build-test]
runs-on: ubuntu-latest
if: always()
steps:
- name: Check web-build-test passed or was skipped
run: |
if [[ "${{ needs.web-build-test.result }}" == "failure" || "${{ needs.web-build-test.result }}" == "cancelled" ]]; then
exit 1
fi

8
CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1,8 @@
# Code of Conduct
This project follows the ownCloud Code of Conduct.
Please read the full Code of Conduct at:
**<https://owncloud.com/contribute/code-of-conduct/>**
By participating in this project, you agree to abide by its terms.

View File

@@ -1,263 +1,9 @@
First of all, thank you for taking the time to read this and your interest in contributing to ownCloud Infinite Scale!
# Contributing
The following is a set of guidelines for contributing to most of the projects hosted in the [ownCloud Organization](https://github.com/owncloud) on [GitHub](https://www.github.com). These are mostly guidelines, not rules. Use your best judgment, and feel free to propose changes to this document in a pull request.
Thank you for your interest in contributing to this project!
For simplicity reasons, this document mostly refers to the ownCloud [Infinite Scale project](https://www.github.com/owncloud/ocis), but it should be easily transferable to other (sub)projects.
Please read the full contributing guidelines at:
**<https://owncloud.com/contribute/>**
#### Table Of Contents
[I don't want to read this whole thing, I just have a question](#i-dont-want-to-read-this-whole-thing-i-just-have-a-question)
[What should I know before I get started](#what-should-i-know-before-i-get-started)
* [ownCloud is hosted on GitHub](#owncloud-is-hosted-on-github)
* [ownCloud Company, Engineering Partners and Community](#owncloud-company,-engineering-partners-and-community)
* [Licensing and CLA](#licensing-and-cla)
[How Can I Contribute](#how-can-i-contribute)
* [Help spreading the word](#help-spreading-the-word)
* [Reporting Bugs](#reporting-bugs)
* [Suggesting Enhancements](#suggesting-enhancements)
* [Your First Code Contribution](#your-first-code-contribution)
* [Pull Requests](#pull-requests)
* [Documentation Contributions](#documentation-contributions)
* [Internationalization](#internationalization)
* [Deployments: Docker, Ansible and friends](#deployments-docker-ansible-and-friends)
[Styleguides](#styleguides)
* [Git Commit Messages](#git-commit-messages)
* [Golang Styleguide](#golang-styleguide)
* [Web Styleguide](#web-styleguide)
* [Documentation Styleguide](#documentation-styleguide)
[Additional Notes](#additional-notes)
* [Issue and Pull Request Labels](#issue-and-pull-request-labels)
## I don't want to read this whole thing I just have a question
> **Note:** Please don't file an issue to ask a question. You'll get faster results by using the resources below.
For general questions, please refer to [ownCloud's FAQs](https://owncloud.com/faq/) or ask on the [ownCloud Central Server](https://central.owncloud.org/).
We also have a [Matrix channel](https://matrix.to/#/#ocis:matrix.org) to answer your questions specifically about ownCloud Infinite Scale.
## What should I know before I get started
### ownCloud is hosted on GitHub
To effectively contribute to ownCloud Infinite Scale, you need a GitHub account. You can get that for free at [GitHub](https://github.com/join). You can find howtos on the internet, for example [here](https://www.wikihow.com/Create-an-Account-on-GitHub).
For other ways of contributing, for example with translations, other systems require you to have an account as well, for example [Transifex](https://www.transifex.com).
The ownCloud project follows the strict GitHub workflow of development as briefly [described here](https://guides.github.com/introduction/flow/).
### ownCloud Company, Engineering Partners and Community
ownCloud Infinite Scale is largely created by developers who are employed by the [ownCloud company](https://www.owncloud.com), which is located in Germany. It is providing support for ownCloud for customers worldwide. In addition, there are engineering partners who also work full time on ownCloud related code, for example in [CERN REVA](https://github.com/cs3org/reva/).
Because of that fact, the pace that the development is moving forward is sometimes high for people who are not willing and/or able to spend a comparable amount of time to contribute. Even though this can be a challenge, it should not scare anybody away. Here is our clear commitment that we feel honored by everybody who is interested in our work and improves it, no matter how big the contribution might be.
We as the full time devs from either organization are doing our best to listen, review and consider all changes that are brought forward following this guideline and make sense for the project.
### Licensing and CLA
We are very happy that there is *no CLA* required for most of the code of ownCloud Infinite Scale.
Currently, only for the following components you need to sign a [Contributors License Agreement](https://en.wikipedia.org/wiki/Contributor_License_Agreement):
* [ownCloud Web](https://github.com/owncloud/web/): [Link to CLA](https://owncloud.com/contribute/join-the-development/contributor-agreement/)
Please make sure to read and understand the details of the CLA before starting to invest time on a component that requires it. If you have any questions or concerns please feel free to raise them with us.
## How Can I Contribute
There are many ways to contribute to open source projects, and all are equally valuable and appreciated.
### Help spreading the word
This way to contribute to the project can not be overestimated: People who talk about their experience with ownCloud Infinite Scale and help others with that are the key to success of the project.
There are too many ways of doing that to line them up here, but examples are answering questions in [ownCloud Central](https://central.owncloud.org/) or on [ownCloud Talk](https://talk.owncloud.com/channel/ocis), writing blog posts etc. pp.
There is no formal guideline to this, just do it :-)
### Reporting Bugs
This section guides you through submitting a bug report for ownCloud Infinite Scale. Following these guidelines helps maintainers and the community understand your report :pencil:, reproduce the behavior :computer: :computer:, and find related reports :mag_right:.
Before creating bug reports, please check [this list](#before-submitting-a-bug-report) as you might find out that you don't need to create one. When you are creating a bug report, please [include as many details as possible](#how-do-i-submit-a-good-bug-report). Fill out [the required template](https://github.com/owncloud/ocis/issues/new?Type%3ABug&template=bug_report.md), the information it asks for helps us resolve issues faster.
> **Note:** If you find a **Closed** issue that seems like it is the same thing that you're experiencing, open a new issue and include a link to the original issue in the body of your new one. If you have permission to reopen the issue, feel free to do so.
#### Before Submitting A Bug Report
* **Make sure you are running a recent version** Usually, developers' interest in old versions of software drops very fast once a new shiny version has been released. So the general recommendation is: Use the latest released version or even the current master to reproduce problems that you might encounter. That helps a lot to attract developers attention.
* **Determine which [repository](https://github.com/owncloud) the problem should be reported in**.
* **Perform a [cursory search](https://github.com/search?q=+is%3Aissue+user%3Aowncloud)** with possibly a more granular filter on the repository, to see if the problem has already been reported. If it has **and the issue is still open**, add a comment to the existing issue instead of opening a new one **if you have new information**. Please abstain from adding "plus ones", except using the GitHub emojis. That might indicate how many users are affected.
#### How Do I Submit A (Good) Bug Report
Bugs are tracked as [GitHub issues](https://guides.github.com/features/issues/). After you've determined [which repository](https://github.com/owncloud) your bug is related to, create an issue on that repository and provide the following information by filling in [the template](https://github.com/owncloud/ocis/issues/new?Type%3ABug&template=bug_report.md).
Explain the problem and include additional details to help maintainers reproduce the problem:
* **Use a clear and descriptive title** for the issue to identify the problem.
* **Describe the exact steps which reproduce the problem** in as many details as possible. Start with describing, from a user perspective, what you tried to achieve, i.e. "I want to share some pictures with Grandma". When listing steps, **don't just say what you did, but explain how you did it**. For example, if you uploaded a file to ownCloud, say which client you used, which way of uploading you chose, if the name was special somehow and how big it was.
* **Provide specific examples to demonstrate the steps**. Include links to files or GitHub projects, or copy/pasteable snippets, which you use in those examples. If you're providing snippets in the issue, use [Markdown code blocks](https://help.github.com/articles/markdown-basics/#multiple-lines).
* **Describe the behavior you observed after following the steps** and point out what exactly is the problem with that behavior.
* **Explain which behavior you expected to see instead and why.**
* **Include screenshots and animated GIFs** which show you following the described steps and clearly demonstrate the problem. You can use [this tool](https://www.cockos.com/licecap/) to record GIFs on macOS and Windows, and [this tool](https://github.com/colinkeenan/silentcast) or [this tool](https://github.com/GNOME/byzanz) on Linux.
* **If you report a web browser related problem**, consider to using the browser's Web developer tools (such as the debugger, console or network monitor) to check what happened. Make sure to add screenshots of the utilities if you are short of time to interpret it.
* **If the problem wasn't triggered by a specific action**, describe what you were doing before the problem happened and share more information using the guidelines below.
Provide more context by answering these questions:
* **Did the problem start happening recently** (e.g. after updating to a new version) or was this always a problem?
* If the problem started happening recently, **can you reproduce the problem in an older version?** What's the most recent version in which the problem doesn't happen? You can find more information about how to set up [test environments](https://owncloud.dev/ocis/development/testing/) in the [developer documentation](https://owncloud.dev/#developer-documentation).
* **Can you reliably reproduce the issue?** If not, provide details about how often the problem happens and under which conditions it normally happens.
Include details about your configuration and environment as asked for in the template.
### Suggesting Enhancements
This section guides you through submitting an enhancement suggestion for ownCloud Infinite Scale, including completely new features and minor improvements to existing functionality. Following these guidelines helps maintainers and the community understand your suggestion :pencil: and find related suggestions :mag_right:.
Before creating enhancement suggestions, please check [this list](#before-submitting-an-enhancement-suggestion) as you might find out that you don't need to create one. When you are creating an enhancement suggestion, please [include as many details as possible](#how-do-i-submit-a-good-enhancement-suggestion). Fill in [the template](https://github.com/owncloud/ocis/.github/blob/master/.github/ISSUE_TEMPLATE/feature_request.md), including the steps that you imagine you would take if the feature you're requesting existed.
#### Before Submitting An Enhancement Suggestion
* **Check if there's already an extension or other component which provides that enhancement, even in a different way.**
* **Perform a [cursory search](https://github.com/search?q=+is%3Aissue+user%3Aowncloud)** to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one. Feel free to use the GitHub emojis to indicate that you are in favour of an enhancement request.
#### How Do I Submit A (Good) Enhancement Suggestion
Enhancement suggestions are tracked as [GitHub issues](https://guides.github.com/features/issues/). After you've determined [which repository](https://github.com/owncloud) your enhancement suggestion is related to, create an issue on that repository and provide the following information:
* **Use a clear and descriptive title** for the issue to identify the suggestion.
* **Provide a step-by-step description of the suggested enhancement** in as many details as possible.
* **Provide specific examples to demonstrate the steps**. Include copy/pasteable snippets which you use in those examples, as [Markdown code blocks](https://help.github.com/articles/markdown-basics/#multiple-lines).
* **Explain why this enhancement would be useful** to most ownCloud users.
* **List some other projects or products where this enhancement exists.**
### Your First Code Contribution
Unsure where to begin contributing to ownCloud? You can start by looking through these `Needs-help` issues:
* The [Good first issue](https://github.com/owncloud/ocis/labels/Topic%3Agood-first-issue) label marks good items to start with.
* [Tests needed](https://github.com/owncloud/ocis/labels/Interaction%3ANeeds-tests) - issues which would benefit from a test.
* [Help wanted issues](https://github.com/owncloud/ocis/labels/Interaction%3ANeeds-help) - issues which should be a bit more involved.
It is fine to pick one of the list following personal preference. While not perfect, number of comments is a reasonable proxy for impact a given change will have.
To find out how to set up ownCloud Infinite Scale for local development please refer to the [Developer Documentation](https://owncloud.dev/ocis/development/getting-started/). It contains a lot of information that will come in handy when starting to work on the project.
### Pull Requests
All contributions to ownClouds projects use so-called pull requests following the [GitHub PR workflow](https://guides.github.com/introduction/flow/).
Please follow these steps to have your contribution considered by the maintainers:
* Follow all instructions in [the template](https://github.com/owncloud/ocis/blob/master/.github/pull_request_template.md)
* Follow the [styleguides](#styleguides) where applicable
* After you submit your pull request, verify that all [status checks](https://help.github.com/articles/about-status-checks/) are passing <details><summary>What if the status checks are failing?</summary>If a status check is failing, and you believe that the failure is unrelated to your change, please leave a comment on the pull request explaining why you believe the failure is unrelated. A maintainer will re-run the status check for you. If we conclude that the failure was a false positive, then we will open an issue to track that problem with our status check suite.</details>
While the prerequisites above must be satisfied prior to having your pull request reviewed, the reviewer(s) may ask you to complete additional design work, tests, or other changes before your pull request can be ultimately accepted.
### Documentation Contributions
ownCloud is very proud of the documentation it has, which is the work of a great team of people. Of course, also the documentation is open to contributions.
See the [Getting Started Guide](https://owncloud.dev/ocis/development/getting-started/) on how to get started. Other useful information is summarized in the [Documentation Readme](https://github.com/owncloud/docs).
### Internationalization
Our projects are getting translated into many languages to allow people from all over the world to use ownCloud in their native language. For translations, ownCloud uses [Transifex](https://www.transifex.com) as a community based collaboration platform for internationalization.
For contributions please refer to the [Transifex Resources](https://www.transifex.com/resources/) to learn how to improve ownClouds translations there.
### Deployments: Docker, Ansible and friends
Depending on the ownCloud component, there is complex deployment tooling to install in various environments. There is for example [ownCloud Ansible](https://github.com/owncloud-ansible) with Ansible resources. Contributions to that are very appreciated and follow the same guidelines as every other code contribution.
## Styleguides
To keep up with a consistent code and tooling landscape, some ownCloud modules maintain styleguides for contributions. It is mandatory to follow them in contributions.
### Git Commit Messages
* Use the present tense ("Add feature" not "Added feature")
* Use the imperative mood ("Move cursor to..." not "Moves cursor to...")
* Limit the first line to 72 characters or less
* Reference issues and pull requests liberally after the first line
* When only changing documentation, include `[docs-only]` in the commit title
### Golang Styleguide
Use the built-in golang code formatter before submitting the patch. Also, consulting documentation like [Effective Go](https://golang.org/doc/effective_go) or [Practical Go](http://bit.ly/gcsg-2019) helps to improve the code quality.
### Web Styleguide
Refer to related documents in the [ownCloud Web Repository](https://github.com/owncloud/web).
#### Documentation Styleguide
See the [ownCloud Documentation Styleguide](https://github.com/owncloud/docs/blob/master/docs/style-guide.md).
## Additional Notes
### Issue and Pull Request Labels
This section lists the labels we use to help us track and manage issues and pull requests. Most labels are used across all ownCloud repositories, but some are specific.
[GitHub search](https://help.github.com/articles/searching-issues/) makes it easy to use labels for finding groups of issues or pull requests you're interested in. To help you find issues and pull requests, each label can be used in search links for finding open items with that label in the ownCloud repositories.
The labels are loosely grouped by their purpose, but it's not required that every issue has a label from every group or that an issue can't have more than one label from the same group.
The list here contains all the more general categories of issues which are followed by a colon and a specific value. For example severity 1 looks like `Severity:sev1-critical`.
#### Platform
Describes the platform the issue is happening on, i.e. iOS or Windows.
#### Estimation
T-Shirt sizes for effort estimation to fix that bug or implement an enhancement. Ranges from XS to XXXL.
#### Priority
P1 to P4 (lowest) to indicate a priority. Mostly a tool for internal project management and support.
#### QA
Flags to indicate the internal QA status in terms of process and priority. Please leave alone unless you're QA ;-)
#### Severity
Severity for the product, mostly impact on user.
#### Type
The issue type, helps to structure the issues in the agile categories (Epic, Story...) but also organizational ones.
#### Topic
A general category of the topic of a ticket.
#### Category
Categorizes the issue to also indicate the type of the issue.
#### Status
The status in the ticket life cycle. Keep an eye on that one, especially for the `Waiting-for-Feedback` tag which might indicate that the reporter is asked for feedback.
#### Interaction
Another label that indicates the type of the issue.
#### Browser
Important for browser dependent web issues. It specifies the browser that shows the error.
#### Early-Adopter
Tags issues that were reported by one of the oCIS early adopters, i.e. customers and users who start using ownCloud Infinite Scale before its general availability.
For development setup, coding standards, and pull request process,
see the README in this repository.

188
LICENSES/Apache-2.0.txt Normal file
View File

@@ -0,0 +1,188 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.

11
LICENSES/BSD-3-Clause.txt Normal file
View File

@@ -0,0 +1,11 @@
Copyright (c) <year> <owner>.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

18
LICENSES/MIT.txt Normal file
View File

@@ -0,0 +1,18 @@
MIT License
Copyright (c) <year> <copyright holders>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial
portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.

373
LICENSES/MPL-2.0.txt Normal file
View File

@@ -0,0 +1,373 @@
Mozilla Public License Version 2.0
==================================
1. Definitions
--------------
1.1. "Contributor"
means each individual or legal entity that creates, contributes to
the creation of, or owns Covered Software.
1.2. "Contributor Version"
means the combination of the Contributions of others (if any) used
by a Contributor and that particular Contributor's Contribution.
1.3. "Contribution"
means Covered Software of a particular Contributor.
1.4. "Covered Software"
means Source Code Form to which the initial Contributor has attached
the notice in Exhibit A, the Executable Form of such Source Code
Form, and Modifications of such Source Code Form, in each case
including portions thereof.
1.5. "Incompatible With Secondary Licenses"
means
(a) that the initial Contributor has attached the notice described
in Exhibit B to the Covered Software; or
(b) that the Covered Software was made available under the terms of
version 1.1 or earlier of the License, but not also under the
terms of a Secondary License.
1.6. "Executable Form"
means any form of the work other than Source Code Form.
1.7. "Larger Work"
means a work that combines Covered Software with other material, in
a separate file or files, that is not Covered Software.
1.8. "License"
means this document.
1.9. "Licensable"
means having the right to grant, to the maximum extent possible,
whether at the time of the initial grant or subsequently, any and
all of the rights conveyed by this License.
1.10. "Modifications"
means any of the following:
(a) any file in Source Code Form that results from an addition to,
deletion from, or modification of the contents of Covered
Software; or
(b) any new file in Source Code Form that contains any Covered
Software.
1.11. "Patent Claims" of a Contributor
means any patent claim(s), including without limitation, method,
process, and apparatus claims, in any patent Licensable by such
Contributor that would be infringed, but for the grant of the
License, by the making, using, selling, offering for sale, having
made, import, or transfer of either its Contributions or its
Contributor Version.
1.12. "Secondary License"
means either the GNU General Public License, Version 2.0, the GNU
Lesser General Public License, Version 2.1, the GNU Affero General
Public License, Version 3.0, or any later versions of those
licenses.
1.13. "Source Code Form"
means the form of the work preferred for making modifications.
1.14. "You" (or "Your")
means an individual or a legal entity exercising rights under this
License. For legal entities, "You" includes any entity that
controls, is controlled by, or is under common control with You. For
purposes of this definition, "control" means (a) the power, direct
or indirect, to cause the direction or management of such entity,
whether by contract or otherwise, or (b) ownership of more than
fifty percent (50%) of the outstanding shares or beneficial
ownership of such entity.
2. License Grants and Conditions
--------------------------------
2.1. Grants
Each Contributor hereby grants You a world-wide, royalty-free,
non-exclusive license:
(a) under intellectual property rights (other than patent or trademark)
Licensable by such Contributor to use, reproduce, make available,
modify, display, perform, distribute, and otherwise exploit its
Contributions, either on an unmodified basis, with Modifications, or
as part of a Larger Work; and
(b) under Patent Claims of such Contributor to make, use, sell, offer
for sale, have made, import, and otherwise transfer either its
Contributions or its Contributor Version.
2.2. Effective Date
The licenses granted in Section 2.1 with respect to any Contribution
become effective for each Contribution on the date the Contributor first
distributes such Contribution.
2.3. Limitations on Grant Scope
The licenses granted in this Section 2 are the only rights granted under
this License. No additional rights or licenses will be implied from the
distribution or licensing of Covered Software under this License.
Notwithstanding Section 2.1(b) above, no patent license is granted by a
Contributor:
(a) for any code that a Contributor has removed from Covered Software;
or
(b) for infringements caused by: (i) Your and any other third party's
modifications of Covered Software, or (ii) the combination of its
Contributions with other software (except as part of its Contributor
Version); or
(c) under Patent Claims infringed by Covered Software in the absence of
its Contributions.
This License does not grant any rights in the trademarks, service marks,
or logos of any Contributor (except as may be necessary to comply with
the notice requirements in Section 3.4).
2.4. Subsequent Licenses
No Contributor makes additional grants as a result of Your choice to
distribute the Covered Software under a subsequent version of this
License (see Section 10.2) or under the terms of a Secondary License (if
permitted under the terms of Section 3.3).
2.5. Representation
Each Contributor represents that the Contributor believes its
Contributions are its original creation(s) or it has sufficient rights
to grant the rights to its Contributions conveyed by this License.
2.6. Fair Use
This License is not intended to limit any rights You have under
applicable copyright doctrines of fair use, fair dealing, or other
equivalents.
2.7. Conditions
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
in Section 2.1.
3. Responsibilities
-------------------
3.1. Distribution of Source Form
All distribution of Covered Software in Source Code Form, including any
Modifications that You create or to which You contribute, must be under
the terms of this License. You must inform recipients that the Source
Code Form of the Covered Software is governed by the terms of this
License, and how they can obtain a copy of this License. You may not
attempt to alter or restrict the recipients' rights in the Source Code
Form.
3.2. Distribution of Executable Form
If You distribute Covered Software in Executable Form then:
(a) such Covered Software must also be made available in Source Code
Form, as described in Section 3.1, and You must inform recipients of
the Executable Form how they can obtain a copy of such Source Code
Form by reasonable means in a timely manner, at a charge no more
than the cost of distribution to the recipient; and
(b) You may distribute such Executable Form under the terms of this
License, or sublicense it under different terms, provided that the
license for the Executable Form does not attempt to limit or alter
the recipients' rights in the Source Code Form under this License.
3.3. Distribution of a Larger Work
You may create and distribute a Larger Work under terms of Your choice,
provided that You also comply with the requirements of this License for
the Covered Software. If the Larger Work is a combination of Covered
Software with a work governed by one or more Secondary Licenses, and the
Covered Software is not Incompatible With Secondary Licenses, this
License permits You to additionally distribute such Covered Software
under the terms of such Secondary License(s), so that the recipient of
the Larger Work may, at their option, further distribute the Covered
Software under the terms of either this License or such Secondary
License(s).
3.4. Notices
You may not remove or alter the substance of any license notices
(including copyright notices, patent notices, disclaimers of warranty,
or limitations of liability) contained within the Source Code Form of
the Covered Software, except that You may alter any license notices to
the extent required to remedy known factual inaccuracies.
3.5. Application of Additional Terms
You may choose to offer, and to charge a fee for, warranty, support,
indemnity or liability obligations to one or more recipients of Covered
Software. However, You may do so only on Your own behalf, and not on
behalf of any Contributor. You must make it absolutely clear that any
such warranty, support, indemnity, or liability obligation is offered by
You alone, and You hereby agree to indemnify every Contributor for any
liability incurred by such Contributor as a result of warranty, support,
indemnity or liability terms You offer. You may include additional
disclaimers of warranty and limitations of liability specific to any
jurisdiction.
4. Inability to Comply Due to Statute or Regulation
---------------------------------------------------
If it is impossible for You to comply with any of the terms of this
License with respect to some or all of the Covered Software due to
statute, judicial order, or regulation then You must: (a) comply with
the terms of this License to the maximum extent possible; and (b)
describe the limitations and the code they affect. Such description must
be placed in a text file included with all distributions of the Covered
Software under this License. Except to the extent prohibited by statute
or regulation, such description must be sufficiently detailed for a
recipient of ordinary skill to be able to understand it.
5. Termination
--------------
5.1. The rights granted under this License will terminate automatically
if You fail to comply with any of its terms. However, if You become
compliant, then the rights granted under this License from a particular
Contributor are reinstated (a) provisionally, unless and until such
Contributor explicitly and finally terminates Your grants, and (b) on an
ongoing basis, if such Contributor fails to notify You of the
non-compliance by some reasonable means prior to 60 days after You have
come back into compliance. Moreover, Your grants from a particular
Contributor are reinstated on an ongoing basis if such Contributor
notifies You of the non-compliance by some reasonable means, this is the
first time You have received notice of non-compliance with this License
from such Contributor, and You become compliant prior to 30 days after
Your receipt of the notice.
5.2. If You initiate litigation against any entity by asserting a patent
infringement claim (excluding declaratory judgment actions,
counter-claims, and cross-claims) alleging that a Contributor Version
directly or indirectly infringes any patent, then the rights granted to
You by any and all Contributors for the Covered Software under Section
2.1 of this License shall terminate.
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
end user license agreements (excluding distributors and resellers) which
have been validly granted by You or Your distributors under this License
prior to termination shall survive termination.
************************************************************************
* *
* 6. Disclaimer of Warranty *
* ------------------------- *
* *
* Covered Software is provided under this License on an "as is" *
* basis, without warranty of any kind, either expressed, implied, or *
* statutory, including, without limitation, warranties that the *
* Covered Software is free of defects, merchantable, fit for a *
* particular purpose or non-infringing. The entire risk as to the *
* quality and performance of the Covered Software is with You. *
* Should any Covered Software prove defective in any respect, You *
* (not any Contributor) assume the cost of any necessary servicing, *
* repair, or correction. This disclaimer of warranty constitutes an *
* essential part of this License. No use of any Covered Software is *
* authorized under this License except under this disclaimer. *
* *
************************************************************************
************************************************************************
* *
* 7. Limitation of Liability *
* -------------------------- *
* *
* Under no circumstances and under no legal theory, whether tort *
* (including negligence), contract, or otherwise, shall any *
* Contributor, or anyone who distributes Covered Software as *
* permitted above, be liable to You for any direct, indirect, *
* special, incidental, or consequential damages of any character *
* including, without limitation, damages for lost profits, loss of *
* goodwill, work stoppage, computer failure or malfunction, or any *
* and all other commercial damages or losses, even if such party *
* shall have been informed of the possibility of such damages. This *
* limitation of liability shall not apply to liability for death or *
* personal injury resulting from such party's negligence to the *
* extent applicable law prohibits such limitation. Some *
* jurisdictions do not allow the exclusion or limitation of *
* incidental or consequential damages, so this exclusion and *
* limitation may not apply to You. *
* *
************************************************************************
8. Litigation
-------------
Any litigation relating to this License may be brought only in the
courts of a jurisdiction where the defendant maintains its principal
place of business and such litigation shall be governed by laws of that
jurisdiction, without reference to its conflict-of-law provisions.
Nothing in this Section shall prevent a party's ability to bring
cross-claims or counter-claims.
9. Miscellaneous
----------------
This License represents the complete agreement concerning the subject
matter hereof. If any provision of this License is held to be
unenforceable, such provision shall be reformed only to the extent
necessary to make it enforceable. Any law or regulation which provides
that the language of a contract shall be construed against the drafter
shall not be used to construe this License against a Contributor.
10. Versions of the License
---------------------------
10.1. New Versions
Mozilla Foundation is the license steward. Except as provided in Section
10.3, no one other than the license steward has the right to modify or
publish new versions of this License. Each version will be given a
distinguishing version number.
10.2. Effect of New Versions
You may distribute the Covered Software under the terms of the version
of the License under which You originally received the Covered Software,
or under the terms of any subsequent version published by the license
steward.
10.3. Modified Versions
If you create software not governed by this License, and you want to
create a new license for such software, you may create and use a
modified version of this License if you rename the license and remove
any references to the name of the license steward (except to note that
such modified license differs from this License).
10.4. Distributing Source Code Form that is Incompatible With Secondary
Licenses
If You choose to distribute Source Code Form that is Incompatible With
Secondary Licenses under the terms of this version of the License, the
notice described in Exhibit B of this License must be attached.
Exhibit A - Source Code Form License Notice
-------------------------------------------
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at https://mozilla.org/MPL/2.0/.
If it is not possible or desirable to put the notice in a particular
file, then You may include the notice in a location (such as a LICENSE
file in a relevant directory) where a recipient would be likely to look
for such a notice.
You may add additional accurate notices of copyright ownership.
Exhibit B - "Incompatible With Secondary Licenses" Notice
---------------------------------------------------------
This Source Code Form is "Incompatible With Secondary Licenses", as
defined by the Mozilla Public License, v. 2.0.

31
NOTICE Normal file
View File

@@ -0,0 +1,31 @@
ownCloud Infinite Scale (ocis)
Copyright 2020-2026 ownCloud GmbH
This product includes software developed by ownCloud GmbH and the
ownCloud community, licensed under the Apache License, Version 2.0
(see the LICENSE file in this repository's root directory).
--------------------------------------------------------------------
Provenance note: the ownCloud Web frontend (web/)
--------------------------------------------------------------------
The `web/` directory contains the source of the ownCloud Web frontend.
It was formerly maintained as the independent repository
https://github.com/owncloud/web and, through its final release
(tag `v12.5.0`, also tagged `last-agpl-release`, commit
b16a34fdf5569d2fd63b1ff3c575c1a4ee569ad3), was historically licensed
under the GNU Affero General Public License, version 3.0 (AGPL-3.0).
All contributors to that repository accepted the ownCloud Contributor
License Agreement (CLA), which grants ownCloud GmbH the right to
relicense their contributions. Under that grant, ownCloud GmbH has
relicensed the source tree at the commit above from AGPL-3.0 to the
Apache License, Version 2.0 -- the same license that covers the rest
of this repository -- and merged it into this repository.
The pre-relicense, AGPL-3.0-licensed development history remains
publicly available in the archived https://github.com/owncloud/web
repository for historical and attribution purposes. That history is
not the license under which the code in this repository is
distributed; this repository's root LICENSE (Apache-2.0) governs the
entirety of this repository, including web/.

9
REUSE.toml Normal file
View File

@@ -0,0 +1,9 @@
version = 1
SPDX-PackageName = "ocis"
SPDX-PackageSupplier = "ownCloud GmbH <devops@owncloud.com>"
SPDX-PackageDownloadLocation = "https://github.com/owncloud/ocis"
[[annotations]]
path = "**"
SPDX-FileCopyrightText = "2016-2026 ownCloud GmbH - A Kiteworks Company and ownCloud contributors"
SPDX-License-Identifier = "Apache-2.0"

11
SECURITY.md Normal file
View File

@@ -0,0 +1,11 @@
# Security Policy
## Reporting a Vulnerability
**Do NOT open a public GitHub issue for security vulnerabilities.**
Please report security issues responsibly via:
**<https://security.owncloud.com>**
You can also report vulnerabilities through our YesWeHack bug bounty program:
**<https://yeswehack.com/programs/owncloud-bug-bounty-program>**

10
SUPPORT.md Normal file
View File

@@ -0,0 +1,10 @@
# Support
For support with this project, please use the following channels:
- **Enterprise Support**: <https://owncloud.com/contact-us/>
- **Community discussions**: https://github.com/orgs/owncloud/discussions
- **Matrix Chat**: <https://app.element.io/#/room/#owncloud:matrix.org>
- **Documentation**: <https://doc.owncloud.com>
Please do not use GitHub issues for general support questions.

View File

@@ -1,4 +1,4 @@
Bugfix: Fail closed on inconclusive Drives.Create check; preserve personal space
Bugfix: Do not disable personal space on inconclusive permission check
When a user's role is (re-)assigned, both the proxy (on OIDC login) and the graph
appRoleAssignment handler check the `Drives.Create` permission to decide whether to

4
ci.env
View File

@@ -1,4 +0,0 @@
# Pins the ownCloud Web frontend version used in CI tests.
# Read by: tests/acceptance/run-e2e.py and .github/workflows/acceptance-tests.yml (Playwright cache key).
WEB_COMMITID=7dbf6ee5d4df704d19cc33da5564042e226e6871
WEB_BRANCH=stable-12.4

View File

@@ -22,7 +22,7 @@ Welcome to our developer documentation. Here you find documentation with focus f
- [oCIS]({{< ref "./ocis" >}}) server
- oCIS Services
- Clients like:
- [ownCloud Web](https://github.com/owncloud/web) - the new web frontend for oCIS and ownCloud
- [ownCloud Web](https://github.com/owncloud/ocis/tree/master/web) - the new web frontend for oCIS and ownCloud, shipped in-tree as part of oCIS
- [ownCloud Android app](https://github.com/owncloud/android)
- [ownCloud iOS app](https://github.com/owncloud/ios-app)
- [ownCloud Desktop Syncing Client](https://github.com/owncloud/client)
@@ -37,7 +37,7 @@ You can also find all client sources on [GitHub](https://github.com/owncloud/).
## Join the oCIS Community
The [server repository](https://github.com/owncloud/ocis) on [GitHub](https://www.github.com) is a good entry point to the oCIS project. In addition to that there are also ownCloud projects for clients for [iOS](https://github.com/owncloud/ios-app), [Android](https://github.com/owncloud/android), the major [Desktop](https://github.com/owncloud/desktop) platforms and [ownCloud Web](https://github.com/owncloud/web).
The [server repository](https://github.com/owncloud/ocis) on [GitHub](https://www.github.com) is a good entry point to the oCIS project -- it also contains the [ownCloud Web](https://github.com/owncloud/ocis/tree/master/web) frontend source in-tree. In addition to that there are also ownCloud projects for clients for [iOS](https://github.com/owncloud/ios-app), [Android](https://github.com/owncloud/android) and the major [Desktop](https://github.com/owncloud/desktop) platforms.
To chat about development, join our public chat on [matrix: ownCloud Infinite Scale](https://matrix.to/#/#ocis:matrix.org).

View File

@@ -386,13 +386,12 @@ The frontend for the minio server is available at `http://minio.owncloud.test` a
In case you want to run ownCloud Web from a development branch together with this deployment example (e.g. for feature development for the app provider frontend) you can use this deployment example with the local setup and some additional steps as described below.
1. Clone the [ownCloud Web repository](https://github.com/owncloud/web) on your development machine.
2. Run `pnpm i && pnpm build:w` for `web`, so that it creates and continuously updates the `dist` folder for web.
3. Add the dist folder as read only volume to `volumes` section of the `ocis` service in the `docker-compose.yml` file:
1. From your local clone of the [ocis repository](https://github.com/owncloud/ocis), run `pnpm i && pnpm build:w` inside the `web/` directory, so that it creates and continuously updates the `dist` folder for web.
2. Add the dist folder as read only volume to `volumes` section of the `ocis` service in the `docker-compose.yml` file:
```yaml
- /your/local/path/to/web/dist/:/web/dist:ro
- /your/local/path/to/ocis/web/dist/:/web/dist:ro
```
Make sure to point to the `dist` folder inside your local copy of the web repository.
Make sure to point to the `web/dist` folder inside your local copy of the ocis repository.
4. Set the oCIS environment variables `WEB_ASSET_CORE_PATH` and `WEB_ASSET_APPS_PATH` in the `environment` section of the `ocis` service, so that it uses your mounted dist folder for the web assets, instead of the assets that are embedded into oCIS.
```yaml
WEB_ASSET_CORE_PATH: "/web/dist"

View File

@@ -36,7 +36,7 @@ Depending on the functionality of your extension, you might need to integrate wi
### ownCloud Web
If your extension is not just doing something in the background, you will need a UI in order to allow the user to interact with your extension. You could just provide your own web frontend for that purpose, but for a better user experience you can easily integrate into the web frontend of oCIS, the new [ownCloud Web](https://github.com/owncloud/web).
If your extension is not just doing something in the background, you will need a UI in order to allow the user to interact with your extension. You could just provide your own web frontend for that purpose, but for a better user experience you can easily integrate into the web frontend of oCIS, [ownCloud Web](https://github.com/owncloud/ocis/tree/master/web), which ships in-tree as part of oCIS.
ownCloud Web allows you to write an extension for itself and therefore offers a seamless user experience. Upon login, the user will be able to use the application switcher to switch between the files view, settings and other available and installed extensions, yours included. Furthermore it is also possible to register your extension for different file actions. As an example, you could offer your extension to the user for creating and editing office documents. The user will then be able to create or open a file with your application directly from the files view. How to provide create an extension for ownCloud Web can be seen best in [the Hello extension](https://github.com/owncloud/ocis-hello/blob/master/ui/app.js), whereas plain file handling without any web frontend is available in the [WOPI server extension](https://github.com/owncloud/ocis-wopiserver/blob/master/ui/app.js).

View File

@@ -10,28 +10,14 @@ geekdocFilePath: releasing.md
## Releasing
The next generation Web Frontend is shipped as an oCIS Extension. The `ocis-web` extension is also embedded in the single binary and part of the `ocis server` command.
The Web Frontend source lives in-tree under `web/` and is built as part of the regular oCIS
generate/release process — there is no separate repository, version pin, or release step to
coordinate anymore.
To update this package within all the deliveries, we need to update the package in the following chain from the bottom to the top.
Running `make generate` (or `make -C services/web ci-node-generate`) builds the web frontend
from `web/` via `pnpm install && pnpm build` and copies the resulting assets into
`services/web/assets/core`, from where they are embedded into the `ocis` binary via Go's
`//go:embed` directive in `services/web/web.go`.
### Package Hierarchy
- [ocis](https://github.com/owncloud/ocis)
- [ocis-web](https://github.com/owncloud/ocis/tree/master/web)
- [ocis-pkg](https://github.com/owncloud/ocis/tree/master/ocis-pkg)
- [ownCloud Web](https://github.com/owncloud/web)
#### Prerequisites
Before updating the assets, make sure that [ownCloud Web](https://github.com/owncloud/web) has been released first
and take note of its release tag name.
#### Updating ocis-web
1. Create a branch `update-web-$version` in the [ocis repository](https://github.com/owncloud/ocis)
2. Change into web package folder via `cd web`
3. Inside `web/`, update the `Makefile` so that the WEB_ASSETS_VERSION variable references the currently released version of https://github.com/owncloud/web
4. Move to the changelog (`cd ../changelog/`) and add a changelog file to the `unreleased/` folder (You can copy an old web release changelog item as a template)
5. Move to the repo root (`cd ..`) and update the `WEB_COMMITID` in `/ci.env` to the commit id from the released version (unless the existing commit id is already newer)
6. **Optional:** Test the changes locally by running `cd ocis && go run cmd/ocis/main.go server`, visiting [https://localhost:9200](https://localhost:9200) and confirming everything renders correctly
7. Commit your changes, push them and [create a PR](https://github.com/owncloud/ocis/pulls)
To make changes to the web frontend, edit the source under `web/` directly and open a PR
against this repository, the same as any other oCIS change.

View File

@@ -1,6 +1,6 @@
SHELL := bash
NAME := web
WEB_ASSETS_VERSION = v12.4.0
WEB_DIR := ../../web
include ../../.make/recursion.mk
@@ -28,18 +28,22 @@ include ../../.make/generate.mk
ci-go-generate: # CI runs ci-node-generate automatically before this target
.PHONY: ci-node-generate
ci-node-generate: pull-assets
ci-node-generate: build-assets
.PHONY: pull-assets
pull-assets:
.PHONY: build-assets
build-assets:
cd $(WEB_DIR) && pnpm install && pnpm check:types && pnpm build
cp $(WEB_DIR)/config/config.json.dist $(WEB_DIR)/dist/
git clean -xfd assets
curl --fail -slL -o- https://github.com/owncloud/web/releases/download/$(WEB_ASSETS_VERSION)/web.tar.gz | tar xzf - -C assets/core/
cp -r $(WEB_DIR)/dist/. assets/core/
############ licenses ############
.PHONY: ci-node-check-licenses
ci-node-check-licenses: # ownCloud Web does the check on it's own
ci-node-check-licenses:
cd $(WEB_DIR) && pnpm licenses:check
.PHONY: ci-node-save-licenses
ci-node-save-licenses:
@mkdir -p ../../third-party-licenses/node/web
@curl --fail -slL -o- https://github.com/owncloud/web/releases/download/$(WEB_ASSETS_VERSION)/third-party-licenses.tar.gz | tar xzf - -C ../../third-party-licenses/node/web
cd $(WEB_DIR) && pnpm licenses:csv && pnpm licenses:save
cp -r $(WEB_DIR)/third-party-licenses/third-party-licenses/. ../../third-party-licenses/node/web/

View File

@@ -1,6 +1,6 @@
# Web
The web service embeds and serves the static files for the [Infinite Scale Web Client](https://github.com/owncloud/web).
The web service embeds and serves the static files for the Infinite Scale Web Client, whose source lives in-tree under [`web/`](https://github.com/owncloud/ocis/tree/master/web).
Note that clients will respond with a connection error if the web service is not available.
The web service also provides a minimal API for branding functionality like changing the logo shown.
@@ -25,7 +25,7 @@ for more details.
### Web UI Config File
When defined via the `WEB_UI_CONFIG_FILE` environment variable, the configuration of the web UI can be made
with a [json based](https://github.com/owncloud/web/tree/master/config) file.
with a [json based](https://github.com/owncloud/ocis/tree/master/web/config) file.
### Embedding Web

View File

@@ -16,8 +16,6 @@ services:
# email
EMAIL_HOST: email
EMAIL_PORT: 8025
env_file:
- ../../../../ci.env
volumes:
- ./run-tests.sh:/test/run-tests.sh
- ../../../../:/ocis

View File

@@ -12,13 +12,11 @@ import sys
import shlex
import subprocess
import signal
import tempfile
import time
import shutil
from pathlib import Path
WEB_REPO = "https://github.com/owncloud/web.git"
def wait_for(condition_fn, timeout: int, label: str) -> None:
deadline = time.time() + timeout
while not condition_fn():
@@ -78,6 +76,38 @@ def tika_warm(tika_url: str) -> bool:
return r.stdout.strip() == "200"
def app_providers_ready(ocis_url: str) -> bool:
# Collabora and OnlyOffice register asynchronously with the app registry
# over their WOPI bridge connection; don't start tests until both are up.
cmd = ["curl", "-sk", "-uadmin:admin", f"{ocis_url}/app/list"]
r = subprocess.run(cmd, capture_output=True, text=True)
if r.returncode != 0 or not r.stdout.strip():
return False
try:
data = json.loads(r.stdout)
except json.JSONDecodeError:
return False
names = set()
for mime in data.get("mime-types", []):
for provider in mime.get("app_providers", []):
names.add(provider.get("name"))
return "Collabora" in names and "OnlyOffice" in names
def load_env_file(path: Path) -> dict:
"""Parse a bash-style env file (export KEY=value) into a dict."""
env = {}
for line in path.read_text().splitlines():
line = line.strip()
if not line or line.startswith("#") or line.startswith("!"):
continue
line = line.removeprefix("export ").strip()
if "=" in line:
k, v = line.split("=", 1)
env[k.strip()] = v.strip()
return env
def run(cmd: list, env: dict = None, check: bool = True, cwd=None):
e = {**os.environ, **(env or {})}
return subprocess.run(cmd, env=e, check=check, cwd=cwd)
@@ -95,15 +125,22 @@ def main() -> int:
mfa_needed = os.environ.get("MFA_NEEDED", "").lower() == "true"
oidc_needed = os.environ.get("OIDC_NEEDED", "").lower() == "true"
oidc_iframe_needed = os.environ.get("OIDC_IFRAME_NEEDED", "").lower() == "true"
collaboration_needed = os.environ.get("COLLABORATION_NEEDED", "").lower() == "true"
federated_needed = os.environ.get("FEDERATED_NEEDED", "").lower() == "true"
# MFA mode runs ocis behind keycloak with TOTP enforced
keycloak_needed = keycloak_needed or mfa_needed
repo_root = Path(__file__).resolve().parents[2]
ocis_bin = repo_root / "ocis/bin/ocis"
wrapper_bin = repo_root / "tests/ociswrapper/bin/ociswrapper"
ocis_url = "https://127.0.0.1:9200"
# The federated suite must address the primary as localhost instead of
# 127.0.0.1: the ocm invite flow bakes this host into invite codes
# (token@host), and the federated instance authorizes it against
# tests/config/local/providers.json (shared with run-github.py's apiOcm
# suite), which only lists localhost:9200.
ocis_url = "https://localhost:9200" if federated_needed else "https://127.0.0.1:9200"
ocis_config_dir = Path.home() / ".ocis/config"
web_dir = repo_root / "webTestRunner"
web_dir = repo_root / "web"
# build ocis + ociswrapper only if not already provided (e.g. via artifact)
if not ocis_bin.exists():
@@ -112,22 +149,6 @@ def main() -> int:
run(["make", "-C", str(repo_root / "tests/ociswrapper"), "build"],
env={"GOWORK": "off"})
# clone + install web only if not already provided (e.g. via artifact)
if not web_dir.exists():
ci_env = {}
ci_env_file = repo_root / "ci.env"
if ci_env_file.exists():
for line in ci_env_file.read_text().splitlines():
if "=" in line and not line.startswith("#"):
k, v = line.split("=", 1)
ci_env[k.strip()] = v.strip()
web_branch = ci_env.get("WEB_BRANCH", "master")
web_commitid = ci_env.get("WEB_COMMITID", "")
run(["git", "clone", "-b", web_branch, "--single-branch", "--no-tags",
WEB_REPO, str(web_dir)])
if web_commitid:
subprocess.run(["git", "checkout", web_commitid], cwd=web_dir, check=True)
if not (web_dir / "node_modules").exists():
pkg_manager = json.loads((web_dir / "package.json").read_text()).get("packageManager", "pnpm")
run(["npm", "install", "--silent", "--global", "--force", pkg_manager])
@@ -139,8 +160,17 @@ def main() -> int:
# init ocis
run([str(ocis_bin), "init", "--insecure", "true"])
# tests/config/ci/app-registry.yaml maps its one mimetype to "FakeOffice", the
# stub used by run-github.py's (Behat) apiCollaboration suite. The app-provider
# e2e suite drives real Collabora/OnlyOffice containers instead, so it needs its
# own mapping to those app names, for both the odt and docx mimetypes it exercises.
app_registry_src = (
"tests/config/local/app-registry-office-suites.yaml"
if collaboration_needed
else "tests/config/ci/app-registry.yaml"
)
shutil.copy(
repo_root / "tests/config/ci/app-registry.yaml",
repo_root / app_registry_src,
ocis_config_dir / "app-registry.yaml",
)
@@ -170,6 +200,19 @@ def main() -> int:
gha_web_cfg = _patch_urls(drone_web_cfg, "https://ocis-server:9200", ocis_url)
# The web UI only loads the apps listed in its config. ocis-config.json predates
# the playwright suites, so add what specific suites depend on:
# - "external" is the blueprint app for the office editors: web-runtime builds
# the per-provider Collabora/OnlyOffice apps (including their "New file" menu
# entries) only when web-app-external itself is loaded.
# - "ocm" provides the "open-cloud-mesh" federation UI the ocm suite drives.
# (The federated instance's own config, tests/config/local/fed-ocis-web.json,
# already lists it.)
if collaboration_needed:
gha_web_cfg["apps"].append("external")
if federated_needed:
gha_web_cfg["apps"].append("ocm")
# The web client reads its OIDC scope from openIdConnect.scope in this UI
# config, NOT from the WEB_OIDC_SCOPE server env var, so override it here.
# - oidc (refresh-token) spec asserts the scope contains `offline_access`.
@@ -297,6 +340,56 @@ def main() -> int:
if oidc_iframe_needed:
server_env["IDP_ACCESS_TOKEN_EXPIRATION"] = "30"
if collaboration_needed:
server_env.update({
"MICRO_REGISTRY": "nats-js-kv",
"MICRO_REGISTRY_ADDRESS": "127.0.0.1:9233",
"FRONTEND_APP_HANDLER_SECURE_VIEW_APP_ADDR": "com.owncloud.api.collaboration.Collabora",
# These two domains, the page origin, and Collabora's frame_ancestors
# (workflow) must all use the same host literal: CSP source
# expressions match by exact host.
"COLLABORA_DOMAIN": "127.0.0.1:9980",
"ONLYOFFICE_DOMAIN": "127.0.0.1:443",
# The default proxy CSP only allows frame-src 'self', so the browser
# refuses to embed the office editor iframes (different port). The CSP
# file whitelists ${COLLABORA_DOMAIN}/${ONLYOFFICE_DOMAIN} in frame-src
# -- without it the editors never load and every office test times out.
"PROXY_CSP_CONFIG_FILE_LOCATION": str(repo_root / "tests/config/ci/csp.yaml"),
})
federated_url = "https://localhost:10200"
federated_env = None
if federated_needed:
# run-github.py's (Behat apiOcm) federation setup already solved this exact
# problem, so reuse its canonical port-mapping file instead of re-deriving one:
# only offsetting *_DEBUG_ADDR left the actual service ports (e.g. gateway's
# GATEWAY_GRPC_ADDR 127.0.0.1:9142) on their defaults, so the federated
# "ocis server" process crashed trying to bind the same ports the primary
# instance already held.
providers_file = str(repo_root / "tests/config/local/providers.json")
server_env.update({
"OCIS_ADD_RUN_SERVICES": "ocm",
"OCIS_ENABLE_OCM": "true",
"OCM_OCM_INVITE_MANAGER_INSECURE": "true",
"OCM_OCM_SHARE_PROVIDER_INSECURE": "true",
"OCM_OCM_STORAGE_PROVIDER_INSECURE": "true",
"OCM_OCM_PROVIDER_AUTHORIZER_PROVIDERS_FILE": providers_file,
})
federated_config_dir = Path.home() / ".ocis-federated/config"
federated_data_dir = Path.home() / ".ocis-federated"
federated_env = {**server_env}
federated_env.update(load_env_file(repo_root / "tests/config/local/.env-federation"))
# override the file's ${HOME}-prefixed paths (load_env_file doesn't expand
# shell variables) and anything specific to this script's own layout
federated_env.update({
"OCIS_URL": federated_url,
"OCIS_BASE_DATA_PATH": str(federated_data_dir),
"OCIS_CONFIG_DIR": str(federated_config_dir),
"OCM_OCM_PROVIDER_AUTHORIZER_PROVIDERS_FILE": providers_file,
"MICRO_REGISTRY_ADDRESS": "127.0.0.1:10233",
})
procs = []
print("Starting ocis...")
@@ -341,6 +434,72 @@ def main() -> int:
wait_for(lambda: search_ready(ocis_url), 60, "search service")
print("search ready.")
if collaboration_needed:
# WOPI bridges: one per office app, started only after ocis itself is up
# so they can register with its gateway. Ported from setup_wopi_collabora
# / setup_wopi_onlyoffice in tests/actions/setup-services.sh.
wopi_common = {
"MICRO_REGISTRY": "nats-js-kv",
"MICRO_REGISTRY_ADDRESS": "127.0.0.1:9233",
"COLLABORATION_APP_INSECURE": "true",
"COLLABORATION_CS3API_DATAGATEWAY_INSECURE": "true",
"OCIS_JWT_SECRET": "some-ocis-jwt-secret",
"COLLABORATION_WOPI_SECRET": "some-wopi-secret",
}
collabora_env = {
**os.environ, **wopi_common,
"COLLABORATION_GRPC_ADDR": "0.0.0.0:9301",
"COLLABORATION_HTTP_ADDR": "0.0.0.0:9300",
"COLLABORATION_DEBUG_ADDR": "0.0.0.0:9304",
"COLLABORATION_APP_NAME": "Collabora",
"COLLABORATION_APP_ADDR": "https://127.0.0.1:9980",
"COLLABORATION_APP_ICON": "https://127.0.0.1:9980/favicon.ico",
"COLLABORATION_WOPI_SRC": "http://127.0.0.1:9300",
}
onlyoffice_env = {
**os.environ, **wopi_common,
"COLLABORATION_GRPC_ADDR": "0.0.0.0:9303",
"COLLABORATION_HTTP_ADDR": "0.0.0.0:9302",
"COLLABORATION_DEBUG_ADDR": "0.0.0.0:9305",
"COLLABORATION_APP_NAME": "OnlyOffice",
"COLLABORATION_APP_PRODUCT": "OnlyOffice",
"COLLABORATION_APP_ADDR": "https://127.0.0.1:443",
"COLLABORATION_APP_ICON": "https://127.0.0.1/web-apps/apps/documenteditor/main/resources/img/favicon.ico",
"COLLABORATION_WOPI_SRC": "http://127.0.0.1:9302",
}
procs.append(subprocess.Popen([str(ocis_bin), "collaboration", "server"], env=collabora_env))
procs.append(subprocess.Popen([str(ocis_bin), "collaboration", "server"], env=onlyoffice_env))
wait_for(lambda: app_providers_ready(ocis_url), 150, "Collabora/OnlyOffice app providers")
print("app providers ready.")
if federated_needed:
# Second, independent ocis instance for OCM federation tests. See the
# federated_env comment above main() for its port-mapping source.
# OCIS_BASE_DATA_PATH must match federated_env's, or init writes the
# proxy cert under the default ~/.ocis (colliding with the primary
# instance's) instead of federated_data_dir, and the server then
# generates its own untrusted one lazily at startup.
run([str(ocis_bin), "init", "--insecure", "true"],
env={
"OCIS_CONFIG_DIR": str(federated_config_dir),
"OCIS_BASE_DATA_PATH": str(federated_data_dir),
})
federated_cert = federated_data_dir / "proxy/server.crt"
if federated_cert.exists():
subprocess.run(
["sudo", "cp", str(federated_cert),
"/usr/local/share/ca-certificates/ocis-federated.crt"],
check=True,
)
subprocess.run(["sudo", "update-ca-certificates"], check=True)
federated_proc = subprocess.Popen(
[str(ocis_bin), "server"],
env=federated_env,
)
procs.append(federated_proc)
wait_for(lambda: ocis_healthy(federated_url, use_basic_auth=True), 300, "ocis-federated")
print("ocis-federated ready.")
playwright_env = {
**os.environ,
"BASE_URL_OCIS": ocis_url,
@@ -354,15 +513,35 @@ def main() -> int:
"BROWSER": "chromium",
}
trusted_certs = [ocis_cert]
if keycloak_needed:
playwright_env.update({
"KEYCLOAK": "true",
"KEYCLOAK_HOST": "localhost:8443",
})
keycloak_cert = repo_root / "keycloak-certs/keycloakcrt.pem"
if keycloak_cert.exists():
trusted_certs.append(keycloak_cert)
if mfa_needed:
playwright_env["MFA"] = "true"
if federated_needed:
playwright_env["FEDERATED_BASE_URL_OCIS"] = "localhost:10200"
trusted_certs.append(federated_cert)
if len(trusted_certs) > 1:
# NODE_EXTRA_CA_CERTS takes a single file; concatenate every self-signed
# cert in play (oCIS, Keycloak, federated instance) so node-fetch/axios
# calls made directly against any of them are trusted too.
bundle = tempfile.NamedTemporaryFile(
mode="w", suffix=".pem", prefix="ocis-ca-bundle-", delete=False)
for cert in trusted_certs:
bundle.write(cert.read_text())
bundle.close()
playwright_env["NODE_EXTRA_CA_CERTS"] = bundle.name
print(f"Running e2e: {e2e_args}")
result = subprocess.run(
["bash", "run-e2e.sh"] + shlex.split(e2e_args),

View File

@@ -1,21 +0,0 @@
#!/bin/bash
# Checks S3 MinIO cache for web test runner artifacts (acceptance/e2e/web).
# Sources ci.env to get WEB_COMMITID used as the cache key.
source ci.env
# if no $1 is supplied end the script
# Can be web, acceptance or e2e
if [ -z "$1" ]; then
echo "No cache item is supplied."
exit 1
fi
echo "Checking web version - $WEB_COMMITID in cache"
web_cache=$(mc find s3/$CACHE_BUCKET/ocis/web-test-runner/$WEB_COMMITID/$1 2>&1 | grep 'Object does not exist')
if [[ -z "$web_cache" ]]; then
echo "$1 cache with commit id $WEB_COMMITID already available."
exit 78
else
echo "$1 cache with commit id $WEB_COMMITID was not available."
fi

View File

@@ -18,11 +18,17 @@ directives:
- '''self'''
- 'blob:'
- 'https://embed.diagrams.net/'
# In contrary to bash and docker the default is given after the | character
- 'https://${ONLYOFFICE_DOMAIN|onlyoffice:443}/'
- 'https://${COLLABORA_DOMAIN|collabora:9980}/'
img-src:
- '''self'''
- 'data:'
- 'blob:'
- 'https://raw.githubusercontent.com/owncloud/awesome-ocis/'
# In contrary to bash and docker the default is given after the | character
- 'https://${ONLYOFFICE_DOMAIN|onlyoffice:443}/'
- 'https://${COLLABORA_DOMAIN|collabora:9980}/'
manifest-src:
- '''self'''
media-src:

View File

@@ -0,0 +1,24 @@
app_registry:
mimetypes:
# Mirrors web/dev/docker/ocis/app-registry.yaml, the registry web's own e2e
# CI ran the app-provider suite against. The web UI's "New file" menu shows
# an entry for every /app/list mimetype that has allow_creation plus a
# registered provider, so the plain document mimetypes are the right ones
# here -- Collabora/OnlyOffice register them dynamically via WOPI discovery.
# "Create from template" needs no static entry either: reva stamps
# target_ext onto the -template mimetypes the providers register themselves
# (vendor/.../appprovider/templates.go).
- mime_type: application/vnd.oasis.opendocument.text
extension: odt
name: OpenDocument
description: OpenDocument text document
icon: ""
default_app: Collabora
allow_creation: true
- mime_type: application/vnd.openxmlformats-officedocument.wordprocessingml.document
extension: docx
name: Microsoft Word
description: Microsoft Word document
icon: ""
default_app: OnlyOffice
allow_creation: true

4
web/.clean-publish Normal file
View File

@@ -0,0 +1,4 @@
{
"withoutPublish": true,
"tempDir": "package"
}

6
web/.depcheckrc Normal file
View File

@@ -0,0 +1,6 @@
{
"ignores": [
"requirejs",
"@babel/register"
]
}

2
web/.dockerignore Normal file
View File

@@ -0,0 +1,2 @@
node_modules
apps/*/node_modules

14
web/.editorconfig Normal file
View File

@@ -0,0 +1,14 @@
root = true
[*]
insert_final_newline = true
charset = utf-8
trim_trailing_whitespace = true
end_of_line = lf
[*.{js,json,vue,feature,ts}]
indent_style = space
indent_size = 2
[*.{md,markdown}]
trim_trailing_whitespace = false

66
web/.gitignore vendored Normal file
View File

@@ -0,0 +1,66 @@
release/*
**/l10n/locale
**/l10n/template.pot
**/hugo
build/version.json
.env
.idea
.vscode
*.bundle.js
*.bundle.js.map
*.chunk.js
*.chunk.js.map
config.json
package-lock.json
node_modules
dist
*.log
.DS_Store
.envrc
reports
tests/e2e/cucumber/report/cucumber_report.json
tests/e2e/cucumber/reportGenerator/cucumber_report.json
tests/ocis
tests/testing-app
playwright-report
/webpack.json
/webpack-build-log.json
/.vite-inspect
/coverage
**/coverage/
/.pnpm-store/
# drone CI is in .drone.star, do not let someone accidentally commit a local .drone.yml
.drone.yml
# Themes
/packages/web-runtime/themes/*
!/packages/web-runtime/themes/owncloud/
# Compiled tokens
/packages/design-system/src/assets/tokens/
# Report for tests
tests/e2e/cucumber/report/*
!tests/e2e/cucumber/report/index.mjs
.vscode/settings.json
# third party licenses
/third-party-licenses
# dev setup
/dev/docker/ocis-ca
/dev/docker/traefik/certificates
docker-compose.override.yml
/dev/docker/apps

17
web/.npmrc Normal file
View File

@@ -0,0 +1,17 @@
auto-install-peers=true
shared-workspace-lockfile=true
# @vue/component-compiler-utils
hoist-pattern[]=sass
hoist-pattern[]=*@codemirror*
hoist-pattern[]=*@lezer*
# eslint (public so they are picked up by IDEs)
public-hoist-pattern[]=*eslint*
# Make ODS available to tests, even if the main package does not require it
public-hoist-pattern[]=@ownclouders/design-system
# c.f. https://github.com/vuejs/test-utils/pull/2197
hoist-pattern[]=@vue/server-renderer

1
web/.prettierignore Normal file
View File

@@ -0,0 +1 @@
**/src/graph/generated

1
web/.prettierrc.json Normal file
View File

@@ -0,0 +1 @@
"@ownclouders/prettier-config"

136
web/Makefile Normal file
View File

@@ -0,0 +1,136 @@
SHELL := bash
DIST := ${CURDIR}/dist
HUGO := docs/hugo
RELEASE := ${CURDIR}/release
NODE_MODULES := ${CURDIR}/node_modules
# define standard colors
BLACK := $(shell tput -Txterm setaf 0)
RED := $(shell tput -Txterm setaf 1)
GREEN := $(shell tput -Txterm setaf 2)
YELLOW := $(shell tput -Txterm setaf 3)
LIGHTPURPLE := $(shell tput -Txterm setaf 4)
PURPLE := $(shell tput -Txterm setaf 5)
BLUE := $(shell tput -Txterm setaf 6)
WHITE := $(shell tput -Txterm setaf 7)
RESET := $(shell tput -Txterm sgr0)
node_modules: package.json pnpm-lock.yaml
[ -n "${NO_INSTALL}" ] || pnpm install
touch ${NODE_MODULES}
.PHONY: help
DEFAULT_GOAL := help
help:
@echo "Please use 'make <target>' where <target> is one of the following:"
@echo
@echo -e "${GREEN}List all available .PHONY targets:${RESET}\n"
@echo -e "\tmake list\t\t${BLUE}sorted alphabetically${RESET}"
@echo -e "${BLACK}---------------------------------------------------------${RESET}"
@echo -e "${GREEN}Install/update required packages:${RESET}\n"
@echo -e "\tmake\t\t\t${BLUE}run make without target${RESET}"
@echo -e "${BLACK}---------------------------------------------------------${RESET}"
@echo
@echo -e "${GREEN}Documentation:${RESET}\n"
@echo -e "${PURPLE}\tdocs: https://owncloud.dev/ocis/build-docs/${RESET}\n"
@echo -e "\trun ${YELLOW}make list | grep docs-\t\t${BLUE}note: run all docs command via this makefile${RESET}"
@echo
.PHONY: list
list:
@echo -e 'Available .PHONY targets: \n'
@grep -P -o '(?<=^\.PHONY: )(.*)' Makefile | sort -u
@echo -e ''
.PHONY: clean
clean:
rm -rf ${DIST} ${HUGO} ${RELEASE} ${NODE_MODULES}
.PHONY: release
release: clean
make -f Makefile.release
#
# Release
# make this app compatible with the ownCloud
# default build tools
#
.PHONY: dist
dist:
make -f Makefile.release
# note that everything docs related is located in the docs/ folder
# we keep this original calls for the sake of history and ease of use
# for drone only, prepare docs, do not run manually
.PHONY: docs-generate # 1. prepare docs
docs-generate:
# initialize the docs build environment
@$(MAKE) --no-print-directory -C docs docs-init
# remind one that web needs prerequisites installed
@$(MAKE) --no-print-directory -C docs docs-first-time-message
# copy required resources into hugo/content
.PHONY: docs-copy # 2. copy required doc resources
docs-copy:
@$(MAKE) --no-print-directory -C docs docs-copy
# the docs-build|serve commands requires that docs-init was run first for the required data to exists
# create a docs build
.PHONY: docs-build # 3. build prepared docs
docs-build:
@$(MAKE) --no-print-directory -C docs docs-build
# serve built docs with hugo
.PHONY: docs-serve # serve the docs build
docs-serve:
@$(MAKE) --no-print-directory -C docs docs-serve
# clean up doc build artifacts
.PHONY: docs-clean # clean all docs artifacts, must be run as sudo
docs-clean:
@$(MAKE) --no-print-directory -C docs docs-clean
# imitate a full drone run locally to build docs without pushing to the web.
# this can help identify uncaught issues when running `make docs-serve` only.
.PHONY: docs-local # run all steps as drone would do it (1, 2, 3)
docs-local:
@$(MAKE) --no-print-directory docs-generate
@$(MAKE) --no-print-directory docs-copy
@$(MAKE) --no-print-directory docs-build
# prepare a link from the root to the hugo folder because the image requires it
# note that on local building, the referenced container of inside the hugo/makefile is used
.PHONY: docs-hugo-drone-prep # only used for drone !
docs-hugo-drone-prep:
@$(MAKE) --no-print-directory -C docs docs-hugo-drone-prep
# translation relevant
.PHONY: l10n-push
l10n-push:
@$(MAKE) --no-print-directory -C packages/web-runtime/l10n push
.PHONY: l10n-pull
l10n-pull:
@$(MAKE) --no-print-directory -C packages/web-runtime/l10n pull
.PHONY: l10n-clean
l10n-clean:
@$(MAKE) --no-print-directory -C packages/web-runtime/l10n clean
.PHONY: l10n-read
l10n-read: node_modules
@$(MAKE) --no-print-directory -C packages/web-runtime/l10n extract
.PHONY: l10n-write
l10n-write: node_modules
@$(MAKE) --no-print-directory -C packages/web-runtime/l10n translations
.PHONY: generate-qa-activity-report
generate-qa-activity-report: node_modules
@if [ -z "${MONTH}" ] || [ -z "${YEAR}" ]; then \
echo "Please set the MONTH and YEAR environment variables. Usage: make generate-qa-activity-report MONTH=<month> YEAR=<year>"; \
exit 1; \
fi
pnpm exec node generate-qa-activity-report.js --month ${MONTH} --year ${YEAR}

71
web/Makefile.release Normal file
View File

@@ -0,0 +1,71 @@
SHELL := /bin/bash
PNPM := $(shell command -v pnpm 2> /dev/null)
ifndef PNPM
$(error pnpm is not available on your system, please install npm)
endif
app_name=web
cur_dir=$(CURDIR)
dist_dir=$(CURDIR)/dist
third_party_licenses_dir=$(CURDIR)/third-party-licenses
occ=$(CURDIR)/../../occ
private_key=$(HOME)/.owncloud/certificates/$(app_name).key
certificate=$(HOME)/.owncloud/certificates/$(app_name).crt
sign=$(occ) integrity:sign-app --privateKey="$(private_key)" --certificate="$(certificate)"
sign_skip_msg="Skipping signing, either no key and certificate found in $(private_key) and $(certificate) or occ can not be found at $(occ)"
ifneq (,$(wildcard $(private_key)))
ifneq (,$(wildcard $(certificate)))
ifneq (,$(wildcard $(occ)))
CAN_SIGN=true
endif
endif
endif
.DEFAULT_GOAL := build-release
.PHONY: build-release
build-release: build package
.PHONY: build
build: build-web copy-config
.PHONY: build-web
build-web:
[ -n "${NO_INSTALL}" ] || $(PNPM) install
$(PNPM) check:types
$(PNPM) build
.PHONY: copy-config
copy-config:
cp config/config.json.dist $(dist_dir)/
.PHONY: package
package: create-release-folder create-packages
.PHONY: create-release-folder
create-release-folder:
rm -rf $(CURDIR)/release
mkdir $(CURDIR)/release
.PHONY: create-packages
create-packages: package-plain package-licenses
.PHONY: package-plain
package-plain:
cd $(dist_dir) && tar -czf $(CURDIR)/release/$(app_name).tar.gz -C $(dist_dir) *
.PHONY: package-licenses
package-licenses:
pnpm licenses:csv
pnpm licenses:save
cd $(third_party_licenses_dir) && tar -czf $(CURDIR)/release/third-party-licenses.tar.gz -C $(third_party_licenses_dir) *
.PHONY: sign
sign:
ifdef CAN_SIGN
$(sign) --path="$(dist_dir)"
else
@echo $(sign_skip_msg)
endif

45
web/README.md Normal file
View File

@@ -0,0 +1,45 @@
# ownCloud Web
ownCloud Web is the next-generation frontend for ownCloud Infinite Scale, built as a single-page application with Vue.js and TypeScript. It provides a modern, accessible and themeable user interface for managing files, sharing, real-time collaboration and administration -- designed to be extensible through a plugin-based architecture that allows third-party developers to build custom apps and extensions.
## Getting Started
Set up a local development environment for ownCloud Web:
### Prerequisites
- [Node.js](https://nodejs.org/) (LTS recommended)
- [pnpm](https://pnpm.io/)
- [Docker Compose](https://docs.docker.com/compose/) (for backend)
For the complete development setup, see the [setup guide](https://owncloud.dev/clients/web/getting-started/).
### Structure
The `web/packages` directory contains the core modules:
- **client** -- Generated TypeScript client for the oCIS Graph API
- **container** -- Static assets and base files
- **extension-sdk** -- Utilities for developing custom extensions
- **pkg** -- Shared logic used across the codebase
- **runtime** -- Authentication, routing, theming and application handling
Built-in apps (also in `web/packages`):
- **files** -- Core file sync-and-share functionality
- **admin-settings** -- User, group and space administration
- **activities** -- Activity stream
- **app-store** -- Browse and install extensions
- **epub-reader** -- Ebook file viewer
- **external** -- WOPI-based document editing (Collabora, ONLYOFFICE)
- **pdf-viewer** -- PDF file viewer
- **preview** -- Audio, video and image previewer
- **text-editor** -- Plain text editor
## Documentation
- [ownCloud Web Documentation](https://owncloud.dev/clients/web)
- [Development Guide](https://owncloud.dev/clients/web/getting-started/)
- [Extension System](https://owncloud.dev/clients/web/extension-system/)
- [Testing Documentation](https://owncloud.dev/clients/web/testing/testing/)
- [Repository Structure](https://owncloud.dev/clients/web/development/repo-structure/)

3
web/babel.config.cjs Normal file
View File

@@ -0,0 +1,3 @@
module.exports = {
presets: ['@ownclouders/babel-preset']
}

View File

@@ -0,0 +1,19 @@
{
"server" : "",
"theme": "https://localhost:9200/themes/owncloud/theme.json",
"auth": {
"clientId": "",
"url": "",
"authUrl": ""
},
"apps" : [
"files",
"pdf-viewer",
"preview",
"search",
"text-editor",
"html-editor",
"epub-reader"
],
"applications" : []
}

View File

@@ -0,0 +1,25 @@
{
"server": "https://localhost:9200",
"theme": "https://localhost:9200/themes/owncloud/theme.json",
"openIdConnect": {
"metadata_url": "https://localhost:9200/.well-known/openid-configuration",
"authority": "https://localhost:9200",
"client_id": "web",
"response_type": "code",
"scope": "openid profile email"
},
"apps": [
"files",
"preview",
"pdf-viewer",
"search",
"text-editor",
"html-editor",
"external",
"admin-settings",
"epub-reader"
],
"options": {
"contextHelpersReadMore": true
}
}

View File

@@ -0,0 +1,55 @@
---
- name: continuous-deployment-ocis-web-master
server:
server_type: cpx21
image: ubuntu-22.04
location: nbg1
initial_ssh_key_names:
- owncloud-web@drone.owncloud.com
labels:
owner: web-team
for: oCIS-continuous-deployment-examples
rebuild: $REBUILD
rebuild_carry_paths:
- /var/lib/docker/volumes/web_certs
domains:
- "*.ocis-web.master.owncloud.works"
vars:
ssh_authorized_keys:
- https://github.com/butonic.keys
- https://github.com/fschade.keys
- https://github.com/kulmann.keys
- https://github.com/micbar.keys
- https://github.com/wkloucek.keys
docker_compose_projects:
# web now lives in-tree in the ocis repo (previously a separate
# owncloud/web checkout); ops team should confirm this deployment
# example is still needed/relevant now that web ships as part of ocis.
- name: web
git_url: https://github.com/owncloud/ocis.git
ref: master
docker_compose_path: web/deployments/examples/ocis_web
env:
INSECURE: "false"
TRAEFIK_ACME_MAIL: bkulmann@owncloud.com
OCIS_DOCKER_TAG: latest
WEB_DOCKER_TAG: latest
OCIS_DOMAIN: ocis.ocis-web.master.owncloud.works
WOPISERVER_DOMAIN: wopiserver.ocis-web.master.owncloud.works
COLLABORA_DOMAIN: collabora.ocis-web.master.owncloud.works
INBUCKET_DOMAIN: mail.ocis-web.master.owncloud.works
DEMO_USERS: true
SHARE_DENIALS: true
COMPOSE_FILE: docker-compose.yml:monitoring_tracing/docker-compose-additions.yml
- name: monitoring
git_url: https://github.com/owncloud-devops/monitoring-tracing-client.git
ref: master
env:
NETWORK_NAME: ocis-net
TELEMETRY_SERVE_DOMAIN: telemetry.ocis-web.master.owncloud.works
JAEGER_COLLECTOR: jaeger-collector.infra.owncloud.works:443
TELEGRAF_SPECIFIC_CONFIG: ocis_single_container
OCIS_URL: ocis.ocis-web.master.owncloud.works
OCIS_DEPLOYMENT_ID: continuous-deployment-ocis-web-master

View File

@@ -0,0 +1,5 @@
---
---
Please refer to [our documentation](https://owncloud.dev/ocis/deployment/)
for deployment instructions.

View File

@@ -0,0 +1,58 @@
app_registry:
mimetypes:
- mime_type: application/pdf
extension: pdf
name: PDF
description: PDF document
icon: ""
default_app: ""
allow_creation: false
- mime_type: application/vnd.oasis.opendocument.text
extension: odt
name: OpenDocument
description: OpenDocument text document
icon: ""
default_app: Collabora
allow_creation: true
- mime_type: application/vnd.oasis.opendocument.spreadsheet
extension: ods
name: OpenSpreadsheet
description: OpenDocument spreadsheet document
icon: ""
default_app: Collabora
allow_creation: true
- mime_type: application/vnd.oasis.opendocument.presentation
extension: odp
name: OpenPresentation
description: OpenDocument presentation document
icon: ""
default_app: Collabora
allow_creation: true
- mime_type: application/vnd.openxmlformats-officedocument.wordprocessingml.document
extension: docx
name: Microsoft Word
description: Microsoft Word document
icon: ""
default_app: Collabora
allow_creation: true
- mime_type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
extension: xlsx
name: Microsoft Excel
description: Microsoft Excel document
icon: ""
default_app: Collabora
allow_creation: true
- mime_type: application/vnd.openxmlformats-officedocument.presentationml.presentation
extension: pptx
name: Microsoft PowerPoint
description: Microsoft PowerPoint document
icon: ""
default_app: Collabora
allow_creation: true
- mime_type: application/vnd.jupyter
extension: ipynb
name: Jupyter Notebook
description: Jupyter Notebook
icon: ""
default_app: ""
allow_creation: true

View File

@@ -0,0 +1,9 @@
Password@123
Welcome@1
Admin@123!
Summer2023!
Hello123!
Password1!
Qwerty@123
Abc12345!
MyPass@123

View File

@@ -0,0 +1,39 @@
directives:
child-src:
- '''self'''
connect-src:
- '''self'''
- 'https://raw.githubusercontent.com/owncloud/awesome-ocis/'
- 'https://${COMPANION_DOMAIN|companion.owncloud.test}/'
- 'wss://${COMPANION_DOMAIN|companion.owncloud.test}/'
default-src:
- '''none'''
font-src:
- '''self'''
frame-ancestors:
- '''self'''
frame-src:
- '''self'''
- 'https://embed.diagrams.net/'
# In contrary to bash and docker the default is given after the | character
- 'https://${COLLABORA_DOMAIN|collabora.owncloud.test}/'
img-src:
- '''self'''
- 'data:'
- 'blob:'
- 'https://raw.githubusercontent.com/owncloud/awesome-ocis/'
# In contrary to bash and docker the default is given after the | character
- 'https://${COLLABORA_DOMAIN|collabora.owncloud.test}/'
manifest-src:
- '''self'''
media-src:
- '''self'''
object-src:
- '''self'''
- 'blob:'
script-src:
- '''self'''
- '''unsafe-inline'''
style-src:
- '''self'''
- '''unsafe-inline'''

View File

@@ -0,0 +1,106 @@
---
policy_selector:
static:
policy: ocis
policies:
- name: ocis
routes:
# serve oC Web assets from the Web container
- endpoint: /
backend: http://web:8080
unprotected: true
# serve oC Web config from oCIS
- endpoint: /config.json
backend: http://localhost:9100
unprotected: true
# begin of regular oCIS proxy configuration
# we don't need the root rule for oC Web, since we replaced it
# with the both rules above
# - endpoint: /
# service: com.owncloud.web.web
# unprotected: true
- endpoint: /.well-known/webfinger
service: com.owncloud.web.webfinger
unprotected: true
- endpoint: /.well-known/openid-configuration
service: com.owncloud.web.idp
unprotected: true
- endpoint: /branding/logo
service: com.owncloud.web.web
- endpoint: /konnect/
service: com.owncloud.web.idp
unprotected: true
- endpoint: /signin/
service: com.owncloud.web.idp
unprotected: true
- endpoint: /archiver
service: com.owncloud.web.frontend
- endpoint: /ocs/v2.php/apps/notifications/api/v1/notifications/sse
service: com.owncloud.sse.sse
- endpoint: /ocs/v2.php/apps/notifications/api/v1/notifications
service: com.owncloud.web.userlog
- type: regex
endpoint: /ocs/v[12].php/cloud/user/signing-key
service: com.owncloud.web.ocs
- type: regex
endpoint: /ocs/v[12].php/config
service: com.owncloud.web.frontend
unprotected: true
- endpoint: /sciencemesh/
service: com.owncloud.web.ocm
- endpoint: /ocm/
service: com.owncloud.web.ocm
- endpoint: /ocs/
service: com.owncloud.web.frontend
- type: query
endpoint: /remote.php/?preview=1
service: com.owncloud.web.webdav
- type: regex
method: REPORT
endpoint: /remote.php/dav/
service: com.owncloud.web.webdav
- method: REPORT
endpoint: (/remote.php)?/(web)?dav
service: com.owncloud.web.webdav
- method: REPORT
endpoint: /dav/spaces
service: com.owncloud.web.webdav
- type: query
endpoint: /dav/?preview=1
service: com.owncloud.web.webdav
- type: query
endpoint: /webdav/?preview=1
service: com.owncloud.web.webdav
- endpoint: /remote.php/
service: com.owncloud.web.ocdav
- endpoint: /dav/
service: com.owncloud.web.ocdav
- endpoint: /webdav/
service: com.owncloud.web.ocdav
- endpoint: /status
service: com.owncloud.web.ocdav
unprotected: true
- endpoint: /status.php
service: com.owncloud.web.ocdav
unprotected: true
- endpoint: /index.php/
service: com.owncloud.web.ocdav
- endpoint: /apps/
service: com.owncloud.web.ocdav
- endpoint: /data
service: com.owncloud.web.frontend
unprotected: true
- endpoint: /app/list
service: com.owncloud.web.frontend
unprotected: true
- endpoint: /app/
service: com.owncloud.web.frontend
- endpoint: /graph/v1beta1/extensions/org.libregraph/activities
service: com.owncloud.web.activitylog
- endpoint: /graph/v1.0/invitations
service: com.owncloud.web.invitations
- endpoint: /graph/
service: com.owncloud.web.graph
- endpoint: /api/v0/settings
service: com.owncloud.web.settings

View File

@@ -0,0 +1,219 @@
---
services:
traefik:
image: traefik:v3.0.3
networks:
ocis-net:
aliases:
- ${OCIS_DOMAIN:-ocis.owncloud.test}
- ${WOPISERVER_DOMAIN:-wopiserver.owncloud.test}
- ${COLLABORA_DOMAIN:-collabora.owncloud.test}
command:
- '--log.level=${TRAEFIK_LOG_LEVEL:-ERROR}'
# letsencrypt configuration
- '--certificatesResolvers.http.acme.email=${TRAEFIK_ACME_MAIL:-example@example.org}'
- '--certificatesResolvers.http.acme.storage=/certs/acme.json'
- '--certificatesResolvers.http.acme.httpChallenge.entryPoint=http'
- "--certificatesresolvers.http.acme.caserver=${TRAEFIK_ACME_CASERVER:-https://acme-v02.api.letsencrypt.org/directory}"
# enable dashboard
- '--api.dashboard=true'
# define entrypoints
- '--entryPoints.http.address=:80'
- '--entryPoints.http.http.redirections.entryPoint.to=https'
- '--entryPoints.http.http.redirections.entryPoint.scheme=https'
- '--entryPoints.https.address=:443'
# docker provider (get configuration from container labels)
- '--providers.docker.endpoint=unix:///var/run/docker.sock'
- '--providers.docker.exposedByDefault=false'
ports:
- '80:80'
- '443:443'
volumes:
- '/var/run/docker.sock:/var/run/docker.sock:ro'
- 'certs:/certs'
labels:
- 'traefik.enable=${TRAEFIK_DASHBOARD:-false}'
- 'traefik.http.middlewares.traefik-auth.basicauth.users=${TRAEFIK_BASIC_AUTH_USERS:-admin:$$apr1$$4vqie50r$$YQAmQdtmz5n9rEALhxJ4l.}' # defaults to admin:admin
- 'traefik.http.routers.traefik.entrypoints=https'
- 'traefik.http.routers.traefik.rule=Host(`${TRAEFIK_DOMAIN:-traefik.owncloud.test}`)'
- 'traefik.http.routers.traefik.middlewares=traefik-auth'
- 'traefik.http.routers.traefik.tls.certresolver=http'
- 'traefik.http.routers.traefik.service=api@internal'
logging:
driver: ${LOG_DRIVER:-local}
restart: always
ocis:
image: ${OCIS_DOCKER_IMAGE:-owncloud/ocis-rolling}:${OCIS_DOCKER_TAG:-master}
networks:
ocis-net:
entrypoint:
- /bin/sh
# run ocis init to initialize a configuration file with random secrets
# it will fail on subsequent runs, because the config file already exists
# therefore we ignore the error and then start the ocis server
command: ['-c', 'ocis init || true; ocis server']
environment:
OCIS_URL: https://${OCIS_DOMAIN:-ocis.owncloud.test}
OCIS_LOG_LEVEL: ${OCIS_LOG_LEVEL:-error} # make oCIS less verbose
OCIS_LOG_COLOR: "${LOG_PRETTY:-false}"
OCIS_LOG_PRETTY: "${LOG_PRETTY:-false}"
PROXY_TLS: 'false' # do not use SSL between Traefik and oCIS
GATEWAY_GRPC_ADDR: 0.0.0.0:9142 # make the REVA gateway accessible to the app drivers
# INSECURE: needed if oCIS / Traefik is using self generated certificates
OCIS_INSECURE: '${INSECURE:-false}'
# basic auth (not recommended, but needed for eg. WebDAV clients that do not support OpenID Connect)
PROXY_ENABLE_BASIC_AUTH: '${PROXY_ENABLE_BASIC_AUTH:-false}'
# admin user password
IDM_ADMIN_PASSWORD: '${ADMIN_PASSWORD:-admin}' # this overrides the admin password from the configuration file
# demo users
IDM_CREATE_DEMO_USERS: '${DEMO_USERS:-false}'
# enable the notifications service
OCIS_ADD_RUN_SERVICES: "notifications"
NOTIFICATIONS_SMTP_HOST: inbucket
NOTIFICATIONS_SMTP_PORT: 2500
NOTIFICATIONS_SMTP_SENDER: oCIS notifications <notifications@${OCIS_DOMAIN:-ocis.owncloud.test}>
NOTIFICATIONS_SMTP_USERNAME: notifications@${OCIS_DOMAIN:-ocis.owncloud.test}
NOTIFICATIONS_SMTP_INSECURE: "true" # the mail catcher uses self signed certificates
# fulltext search
SEARCH_EXTRACTOR_TYPE: tika
SEARCH_EXTRACTOR_TIKA_TIKA_URL: http://tika:9998
# denial shares
FRONTEND_OCS_ENABLE_DENIALS: '${SHARE_DENIALS:-false}'
# make the registry available to the app provider containers
NATS_NATS_HOST: 0.0.0.0
# CSP configs
PROXY_CSP_CONFIG_FILE_LOCATION: /etc/ocis/csp.yaml
# these two vars are needed in the csp config file to include the web office apps and the importer
COLLABORA_DOMAIN: ${COLLABORA_DOMAIN:-collabora.owncloud.test}
COMPANION_DOMAIN: ${COMPANION_DOMAIN:-companion.owncloud.test}
# enable to allow using the banned passwords list
OCIS_PASSWORD_POLICY_BANNED_PASSWORDS_LIST: banned-password-list.txt
# make collabora the secure view app
FRONTEND_APP_HANDLER_SECURE_VIEW_APP_ADDR: com.owncloud.api.collaboration.Collabora
volumes:
- ./config/ocis/proxy.yaml:/etc/ocis/proxy.yaml
- ./config/ocis/app-registry.yaml:/etc/ocis/app-registry.yaml
- ./config/ocis/csp.yaml:/etc/ocis/csp.yaml
- ./config/ocis/banned-password-list.txt:/etc/ocis/banned-password-list.txt
- ocis-config:/etc/ocis
- ocis-data:/var/lib/ocis
labels:
- 'traefik.enable=true'
- 'traefik.http.routers.ocis.entrypoints=https'
- 'traefik.http.routers.ocis.rule=Host(`${OCIS_DOMAIN:-ocis.owncloud.test}`)'
- 'traefik.http.routers.ocis.tls.certresolver=http'
- 'traefik.http.routers.ocis.service=ocis'
- 'traefik.http.services.ocis.loadbalancer.server.port=9200'
logging:
driver: ${LOG_DRIVER:-local}
restart: always
web:
image: owncloud/web:${WEB_DOCKER_TAG:-latest}
networks:
ocis-net:
logging:
driver: ${LOG_DRIVER:-local}
restart: always
collaboration:
image: ${OCIS_DOCKER_IMAGE:-owncloud/ocis-rolling}:${OCIS_DOCKER_TAG:-master}
networks:
ocis-net:
depends_on:
ocis:
condition: service_started
collabora:
condition: service_healthy
entrypoint:
- /bin/sh
command: [ "-c", "ocis collaboration server" ]
environment:
COLLABORATION_GRPC_ADDR: 0.0.0.0:9301
COLLABORATION_HTTP_ADDR: 0.0.0.0:9300
COLLABORATION_WOPI_SRC: https://${WOPISERVER_DOMAIN:-wopiserver.owncloud.test}
COLLABORATION_APP_NAME: "Collabora"
COLLABORATION_APP_ADDR: https://${COLLABORA_DOMAIN:-collabora.owncloud.test}
COLLABORATION_APP_ICON: https://${COLLABORA_DOMAIN:-collabora.owncloud.test}/favicon.ico
COLLABORATION_APP_INSECURE: "${INSECURE:-true}"
COLLABORATION_CS3API_DATAGATEWAY_INSECURE: "${INSECURE:-true}"
COLLABORATION_LOG_LEVEL: ${LOG_LEVEL:-info}
MICRO_REGISTRY_ADDRESS: "ocis:9233"
OCIS_URL: https://${OCIS_DOMAIN:-ocis.owncloud.test}
volumes:
- ocis-config:/etc/ocis
labels:
- "traefik.enable=true"
- "traefik.http.routers.collaboration.entrypoints=https"
- "traefik.http.routers.collaboration.rule=Host(`${WOPISERVER_DOMAIN:-wopiserver.owncloud.test}`)"
- "traefik.http.routers.collaboration.tls.certresolver=http"
- "traefik.http.routers.collaboration.service=collaboration"
- "traefik.http.services.collaboration.loadbalancer.server.port=9300"
logging:
driver: ${LOG_DRIVER:-local}
restart: always
collabora:
image: collabora/code:24.04.5.1.1
networks:
ocis-net:
environment:
aliasgroup1: https://${WOPISERVER_DOMAIN:-wopiserver.owncloud.test}:443
DONT_GEN_SSL_CERT: 'YES'
extra_params: --o:ssl.enable=false --o:ssl.termination=true --o:welcome.enable=false --o:net.frame_ancestors=${OCIS_DOMAIN:-ocis.owncloud.test}
username: ${COLLABORA_ADMIN_USER}
password: ${COLLABORA_ADMIN_PASSWORD}
cap_add:
- MKNOD
labels:
- 'traefik.enable=true'
- 'traefik.http.routers.collabora.entrypoints=https'
- 'traefik.http.routers.collabora.rule=Host(`${COLLABORA_DOMAIN:-collabora.owncloud.test}`)'
- 'traefik.http.routers.collabora.tls.certresolver=http'
- 'traefik.http.routers.collabora.service=collabora'
- 'traefik.http.services.collabora.loadbalancer.server.port=9980'
logging:
driver: ${LOG_DRIVER:-local}
restart: always
healthcheck:
test: [ "CMD", "curl", "-f", "http://localhost:9980/hosting/discovery" ]
tika:
image: ${TIKA_IMAGE:-apache/tika:latest-full}
networks:
ocis-net:
restart: always
inbucket:
image: inbucket/inbucket
networks:
- ocis-net
entrypoint:
- /bin/sh
command: [ "-c", "apk add openssl; openssl req -subj '/CN=inbucket.test' -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout /tmp/server.key -out /tmp/server.crt; /start-inbucket.sh" ]
environment:
INBUCKET_SMTP_TLSENABLED: "true"
INBUCKET_SMTP_TLSPRIVKEY: /tmp/server.key
INBUCKET_SMTP_TLSCERT: /tmp/server.crt
INBUCKET_STORAGE_MAILBOXMSGCAP: 1000
labels:
- "traefik.enable=true"
- "traefik.http.routers.inbucket.entrypoints=https"
- "traefik.http.routers.inbucket.rule=Host(`${INBUCKET_DOMAIN:-mail.owncloud.test}`)"
- "traefik.http.routers.inbucket.tls.certresolver=http"
- "traefik.http.routers.inbucket.service=inbucket"
- "traefik.http.services.inbucket.loadbalancer.server.port=9000"
logging:
driver: ${LOG_DRIVER:-local}
restart: always
volumes:
certs:
ocis-config:
ocis-data:
networks:
ocis-net:

View File

@@ -0,0 +1,24 @@
---
version: "3.7"
services:
ocis:
environment:
# tracing
OCIS_TRACING_ENABLED: "true"
OCIS_TRACING_TYPE: "jaeger"
OCIS_TRACING_ENDPOINT: jaeger-agent:6831
# metrics
PROXY_DEBUG_ADDR: 0.0.0.0:9205
collaboration:
environment:
# tracing
OCIS_TRACING_ENABLED: "true"
OCIS_TRACING_TYPE: "jaeger"
OCIS_TRACING_ENDPOINT: jaeger-agent:6831
# metrics
COLLABORATION_DEBUG_ADDR: 0.0.0.0:9304
networks:
ocis-net:
external: true

View File

@@ -0,0 +1,20 @@
#!/bin/sh
set -e
apk add curl
#TODO: app driver itself should try again until OnlyOffice is up...
retries=10
while [[ $retries -gt 0 ]]; do
if curl --silent --show-error --fail http://onlyoffice/hosting/discovery > /dev/null; then
echo "OnlyOffice is available !!"
ocis app-provider server
else
echo "OnlyOffice is not yet available, trying again in 10 seconds"
sleep 10
retries=$((retries - 1))
fi
done
echo 'OnlyOffice was not available after 100 seconds'
exit 1

View File

@@ -0,0 +1,33 @@
clients:
- id: web
name: ownCloud web app
application_type: web
insecure: true
trusted: true
redirect_uris:
- https://host.docker.internal:9200/
- https://host.docker.internal:9200/oidc-callback.html
- https://host.docker.internal:9200/oidc-silent-redirect.html
- https://host.docker.internal:9201/
- https://host.docker.internal:9201/oidc-callback.html
- https://host.docker.internal:9201/oidc-silent-redirect.html
- https://host.docker.internal:10200/
- https://host.docker.internal:10200/oidc-callback.html
- https://host.docker.internal:10200/oidc-silent-redirect.html
- https://host.docker.internal:10201/
- https://host.docker.internal:10201/oidc-callback.html
- https://host.docker.internal:10201/oidc-silent-redirect.html
origins:
- https://host.docker.internal:9200
- https://host.docker.internal:9201
- https://host.docker.internal:10200
- https://host.docker.internal:10201
- id: xdXOt13JKxym1B1QcEncf2XDkLAexMBFwiT9j6EfhhHFJhs2KM9jbjTmf8JBXE69
name: ownCloud desktop client
application_type: native
trusted: true
secret: UBntmLjC2yYCeHwsyj73Uwo9TAaecAetRwMw0xYcvNL9yRdLSUi0hUAHfvCHFeFh
redirect_uris:
- http://localhost
- http://127.0.0.1

View File

@@ -0,0 +1,23 @@
[
{
"name": "ocis",
"full_name": "ocis server",
"organization": "ownCloud",
"domain": "host.docker.internal:(9200|10200)",
"homepage": "https://owncloud.com",
"services": [
{
"endpoint": {
"type": {
"name": "OCM",
"description": "ownCloud Open Cloud Mesh API"
},
"name": "ownCloud - OCM API",
"path": "https://host.docker.internal:(9200|10200)/ocm/",
"is_monitored": true
},
"host": "host.docker.internal:(9200|10200)"
}
]
}
]

View File

@@ -0,0 +1,26 @@
{
"server": "https://host.docker.internal:10200",
"theme": "https://host.docker.internal:10200/themes/owncloud/theme.json",
"openIdConnect": {
"metadata_url": "https://host.docker.internal:10200/.well-known/openid-configuration",
"authority": "https://host.docker.internal:10200",
"client_id": "web",
"response_type": "code",
"scope": "openid profile email"
},
"options": {
"contextHelpersReadMore": true
},
"apps": [
"files",
"text-editor",
"pdf-viewer",
"search",
"external",
"admin-settings",
"ocm",
"webfinger",
"epub-reader",
"preview"
]
}

View File

@@ -0,0 +1,29 @@
{
"server": "https://host.docker.internal:9200",
"theme": "https://host.docker.internal:9200/themes/owncloud/theme.json",
"openIdConnect": {
"metadata_url": "https://host.docker.internal:9200/.well-known/openid-configuration",
"authority": "https://host.docker.internal:9200",
"client_id": "web",
"response_type": "code",
"scope": "openid profile email acr"
},
"options": {
"contextHelpersReadMore": true
},
"apps": [
"files",
"text-editor",
"pdf-viewer",
"search",
"external",
"admin-settings",
"ocm",
"webfinger",
"epub-reader",
"app-store",
"activities",
"preview",
"password-protected-folders"
]
}

View File

@@ -0,0 +1,58 @@
app_registry:
mimetypes:
- mime_type: application/pdf
extension: pdf
name: PDF
description: PDF document
icon: ""
default_app: ""
allow_creation: false
- mime_type: application/vnd.oasis.opendocument.text
extension: odt
name: OpenDocument
description: OpenDocument text document
icon: ""
default_app: Collabora
allow_creation: true
- mime_type: application/vnd.oasis.opendocument.spreadsheet
extension: ods
name: OpenSpreadsheet
description: OpenDocument spreadsheet document
icon: ""
default_app: Collabora
allow_creation: true
- mime_type: application/vnd.oasis.opendocument.presentation
extension: odp
name: OpenPresentation
description: OpenDocument presentation document
icon: ""
default_app: Collabora
allow_creation: true
- mime_type: application/vnd.openxmlformats-officedocument.wordprocessingml.document
extension: docx
name: Microsoft Word
description: Microsoft Word document
icon: ""
default_app: OnlyOffice
allow_creation: true
- mime_type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
extension: xlsx
name: Microsoft Excel
description: Microsoft Excel document
icon: ""
default_app: OnlyOffice
allow_creation: true
- mime_type: application/vnd.openxmlformats-officedocument.presentationml.presentation
extension: pptx
name: Microsoft PowerPoint
description: Microsoft PowerPoint document
icon: ""
default_app: OnlyOffice
allow_creation: true
- mime_type: application/vnd.jupyter
extension: ipynb
name: Jupyter Notebook
description: Jupyter Notebook
icon: ""
default_app: ""
allow_creation: true

View File

@@ -0,0 +1,44 @@
directives:
child-src:
- '''self'''
connect-src:
- '''self'''
- 'blob:'
- 'https://raw.githubusercontent.com/owncloud/awesome-ocis/'
default-src:
- '''none'''
font-src:
- '''self'''
frame-ancestors:
- '''self'''
- 'https://host.docker.internal:9200'
- 'https://host.docker.internal:9201'
frame-src:
- '''self'''
- 'blob:'
- 'https://embed.diagrams.net/'
# In contrast to bash and docker the default is given after the | character
- 'https://${ONLYOFFICE_DOMAIN|host.docker.internal:9981}/'
- 'https://${COLLABORA_DOMAIN|host.docker.internal:9980}/'
img-src:
- '''self'''
- 'data:'
- 'blob:'
- 'https://raw.githubusercontent.com/owncloud/awesome-ocis/'
# In contrast to bash and docker the default is given after the | character
- 'https://${ONLYOFFICE_DOMAIN|host.docker.internal:9981}/'
- 'https://${COLLABORA_DOMAIN|host.docker.internal:9980}/'
manifest-src:
- '''self'''
media-src:
- '''self'''
object-src:
- '''self'''
- 'blob:'
script-src:
- '''self'''
- '''unsafe-inline'''
- 'https://www.gstatic.com/'
style-src:
- '''self'''
- '''unsafe-inline'''

View File

@@ -0,0 +1,3 @@
password
12345678
ownCloud-1

View File

@@ -0,0 +1,7 @@
#!/bin/sh
set -e
# we can't mount it directly because the run-document-server.sh script wants to move it
cp /etc/onlyoffice/documentserver/local.dist.json /etc/onlyoffice/documentserver/local.json
/app/ds/run-document-server.sh

View File

@@ -0,0 +1,71 @@
{
"services": {
"CoAuthoring": {
"sql": {
"type": "postgres",
"dbHost": "localhost",
"dbPort": "5432",
"dbName": "onlyoffice",
"dbUser": "onlyoffice",
"dbPass": "onlyoffice"
},
"token": {
"enable": {
"request": {
"inbox": true,
"outbox": true
},
"browser": true
},
"inbox": {
"header": "Authorization"
},
"outbox": {
"header": "Authorization"
}
},
"secret": {
"inbox": {
"string": "B8LjkNqGxn6gf8bkuBUiMwyuCFwFddnu"
},
"outbox": {
"string": "B8LjkNqGxn6gf8bkuBUiMwyuCFwFddnu"
},
"session": {
"string": "B8LjkNqGxn6gf8bkuBUiMwyuCFwFddnu"
}
}
}
},
"rabbitmq": {
"url": "amqp://guest:guest@localhost"
},
"FileConverter": {
"converter": {
"inputLimits": [
{
"type": "docx;dotx;docm;dotm",
"zip": {
"uncompressed": "1GB",
"template": "*.xml"
}
},
{
"type": "xlsx;xltx;xlsm;xltm",
"zip": {
"uncompressed": "1GB",
"template": "*.xml"
}
},
{
"type": "pptx;ppsx;potx;pptm;ppsm;potm",
"zip": {
"uncompressed": "1GB",
"template": "*.xml"
}
}
]
}
}
}

View File

@@ -0,0 +1,6 @@
tls:
stores:
default:
defaultCertificate:
certFile: /certificates/server.crt
keyFile: /certificates/server.key

View File

@@ -0,0 +1,13 @@
#!/bin/sh
set -e
echo "${WOPISECRET}" > /etc/wopi/wopisecret
cp /etc/wopi/wopiserver.conf.dist /etc/wopi/wopiserver.conf
sed -i 's/wopiserver.owncloud.test/'${WOPISERVER_DOMAIN}'/g' /etc/wopi/wopiserver.conf
if [ "$WOPISERVER_INSECURE" == "true" ]; then
sed -i 's/sslverify\s=\sTrue/sslverify = False/g' /etc/wopi/wopiserver.conf
fi
/app/wopiserver.py

View File

@@ -0,0 +1,128 @@
#
# This config is based on https://github.com/cs3org/wopiserver/blob/master/wopiserver.conf
#
# wopiserver.conf
#
# Default configuration file for the WOPI server for oCIS
#
##############################################################
[general]
# Storage access layer to be loaded in order to operate this WOPI server
# only "cs3" is supported with oCIS
storagetype = cs3
# Port where to listen for WOPI requests
port = 8880
# Logging level. Debug enables the Flask debug mode as well.
# Valid values are: Debug, Info, Warning, Error.
loglevel = Error
loghandler = stream
logdest = stdout
# URL of your WOPI server or your HA proxy in front of it
wopiurl = https://wopiserver.owncloud.test
# URL for direct download of files. The complete URL that is sent
# to clients will include the access_token argument
downloadurl = https://wopiserver.owncloud.test/wopi/iop/download
# The internal server engine to use (defaults to flask).
# Set to waitress for production installations.
internalserver = waitress
# List of file extensions deemed incompatible with LibreOffice:
# interoperable locking will be disabled for such files
nonofficetypes = .md .zmd .txt .epd
# List of file extensions to be supported by Collabora (deprecated)
codeofficetypes = .odt .ott .ods .ots .odp .otp .odg .otg .doc .dot .xls .xlt .xlm .ppt .pot .pps .vsd .dxf .wmf .cdr .pages .number .key
# WOPI access token expiration time [seconds]
tokenvalidity = 86400
# WOPI lock expiration time [seconds]
wopilockexpiration = 3600
# WOPI lock strict check: if True (default), WOPI locks will be compared according to specs,
# that is their representation must match. False allows for a more relaxed comparison,
# which compensates incorrect lock requests from Microsoft Office Online 2016-2018
# on-premise setups.
wopilockstrictcheck = True
# Enable support of rename operations from WOPI apps. This is currently
# disabled by default as it has been observed that both MS Office and Collabora
# Online do not play well with this feature.
# Not supported with oCIS, must always be set to "False"
enablerename = False
# Detection of external Microsoft Office or LibreOffice locks. By default, lock files
# compatible with Office for Desktop applications are detected, assuming that the
# underlying storage can be mounted as a remote filesystem: in this case, WOPI GetLock
# and SetLock operations return such locks and prevent online apps from entering edit mode.
# This feature can be disabled in order to operate a pure WOPI server for online apps.
# Not supported with oCIS, must always be set to "False"
detectexternallocks = False
# Location of the webconflict files. By default, such files are stored in the same path
# as the original file. If that fails (e.g. because of missing permissions),
# an attempt is made to store such files in this path if specified, otherwise
# the system falls back to the recovery space (cf. io|recoverypath).
# The keywords <user_initial> and <username> are replaced with the actual username's
# initial letter and the actual username, respectively, so you can use e.g.
# /your_storage/home/user_initial/username
#conflictpath = /
# ownCloud's WOPI proxy configuration. Disabled by default.
#wopiproxy = https://external-wopi-proxy.com
#wopiproxysecretfile = /path/to/your/shared-key-file
#proxiedappname = Name of your proxied app
[security]
# Location of the secret files. Requires a restart of the
# WOPI server when either the files or their content change.
wopisecretfile = /etc/wopi/wopisecret
# iop secret is not used for cs3 storage type
#iopsecretfile = /etc/wopi/iopsecret
# Use https as opposed to http (requires certificate)
usehttps = no
# Certificate and key for https. Requires a restart
# to apply a change.
wopicert = /etc/grid-security/host.crt
wopikey = /etc/grid-security/host.key
[bridge]
# SSL certificate check for the connected apps
sslverify = True
# Minimal time interval between two consecutive save operations [seconds]
#saveinterval = 200
# Minimal time interval before a closed file is WOPI-unlocked [seconds]
#unlockinterval = 90
# CodiMD: disable creating zipped bundles when files contain pictures
#disablezip = False
[io]
# Size used for buffered reads [bytes]
chunksize = 4194304
# Path to a recovery space in case of I/O errors when reaching to the remote storage.
# This is expected to be a local path, and it is provided in order to ease user support.
# Defaults to the indicated spool folder.
recoverypath = /var/spool/wopirecovery
[cs3]
# Host and port of the Reva(-like) CS3-compliant GRPC gateway endpoint
revagateway = ocis:9142
# Reva/gRPC authentication token expiration time [seconds]
# The default value matches Reva's default
authtokenvalidity = 3600
# SSL certificate check for Reva
sslverify = True

View File

@@ -0,0 +1,49 @@
#!/bin/bash
# This script bumps the version in the package.json files of the main app
# and all published packages to the provided version.
#
# NOTE: only run this if all packages are supposed to get the same version!
apps=("design-system" "eslint-config" "extension-sdk" "web-pkg" "web-client" "web-test-helpers")
NEW_VERSION="$1"
if [ -z "$NEW_VERSION" ]; then
echo "Error: No new version provided."
echo "Usage: $0 <new_version>"
exit 1
fi
cd "$(dirname "$0")/../.."
CURRENT_VERSION=$(node -p "require('./package.json').version")
sed -i '' "s/\"version\": \"${CURRENT_VERSION}\"/\"version\": \"${NEW_VERSION}\"/" package.json
for app in "${apps[@]}"; do
cd "./packages/$app"
CURRENT_VERSION=$(node -p "require('./package.json').version")
sed -i '' "s/\"version\": \"${CURRENT_VERSION}\"/\"version\": \"${NEW_VERSION}\"/" package.json
cd "../.."
done
echo "package.json files have been updated to version $NEW_VERSION"
SONAR_PROPERTIES_FILE="sonar-project.properties"
if [ ! -f "$SONAR_PROPERTIES_FILE" ]; then
echo "Error: $SONAR_PROPERTIES_FILE file not found!"
exit 1
fi
if [[ "$OSTYPE" == "darwin"* ]]; then
sed -i '' "s/sonar\.projectVersion=[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*/sonar.projectVersion=$NEW_VERSION/" "$SONAR_PROPERTIES_FILE"
else
sed -i "s/sonar\.projectVersion=[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*/sonar.projectVersion=$NEW_VERSION/" "$SONAR_PROPERTIES_FILE"
fi
if grep -q "sonar.projectVersion=$NEW_VERSION" "$SONAR_PROPERTIES_FILE"; then
echo "Sonar project version successfully updated to $NEW_VERSION"
else
echo "Failed to update Sonar project version. Please check the file format."
exit 1
fi

View File

@@ -0,0 +1,26 @@
#!/bin/bash
# This script creates and pushes tags for the main app and all published packages.
APPS=("design-system" "eslint-config" "extension-sdk" "web-pkg" "web-client" "web-test-helpers")
cd "$(dirname "$0")/../.."
VERSION=$(node -p "require('./package.json').version")
TAG="v${VERSION}"
git tag -s -a "$TAG" -m "$TAG"
git push origin "$TAG"
echo "v$VERSION has been created and pushed"
for app in "${APPS[@]}"; do
cd "./packages/$app"
VERSION=$(node -p "require('./package.json').version")
TAG="${app}-v${VERSION}"
git tag -s -a "$TAG" -m "$TAG"
git push origin "$TAG"
echo "$app-v$VERSION has been created and pushed"
cd "../.."
done

365
web/docker-compose.yml Normal file
View File

@@ -0,0 +1,365 @@
x-ocis-server: &ocis-service
image: ${OCIS_IMAGE:-owncloud/ocis-rolling:master}
entrypoint: /bin/sh
command: ['-c', 'ocis init || true && ocis server']
environment: &ocis-environment
OCIS_INSECURE: '${OCIS_INSECURE:-true}'
OCIS_LOG_LEVEL: '${OCIS_LOG_LEVEL:-error}'
OCIS_LOG_PRETTY: '${OCIS_LOG_PRETTY:-true}'
OCIS_LOG_COLOR: '${OCIS_LOG_COLOR:-true}'
OCIS_PASSWORD_POLICY_MIN_CHARACTERS: '3'
OCIS_PASSWORD_POLICY_MIN_LOWERCASE_CHARACTERS: '0'
OCIS_PASSWORD_POLICY_MIN_UPPERCASE_CHARACTERS: '0'
OCIS_PASSWORD_POLICY_MIN_DIGITS: '0'
OCIS_PASSWORD_POLICY_MIN_SPECIAL_CHARACTERS: '0'
OCIS_PASSWORD_POLICY_BANNED_PASSWORDS_LIST: '/etc/ocis/password-policy-banned-passwords.txt'
# WEB
WEB_ASSET_CORE_PATH: ${WEB_ASSET_CORE_PATH:-/web/dist}
WEB_ASSET_APPS_PATH: ${WEB_ASSET_APPS_PATH:-/web/apps}
WEB_UI_CONFIG_FILE: ${WEB_UI_CONFIG_FILE:-/web/config.json}
#FRONTEND
FRONTEND_SEARCH_MIN_LENGTH: '2'
FRONTEND_OCS_ENABLE_DENIALS: 'true'
FRONTEND_FULL_TEXT_SEARCH_ENABLED: 'true'
GRAPH_INCLUDE_OCM_SHAREES: 'true'
FRONTEND_CONFIGURABLE_NOTIFICATIONS: 'true'
# IDM
IDM_CREATE_DEMO_USERS: '${DEMO_USERS:-true}'
IDM_ADMIN_PASSWORD: '${ADMIN_PASSWORD:-admin}' # override the random admin password from `ocis init`
IDM_SVC_PASSWORD: '${IDM_SVC_PASSWORD:-some-ldap-idm-password}'
IDM_REVASVC_PASSWORD: '${IDM_REVASVC_PASSWORD:-some-ldap-reva-password}'
IDM_IDPSVC_PASSWORD: '${IDM_IDPSVC_PASSWORD:-some-ldap-idp-password}'
# IDP
IDP_LDAP_BIND_PASSWORD: '${IDP_LDAP_BIND_PASSWORD:-some-ldap-idp-password}'
# STORAGE
STORAGE_HOME_DRIVER: '${STORAGE_HOME_DRIVER:-ocis}'
STORAGE_USERS_DRIVER: '${STORAGE_USERS_DRIVER:-ocis}'
STORAGE_TRANSFER_SECRET: '${STORAGE_TRANSFER_SECRET:-some-ocis-transfer-secret}'
# LDAP
GROUPS_LDAP_BIND_PASSWORD: '${GROUPS_LDAP_BIND_PASSWORD:-some-ldap-reva-password}'
USERS_LDAP_BIND_PASSWORD: '${USERS_LDAP_BIND_PASSWORD:-some-ldap-reva-password}'
AUTH_BASIC_LDAP_BIND_PASSWORD: '${AUTH_BASIC_LDAP_BIND_PASSWORD:-some-ldap-reva-password}'
GRAPH_APPLICATION_ID: '${GRAPH_APPLICATION_ID:-some-graph-app-id}'
GRAPH_LDAP_BIND_PASSWORD: '${GRAPH_LDAP_BIND_PASSWORD:-some-ldap-idm-password}'
LDAP_GROUP_SUBSTRING_FILTER_TYPE: 'any'
LDAP_USER_SUBSTRING_FILTER_TYPE: 'any'
# PROXY
PROXY_ENABLE_BASIC_AUTH: '${PROXY_ENABLE_BASIC_AUTH:-true}'
PROXY_TLS: 'false'
# TIKA
SEARCH_EXTRACTOR_TYPE: 'tika'
SEARCH_EXTRACTOR_TIKA_TIKA_URL: 'http://host.docker.internal:9998'
SEARCH_EXTRACTOR_CS3SOURCE_INSECURE: 'true'
# App Provider
GATEWAY_GRPC_ADDR: 0.0.0.0:9142 # make the REVA gateway accessible to the app drivers
NATS_NATS_HOST: 0.0.0.0
NATS_NATS_PORT: 9233
# OCM
OCM_OCM_PROVIDER_AUTHORIZER_PROVIDERS_FILE: '/etc/ocis/ocmproviders.json'
OCM_OCM_INVITE_MANAGER_INSECURE: 'true'
OCM_OCM_SHARE_PROVIDER_INSECURE: 'true'
OCM_OCM_STORAGE_PROVIDER_INSECURE: 'true'
extra_hosts:
- host.docker.internal:${DOCKER_HOST:-host-gateway}
restart: unless-stopped
depends_on:
- traefik
- tika-service
services:
ocis:
<<: *ocis-service
container_name: web_ocis
environment:
<<: *ocis-environment
OCIS_URL: ${OCIS_URL:-https://host.docker.internal:9200}
OCIS_CORS_ALLOW_ORIGINS: https://host.docker.internal:9200,https://host.docker.internal:9201
OCM_WEBAPP_TEMPLATE: https://host.docker.internal:9201/o/{{.Token}}/{relative-path-to-shared-resource}
# make the registry available to the app provider containers
MICRO_REGISTRY: 'nats-js-kv'
MICRO_REGISTRY_ADDRESS: 0.0.0.0:9233
PROXY_CSP_CONFIG_FILE_LOCATION: /etc/ocis/csp.yaml
ONLYOFFICE_DOMAIN: host.docker.internal:9981
COLLABORA_DOMAIN: host.docker.internal:9980
FRONTEND_APP_HANDLER_SECURE_VIEW_APP_ADDR: com.owncloud.api.collaboration.Collabora
# Needed for enabling all roles
GRAPH_AVAILABLE_ROLES: b1e2218d-eef8-4d4c-b82d-0f1a1b48f3b5,a8d5fe5e-96e3-418d-825b-534dbdf22b99,fb6c3e19-e378-47e5-b277-9732f9de6e21,58c63c02-1d89-4572-916a-870abc5a1b7d,2d00ce52-1fc2-4dbc-8b95-a73b73395f5a,1c996275-f1c9-4e71-abdf-a42f6495e960,312c0871-5ef7-4b3a-85b6-0e4074c64049,aa97fe03-7980-45ac-9e50-b325749fd7e6,63e64e19-8d43-42ec-a738-2b6af2610efa
labels:
traefik.enable: true
traefik.http.routers.ocis.tls: true
traefik.http.routers.ocis.rule: Host(`host.docker.internal`) && PathPrefix(`/`)
traefik.http.routers.ocis.entrypoints: ocis
traefik.http.services.ocis.loadbalancer.server.port: 9200
# workaround: https://github.com/owncloud/ocis/issues/5108
traefik.http.routers.ocis.middlewares: cors
volumes:
- ./dev/docker/ocis/csp.yaml:/etc/ocis/csp.yaml
- ./dev/docker/ocis/password-policy-banned-passwords.txt:/etc/ocis/password-policy-banned-passwords.txt
- ./dev/docker/ocis.idp.config.yaml:/etc/ocis/idp.yaml
- ./dev/docker/ocis-ca:/var/lib/ocis/proxy
- ./dev/docker/ocis.storage.ocmproviders.json:/etc/ocis/ocmproviders.json
- ./dev/docker/apps:/web/apps
- ./dist:/web/dist
- ./dev/docker/ocis/app-registry.yaml:/etc/ocis/app-registry.yaml
- ocis-config:/etc/ocis
- ${OCIS_WEB_CONFIG:-./dev/docker/ocis.web.config.json}:/web/config.json:ro
ocis-federated:
<<: *ocis-service
container_name: web_ocis_federated
environment:
<<: *ocis-environment
OCIS_URL: https://host.docker.internal:10200
OCIS_CORS_ALLOW_ORIGINS: https://host.docker.internal:10201
OCM_WEBAPP_TEMPLATE: https://host.docker.internal:10201/o/{{.Token}}/{relative-path-to-shared-resource}
labels:
traefik.enable: true
traefik.http.routers.ocis-federated.tls: true
traefik.http.routers.ocis-federated.rule: Host(`host.docker.internal`) && PathPrefix(`/`)
traefik.http.routers.ocis-federated.entrypoints: ocis-federated
traefik.http.services.ocis-federated.loadbalancer.server.port: 9200
# workaround: https://github.com/owncloud/ocis/issues/5108
traefik.http.routers.ocis-federated.middlewares: cors
volumes:
- ./dev/docker/ocis/password-policy-banned-passwords.txt:/etc/ocis/password-policy-banned-passwords.txt
- ./dev/docker/ocis.idp.config.yaml:/etc/ocis/idp.yaml
- ./dev/docker/ocis-ca:/var/lib/ocis/proxy
- ./dev/docker/ocis.storage.ocmproviders.json:/etc/ocis/ocmproviders.json
- ./dist:/web/dist
- ./dev/docker/ocis/app-registry.yaml:/etc/ocis/app-registry.yaml
- ocis-federated-config:/etc/ocis
- ${OCIS_WEB_CONFIG:-./dev/docker/ocis.web-federated.config.json}:/web/config.json:ro
collaboration:
image: ${OCIS_IMAGE:-owncloud/ocis-rolling:master}
depends_on:
ocis:
condition: service_started
collabora:
condition: service_healthy
entrypoint:
- /bin/sh
command: ['-c', 'ocis collaboration server']
environment:
COLLABORATION_GRPC_ADDR: 0.0.0.0:9301
COLLABORATION_HTTP_ADDR: 0.0.0.0:9300
MICRO_REGISTRY: nats-js-kv
MICRO_REGISTRY_ADDRESS: ocis:9233
COLLABORATION_WOPI_SRC: https://${WOPISERVER_DOMAIN:-host.docker.internal:9300}
COLLABORATION_APP_NAME: Collabora
COLLABORATION_APP_ADDR: https://${COLLABORA_DOMAIN:-host.docker.internal:9980}
COLLABORATION_APP_ICON: https://${COLLABORA_DOMAIN:-host.docker.internal:9980}/favicon.ico
COLLABORATION_APP_INSECURE: ${INSECURE:-true}
COLLABORATION_CS3API_DATAGATEWAY_INSECURE: ${INSECURE:-true}
COLLABORATION_LOG_LEVEL: ${LOG_LEVEL:-info}
OCIS_URL: ${OCIS_URL:-https://host.docker.internal:9200}
extra_hosts:
- host.docker.internal:${DOCKER_HOST:-host-gateway}
volumes:
- ocis-config:/etc/ocis
labels:
traefik.enable: true
traefik.http.routers.collaboration.tls: true
traefik.http.routers.collaboration.rule: PathPrefix(`/`)
traefik.http.routers.collaboration.entrypoints: collaboration
traefik.http.services.collaboration.loadbalancer.server.port: 9300
logging:
driver: ${LOG_DRIVER:-local}
restart: always
collabora:
image: collabora/code:25.04.7.3.1
entrypoint: /bin/sh
command: ['-c', 'coolconfig generate-proof-key ; /start-collabora-online.sh']
environment:
DONT_GEN_SSL_CERT: YES
extra_params: |
--o:ssl.enable=false \
--o:ssl.ssl_verification=false \
--o:ssl.termination=true \
--o:welcome.enable=false \
--o:net.content_security_policy=frame-ancestors ${OCIS_URL:-https://host.docker.internal:9200}
username: ${COLLABORA_ADMIN_USER:-admin}
password: ${COLLABORA_ADMIN_PASSWORD:-admin}
cap_add:
- MKNOD
- SYS_ADMIN
extra_hosts:
- host.docker.internal:${DOCKER_HOST:-host-gateway}
healthcheck:
test: [
'CMD',
'bash',
'-c',
"exec 3<>/dev/tcp/127.0.0.1/9980 && echo -e 'GET /hosting/discovery HTTP/1.1\r\nHost: localhost:9980\r\n\r\n' >&3 && head -n 1 <&3 | grep '200 OK'"
]
labels:
traefik.enable: true
traefik.http.routers.collabora.tls: true
traefik.http.routers.collabora.rule: PathPrefix(`/`)
traefik.http.routers.collabora.entrypoints: collabora
traefik.http.services.collabora.loadbalancer.server.port: 9980
restart: always
depends_on:
- traefik
collaboration-oo:
image: ${OCIS_IMAGE:-owncloud/ocis-rolling:master}
depends_on:
ocis:
condition: service_started
onlyoffice:
condition: service_healthy
entrypoint:
- /bin/sh
command: ['-c', 'ocis collaboration server']
environment:
COLLABORATION_GRPC_ADDR: 0.0.0.0:9303
COLLABORATION_HTTP_ADDR: 0.0.0.0:9302
MICRO_REGISTRY: nats-js-kv
MICRO_REGISTRY_ADDRESS: ocis:9233
COLLABORATION_WOPI_SRC: https://${WOPISERVER_ONLYOFFICE_DOMAIN:-host.docker.internal:9302}
COLLABORATION_APP_NAME: OnlyOffice
COLLABORATION_APP_PRODUCT: OnlyOffice
COLLABORATION_APP_ADDR: https://${ONLYOFFICE_DOMAIN:-host.docker.internal:9981}
COLLABORATION_APP_ICON: https://${ONLYOFFICE_DOMAIN:-host.docker.internal:9981}/web-apps/apps/documenteditor/main/resources/img/favicon.ico
COLLABORATION_APP_INSECURE: ${INSECURE:-true}
COLLABORATION_CS3API_DATAGATEWAY_INSECURE: ${INSECURE:-true}
COLLABORATION_LOG_LEVEL: ${LOG_LEVEL:-info}
OCIS_URL: ${OCIS_URL:-https://host.docker.internal:9200}
extra_hosts:
- host.docker.internal:${DOCKER_HOST:-host-gateway}
volumes:
- ocis-config:/etc/ocis
labels:
traefik.enable: true
traefik.http.routers.collaboration-oo.tls: true
traefik.http.routers.collaboration-oo.rule: PathPrefix(`/`)
traefik.http.routers.collaboration-oo.entrypoints: collaboration-oo
traefik.http.services.collaboration-oo.loadbalancer.server.port: 9302
logging:
driver: ${LOG_DRIVER:-local}
restart: always
onlyoffice:
image: onlyoffice/documentserver:9.2.1
entrypoint:
- /bin/sh
- /entrypoint-override.sh
environment:
WOPI_ENABLED: true
USE_UNAUTHORIZED_STORAGE: true # self signed certificates
volumes:
- ./dev/docker/onlyoffice/entrypoint-override.sh:/entrypoint-override.sh
- ./dev/docker/onlyoffice/local.json:/etc/onlyoffice/documentserver/local.dist.json
extra_hosts:
- host.docker.internal:${DOCKER_HOST:-host-gateway}
healthcheck:
test: ['CMD', 'curl', '-f', 'http://localhost/hosting/discovery']
labels:
traefik.enable: true
traefik.http.routers.onlyoffice.tls: true
traefik.http.routers.onlyoffice.rule: PathPrefix(`/`)
traefik.http.routers.onlyoffice.entrypoints: websecure
traefik.http.services.onlyoffice.loadbalancer.server.port: 80
# websockets can't be opened when this is ommitted
traefik.http.middlewares.onlyoffice.headers.customrequestheaders.X-Forwarded-Proto: https
traefik.http.routers.onlyoffice.middlewares: onlyoffice
restart: always
depends_on:
- traefik
traefik:
image: traefik:v3.7.1
restart: unless-stopped
entrypoint:
[
'/bin/sh',
'-c',
"[ -f /certificates/server.key ] && ./entrypoint.sh $$@ || (apk add openssl && openssl req -subj '/CN=ocis.test' -x509 -sha256 -nodes -days 3650 -newkey rsa:2048 -keyout /certificates/server.key -out /certificates/server.crt && chmod -R 777 /certificates && ./entrypoint.sh $$@)"
]
command:
- '--pilot.dashboard=false'
- '--log.level=DEBUG'
- '--api.dashboard=true'
- '--api.insecure=true'
- '--providers.file.directory=/configs'
- '--providers.docker=true'
- '--providers.docker.exposedbydefault=false'
- '--entrypoints.web.address=:80'
- '--entrypoints.ocis.address=:9200'
- '--entrypoints.ocis-federated.address=:10200'
- '--entrypoints.collabora.address=:9980'
# allow encoded characters which is required for collaboration/Collabora
- '--entryPoints.collabora.http.encodedCharacters.allowEncodedSlash=true'
- '--entryPoints.collabora.http.encodedCharacters.allowEncodedQuestionMark=true'
- '--entryPoints.collabora.http.encodedCharacters.allowEncodedPercent=true'
- '--entrypoints.wopi.address=:8880'
- '--entrypoints.collaboration.address=:9300'
- '--entrypoints.collaboration-oo.address=:9302'
- '--entrypoints.websecure.address=:443'
- '--entrypoints.websecure.http.middlewares=https_config@docker'
- '--entrypoints.websecure.http.tls.options=default'
labels:
traefik.enable: true
traefik.http.routers.http_catchall.rule: HostRegexp(`{any:.+}`)
traefik.http.routers.http_catchall.entrypoints: web
traefik.http.routers.http_catchall.middlewares: https_config
traefik.http.middlewares.https_config.headers.sslRedirect: true
traefik.http.middlewares.https_config.headers.stsSeconds: 63072000
traefik.http.middlewares.https_config.headers.stsIncludeSubdomains: true
traefik.http.middlewares.cors.headers.accesscontrolallowmethods: '*'
traefik.http.middlewares.cors.headers.accesscontrolallowheaders: '*'
traefik.http.middlewares.cors.headers.accesscontrolalloworiginlist: '*'
traefik.http.middlewares.cors.headers.accesscontrolexposeheaders: '*'
traefik.http.middlewares.cors.headers.accesscontrolmaxage: 100
traefik.http.middlewares.cors.headers.addvaryheader: true
ports:
- '80:80'
- '8090:8080'
- '9200:9200'
- '9300:9300'
- '9302:9302'
- '10200:10200'
- '9980:9980'
- '8880:8880'
- '9981:443'
volumes:
- './dev/docker/traefik/certificates:/certificates'
- './dev/docker/traefik/configs:/configs'
- '/var/run/docker.sock:/var/run/docker.sock:ro'
tika-service:
image: owncloudci/wait-for:latest
container_name: web_tika_service
depends_on:
- tika
command:
- 'wait-for -it tika:9998 -t 300'
tika:
image: apache/tika:3.2.3.0
container_name: web_tika
platform: linux/amd64
ports:
- 9998:9998
restart: unless-stopped
volumes:
uploads:
ocis-config:
ocis-federated-config:
networks:
traefik:

25
web/docker/Dockerfile Normal file
View File

@@ -0,0 +1,25 @@
FROM owncloudops/nginx@sha256:8ca0c90c2f537fef6195ba8f5ebe6d6c00fe0a0c545f25ce8acd418a831a19a4
LABEL maintainer="ownCloud GmbH <devops@owncloud.com>" \
org.opencontainers.image.title="ownCloud Web" \
org.opencontainers.image.vendor="ownCloud GmbH" \
org.opencontainers.image.authors="ownCloud GmbH" \
org.opencontainers.image.description="ownCloud Web - User interface for ownCloud" \
org.opencontainers.image.licenses="Apache-2.0" \
org.opencontainers.image.documentation="https://github.com/owncloud/ocis" \
org.opencontainers.image.url="https://hub.docker.com/r/owncloud/web" \
org.opencontainers.image.source="https://github.com/owncloud/ocis"
RUN rm -f /var/lib/nginx/html/*
ADD docker/overlay /
ADD dist/ /var/lib/nginx/html
EXPOSE 8080
USER nginx
STOPSIGNAL SIGTERM
CMD ["nginx", "-g", "daemon off;"]
WORKDIR /var/lib/nginx/html

View File

@@ -0,0 +1,10 @@
#!/usr/bin/env sh
set -eo pipefail
URL=http://127.0.0.1:8080
wget --quiet --tries=1 --spider ${URL}
[ $? -ne 0 ] && exit 1
exit 0

95
web/docs/Makefile Normal file
View File

@@ -0,0 +1,95 @@
SHELL := bash
NAME := web
# we need an override so that this variable is cleanly set in this makefile
# else it might come from somewhere else
override HUGO := ${CURDIR}/hugo
override HDIR := ${CURDIR}/hugo/.git
# print a hint when doing a local build because it may fail if you have not run pnpm commands at least once
docs-first-time-message:
@echo
@echo 'Note, on a fresh web clone, you need to run `pnpm install` and `pnpm build` once to create required directories.'
# if the directory exists, print that we do not need to prepare
hugo-exists:
@if [ -d $(HDIR) ]; then \
echo; \
echo 'Build environment for hugo exists, nothing to setup, continuing.'; \
fi
# if the directory does not extist, initialize the framework and create the theme
$(HDIR):
@echo 'Initialize the hugo framework and build the theme, no docs get built.'
@mkdir -p $(HUGO)/content/
@mkdir -p $(HUGO)/extensions/
@mkdir -p $(HUGO)/public/
@cd $(HUGO) && git init
@cd $(HUGO) && git config advice.detachedHead false
@cd $(HUGO) && git remote rm origin || true
@cd $(HUGO) && git remote add origin https://github.com/owncloud/owncloud.github.io
@cd $(HUGO) && git fetch --depth=1
@cd $(HUGO) && git checkout origin/main -f
@$(MAKE) -C $(HUGO) --no-print-directory theme
# print available make targets
.PHONY: help
.DEFAULT_GOAL := help
help:
@echo -e 'Available .PHONY targets: \n'
@grep -P -o '(?<=^\.PHONY: )(.*)' Makefile | sort -u
@echo
# alternative target because we also use it in the root's makefile
.PHONY:list
list: help
# for drone only. drone uses an image for hugo that needs the hugo folder in the root
# CURDIR will work for make only but not when running manually in the shell
.PHONY: docs-hugo-drone-prep
docs-hugo-drone-prep:
@echo
@echo 'Linking directory hugo for drone.'
@rm -f ../hugo
@ln -s $(HUGO) ../hugo
# create the docs build environment
.PHONY: docs-init
docs-init: hugo-exists $(HDIR)
# if there is nothing to do, stop printing that
# another way would be https://stackoverflow.com/questions/58039810/makefiles-what-is-an-order-only-prerequisite
@:
# the docs-build|serve commands require that docs-init was run first for the required data to exists
# create a docs build
.PHONY: docs-build
docs-build:
@echo
@echo 'Building web for owncloud.dev'
@$(MAKE) -C $(HUGO) --no-print-directory hugo-build
@echo 'To view the rendered docs in the browser, run: make docs-serve'
# serve built docs with hugo
.PHONY: docs-serve
docs-serve:
@$(MAKE) -C $(HUGO) --no-print-directory hugo-server
# copy required resources into hugo
.PHONY: docs-copy
docs-copy:
@echo
@echo 'Syncing required doc files and directories for the build process.'
# brace expansion not with sh
@rsync --delete -ax --exclude={hugo,Makefile,.gitignore,README.md} ./ $(HUGO)/content/$(NAME)
# clean up docs build artifacts (removing the hugo folder)
.PHONY: docs-clean
docs-clean:
# NOTE: the whitespace at the beginning of the ifeq/else/endif statements is intentional.
@echo
ifneq ($(shell id -u), 0)
@echo "You must run the clean command using sudo or as root because some doc files are created by root"
else
@echo 'Clean up docs build artifacts'
@rm -rf $(HUGO)
@echo "Removed folder: $(HUGO)"
endif

12
web/docs/_index.md Normal file
View File

@@ -0,0 +1,12 @@
---
title: "ownCloud Web"
date: 2018-05-02T00:00:00+00:00
weight: -15
geekdocRepo: https://github.com/owncloud/web
geekdocEditPath: edit/master/docs
geekdocFilePath: _index.md
geekdocCollapseSection: true
---
This is the next generation ownCloud frontend.
If you're new here, head over to the the [getting started guide]({{< ref "getting-started.md" >}}) for a quick introduction.

74
web/docs/backend-oc10.md Normal file
View File

@@ -0,0 +1,74 @@
---
title: "Setup With ownCloud Classic"
date: 2020-04-15T00:00:00+00:00
weight: 40
geekdocRepo: https://github.com/owncloud/web
geekdocEditPath: edit/master/docs
geekdocFilePath: backend-oc10.md
---
{{< toc >}}
## Compatibility
Please note that the usage of Web UI and ownCloud Classic as backend is not recommended starting with version 7.1.0 of the Web UI. Therefore, this section only applies to versions < 7.1.0.
## Prerequisites
Decide on which host and port Web will be served, for example `https://web-host:9100/web-path/`.
In this document, we will refer to the following:
- `<web-url>` as the full URL, for example `https://web-host:9100/web-path/`
- `<web-domain>` as the protocol, domain and port, for example: `https://web-host:9100`
## Setting up ownCloud Classic
Make sure you have [ownCloud Classic](https://owncloud.org/download/#owncloud-server) already installed.
### Adjusting config.php
Add the following entries to config/config.php:
- tell ownCloud where Web is located:
```
'web.baseUrl' => '<web-url>',
```
- add a CORS domain entry for Web in config.php:
```
'cors.allowed-domains' => ['<web-domain>'],
```
### Setting up OAuth2
To connect to the ownCloud server, it is necessary to set it up with OAuth2.
Install and enable the [oauth2 app](https://marketplace.owncloud.com/apps/oauth2):
```bash
% occ market:install oauth2
% occ app:enable oauth2
```
Login as administrator in the ownCloud Classic web interface and go to the "User Authentication" section in the admin settings and add an entry for Web as follows:
- pick an arbitrary name for the client
- set the redirection URI to `<web-url>/oidc-callback.html`
- make sure to take note of the **client identifier** value as it will be needed in the Web configuration later on
### Setting up Web
In the local Web checkout, copy the `config/config.json.sample-oc10` file to `config/config.json` and adjust it accordingly:
- Set the "server" key to the URL of the ownCloud server including path. If the URL contains a path, please also add a **trailing slash** there.
- Set the "clientId" key to the **client identifier** as copied from the "User Authentication" section before.
- Adjust "url" and "authUrl" using the ownCloud server URL as prefix for both
- Optionally adjust "apps" for the list of apps to be loaded. These match the app names inside the "apps" folder.
## Running Web
- if running from source, make sure to [build Web]({{< ref "./building.md" >}}) first
- run by launching a rollup dev server `pnpm serve`
- when working on the Web code, rollup will recompile the code automatically
## Running acceptance tests
For testing, please refer to the [testing docs]({{< ref "testing/_index.md" >}})

36
web/docs/backend-ocis.md Normal file
View File

@@ -0,0 +1,36 @@
---
title: "Setup With oCIS"
date: 2020-04-15T00:00:00+00:00
weight: 50
geekdocRepo: https://github.com/owncloud/web
geekdocEditPath: edit/master/docs
geekdocFilePath: backend-ocis.md
---
{{< toc >}}
## Setting up Web
- Clone the [repository](https://github.com/owncloud/web/)
- Initally install all dependencies by running `pnpm install`
- Copy `./config/config.json.sample-ocis` to `./config/config.json` and adjust values if required
## Running Web
- Start bundling web with a watcher by running `pnpm build:w`
## Setting up oCIS
- Setup oCIS by following the [setup instructions](https://owncloud.dev/ocis/getting-started/)
- Start oCIS with local links to your bundled web frontend and config by running `WEB_ASSET_CORE_PATH=../../web/dist WEB_UI_CONFIG_FILE=../../web/dist/config.json OCIS_INSECURE=true IDM_CREATE_DEMO_USERS=true ./bin/ocis server` (and make sure to adjust paths as necessary)
## Start oCIS
- open [https://localhost:9200](https://localhost:9200) and accept the certificate
- when signing in, use one of the [available demo users](https://owncloud.dev/ocis/getting-started/demo-users/)
- whenever code changes are made, you need to manually reload the browser page (no hot reload)
## Running tests
For testing, please refer to the [testing docs]({{< ref "testing/_index.md" >}})

30
web/docs/building.md Normal file
View File

@@ -0,0 +1,30 @@
---
title: "Building From Source"
date: 2018-05-02T00:00:00+00:00
weight: 20
geekdocRepo: https://github.com/owncloud/web
geekdocEditPath: edit/master/docs
geekdocFilePath: building.md
---
{{< toc >}}
## Building ownCloud Web
- Run `pnpm install` to install dependencies
- Run `pnpm build` to build Web and all apps included in the `packages` folder
### Updating Dependencies
- **Do not** update dependencies by yourself but use the provided ones by the repo. When rebasing your local clone, you can always run `pnpm install` to be in sync with the defined dependencies.
## Building the Documentation
Note that the documentation is located in the `docs/` folder.
Note that you should always rebase your working branch if it is based on an older master. This ensures that any relevant documentation build changes have been applied and will not affect the building process.
### Details
For details of the documentation such as notes, setup and how-to's, see the [Documentation](https://owncloud.dev/ocis/build-docs/) section in the developer docs.

View File

@@ -0,0 +1,11 @@
---
title: "Deployments"
date: 2018-05-02T00:00:00+00:00
weight: 55
geekdocRepo: https://github.com/owncloud/web
geekdocEditPath: edit/master/docs/deployments
geekdocFilePath: _index.md
geekdocCollapseSection: true
---
Showcases of different scenarios of deploying ownCloud Web.

View File

@@ -0,0 +1,288 @@
---
title: "Deploy as an app in ownCloud Classic"
date: 2018-05-02T00:00:00+00:00
weight: 1
geekdocRepo: https://github.com/owncloud/web
geekdocEditPath: edit/master/docs/deployments
geekdocFilePath: oc10-app.md
---
{{< toc >}}
## Compatibility
Please note that the usage of Web UI and ownCloud Classic as backend is not recommended starting with version 7.1.0 of the Web UI. Therefore, this section only applies to versions < 7.1.0.
## Introduction
ownCloud Web is being deployed as an app to [ownCloud marketplace](https://marketplace.owncloud.com/) to enable easy integration into existing ownCloud Classic instances.
After completing this setup, ownCloud Web will be available on `https://<your-owncloud-server>/index.php/apps/web`.
## Prerequisites
- Running [ownCloud Classic server](https://owncloud.com/download-server/) with version 10.8
- Installed [oauth2 app](https://marketplace.owncloud.com/apps/oauth2)
- Command line access to your server
## Deploying ownCloud Web
Download the [ownCloud Web app](https://marketplace.owncloud.com/apps/web) from the marketplace and enable it:
```console
occ market:install web
```
## Configure oauth2
Within the `Admin` page of ownCloud Classic, head into `User Authentication` and add a new client with arbitrary name (e.g. `ownCloud Web`) and redirection URL `https://<your-owncloud-server>/index.php/apps/web/oidc-callback.html`.
{{< figure src="/clients/web/static/oauth2.png" alt="Example OAuth2 entry" >}}
{{< hint >}}
You can mark the ownCloud web client as `trusted` by clicking the respective checkbox so authorization after authentication gets omitted.
{{< /hint >}}
{{< hint >}}
If you use OpenID Connect you need to add a new client for ownCloud Web to your identity provider instead.
{{< /hint >}}
## Configure ownCloud Classic
### Set ownCloud Web address
To set the ownCloud Web address and to display ownCloud Web in the app switcher, add the following line into `config/config.php`:
```php
'web.baseUrl' => 'https://<your-owncloud-server>/index.php/apps/web',
```
### Configure link routing
Administrators can optionally decide whether ownCloud Links (public and private links) should be provided by the Classic web interface or by ownCloud Web using the `web.rewriteLinks` option in `config/config.php`. The option defaults to `false` so that the links open in the Classic web interface. Setting it to `true` will redirect all links to ownCloud Web. To redirect all private and public links to ownCloud Web, add the following line into `config/config.php`:
```php
'web.rewriteLinks' => true,
```
### Make ownCloud Web the default web interface
Administrators can optionally decide to make ownCloud Web the default web interface that users see after they log in to ownCloud. By default, the Classic web interface will be presented to users. To present ownCloud Web to users by default, add the following line into `config/config.php`:
```php
'defaultapp' => 'web',
```
{{< hint info >}}
While it is possible to make ownCloud Web the default web interface, the decision should be carefully evaluated. Features are still being added to ownCloud Web and users might need to use the Classic web interface to do certain actions.
{{< /hint >}}
## Configure ownCloud Web
There are a few config values which need to be set in order for ownCloud Web to work correctly. Please copy the example config below into `config/config.json` and adjust it for your environment:
```json
{
"server" : "https://<your-owncloud-server>",
"theme": "https://<your-owncloud-server>/index.php/apps/web/themes/owncloud/theme.json",
"auth": {
"clientId": "<client-id-from-oauth2>",
"url": "https://<your-owncloud-server>/index.php/apps/oauth2/api/v1/token",
"authUrl": "https://<your-owncloud-server>/index.php/apps/oauth2/authorize",
"logoutUrl": "https://<your-owncloud-server>/index.php/logout"
},
"apps" : [
"files",
"preview",
"search"
],
"applications" : [
{
"title": {
"en": "Classic Design",
"de": "Klassisches Design",
"fr": "Design classique",
"zh": "文件"
},
"icon": "swap-box",
"url": "https://<your-owncloud-server>/index.php/apps/files"
},
{
"icon": "settings-4",
"menu": "user",
"target": "_self",
"title": {
"de": "Einstellungen",
"en": "Settings"
},
"url": "https://<your-owncloud-server>/index.php/settings/personal"
}
]
}
```
{{< hint info >}}
If any issues arise when trying to access the new design, a good start for debugging it is to run your `config.json` file through a json validator of your choice.
{{< /hint >}}
|config parameter|explanation|
|---|---|
|server|ownCloud Classic server address|
|theme|Theme to be used in ownCloud Web pointing to a json file inside of `themes` folder|
|auth.clientId|Client ID received when adding ownCloud Web in the `User Authentication` section in `Admin`|
|apps|List of internal extensions to be loaded|
|applications|Additional apps and links to be displayed in the application switcher or in the user menu|
|applications[0].title|Visible title in the application switcher or user menu, localizable|
|applications[1].menu|Use `user` to move the menu item into the user menu. Defaults to app switcher|
{{< hint info >}}
It is important that you don't edit or place the `config.json` within the app folder. If you do, the integrity check of the app will fail and raise warnings.
{{< /hint >}}
{{< hint >}}
If you use OpenID Connect you need to replace the `"auth"` part with following configuration:
```json
"openIdConnect": {
"metadata_url": "<fqdn-of-the-identity-provider>/.well-known/openid-configuration",
"authority": "<fqdn-of-the-identity-provider>",
"client_id": "<client-id-from-the-identity-provider>",
"response_type": "code",
"scope": "openid profile email"
}
```
{{< /hint >}}
## Integrate ownCloud Classic features in ownCloud Web
### Add links to the app switcher
ownCloud Classic features that are not deeply integrated with the Classic UI (e.g., full screen apps) can be added to the ownCloud Web app switcher so that users can easily access them from ownCloud Web. You can use the following example and customize it according to your needs.
{{< hint info >}}
All apps that are listed in the ownCloud Classic app switcher will be added as links to the app switcher of the new ownCloud Web automatically. All of those links will open in a new browser tab on click.
{{< /hint >}}
To add new elements in the app switcher, paste the following into the `applications` section of `config.json`:
```json
{
"title": {
"en": "Custom Groups",
"de": "Benutzerdefinierte Gruppen"
},
"icon": "settings-4",
"url": "https://<your-owncloud-server>/settings/personal?sectionid=customgroups"
}
```
{{< hint info >}}
The URL in the example might need adaptations depending on the configuration of your ownCloud Classic. App switcher elements added this way will open the respective page in a new tab. This method can also be used to link external sites like Help pages or similar.
{{< /hint >}}
### Add links to the user menu
Just like adding links to the app switcher, you can also add links to the user menu.
```json
{
"icon": "settings-4",
"menu": "user",
"target": "_self",
"title": {
"de": "Hilfe",
"en": "Help"
},
"url": "https://help-link.example"
}
```
This will add a link to the specified URL in the user menu. This way, the link will open in the same tab. If you instead want to open it in a new tab, just remove the line `"target": "_self",`.
### ONLYOFFICE
For ONLYOFFICE there is a [native integration](https://github.com/ONLYOFFICE/onlyoffice-owncloud-web) available for ownCloud Web when it is used with ownCloud Classic. It fully integrates the ONLYOFFICE Document Editors and allows users to create and open documents right from ownCloud Web.
To be able to use ONLYOFFICE in ownCloud Web, it is required to run
- ownCloud Classic >= 10.8
- ownCloud Web >= 4.0.0
- [ONLYOFFICE Connector for ownCloud Classic](https://marketplace.owncloud.com/apps/onlyoffice) >= 7.1.1
Make sure that ONLYOFFICE works as expected in the Classic UI and add the following to `config.json` to make it available in ownCloud Web:
```json
"external_apps": [
{
"id": "onlyoffice",
"path": "https://<your-owncloud-server>/apps-external/onlyoffice/js/web/onlyoffice.js"
}
]
```
{{< hint info >}}
The URL in the example might need adaptations depending on the configuration of your ownCloud Classic.
{{< /hint >}}
### Collabora Online
For Collabora Online there is a native integration available for ownCloud Web when it is used with ownCloud Classic. It fully integrates the Collabora Online Document Editors and allows users to create and open documents right from ownCloud Web.
To be able to use Collabora Online in ownCloud Web, it is required to run
- ownCloud Classic >= 10.8
- ownCloud Web >= 4.0.0
- [Collabora Online Connector for ownCloud Classic](https://marketplace.owncloud.com/apps/richdocuments) >= 2.7.0
Make sure that Collabora Online works as expected in the Classic UI and add the following to `config.json` to make it available in ownCloud Web:
```json
"external_apps": [
{
"id": "richdocuments",
"path": "https://<your-owncloud-server>/apps/richdocuments/js/richdocuments.js"
}
]
```
{{< hint info >}}
The URL in the example might need adaptations depending on the configuration of your ownCloud Classic.
{{< /hint >}}
## Additional configuration for certain core apps
There is additional configuration available for certain core apps. You can find them listed below.
### Preview app
In case the backend has additional preview providers configured there is no mechanism, yet, to announce those to the `Preview` app in ownCloud Web. As an intermediate solution you can add the additional supported mimeTypes to the `Preview` app by following these steps:
1. Remove the `"preview"` string from the `"apps"` section in your `config.json` file
2. Add the following config to your `config.json` file:
```json
"external_apps": [
{
"id": "preview",
"path": "web-app-preview",
"config": {
"mimeTypes": ["image/tiff", "image/webp"]
}
}
]
```
If you already have an `"external_apps"` section, just add the preview app to the list. Please adjust the `"mimeTypes"` list according to your additional preview providers. See https://github.com/owncloud/files_mediaviewer#supporting-more-media-types for advise on how to add preview providers to the backend.
### Text-Editor app
The `text-editor` app provides a list of file extensions that the app is associated with, both for opening files and for creating new files.
By default, only `.txt` and `.md` files appear in the file creation menu and offer the text-editor as default app on a left mouse click
in the file list. For other file types the text-editor app only appears in the right mouse click context menu. In case you want to change this
default set of primary file extensions for the text-editor you can overwrite it as follows:
1. Remove the `"text-editor"` string from the `"apps"` section in your `config.json` file
2. Add the following config to your `config.json` file:
```json
"external_apps": [
{
"id": "text-editor",
"path": "web-app-text-editor",
"config": {
"primaryExtensions": ["txt", "yaml"]
}
}
]
```
With the above example config the text editor will offer creation of new files for `.txt` and `.yaml` files instead of `.txt` and `.md` files.
Also, a left mouse click on any `.txt` or `.yaml` file will open the respective file in the text-editor app. In this example, `.md` files would
not be opened in the text-editor by default anymore, but the text-editor will would appear in the context menu for the file as alternative app.
If you already have an `"external_apps"` section, just add the preview app to the list. Please adjust the `"mimeTypes"` list according to your additional preview providers. See https://github.com/owncloud/files_mediaviewer#supporting-more-media-types for advise on how to add preview providers to the backend.
{{< hint info >}}
The reason why the app needs to be ported from the `apps` section to the `external_apps` section is that only the `external_apps` support additional configuration. There are plans to change the configuration of apps to give you a coherent admin experience in that regard.
{{< /hint >}}
## Accessing ownCloud Web
After following all the steps, you should see a new entry in the application switcher called `New Design` which points to the ownCloud web.
{{< figure src="/clients/web/static/application-switcher-oc10.jpg" alt="ownCloud Classic application switcher" >}}

View File

@@ -0,0 +1,16 @@
---
title: 'Development'
date: 2022-01-28T00:00:00+00:00
weight: 50
geekdocRepo: https://github.com/owncloud/web
geekdocEditPath: edit/master/docs/development
geekdocFilePath: _index.md
geekdocCollapseSection: true
---
{{< toc >}}
This section is a guide about the development of ownCloud Web **core**, **apps** and **extensions**.
This includes **tooling**, **conventions** and the **repo structure**.
It is of interest for you if you want to contribute to ownCloud Web or develop your own apps and extensions.

View File

@@ -0,0 +1,63 @@
---
title: "Conventions"
date: 2022-01-28T00:00:00+00:00
weight: 20
geekdocRepo: https://github.com/owncloud/web
geekdocEditPath: edit/master/docs/development
geekdocFilePath: conventions.md
---
{{< toc >}}
This is a collection of tips and conventions to follow when working on the [ownCloud web frontend](https://github.com/owncloud/web).
Since it is a living document, please open a PR if you find something missing.
## Contributing to ownCloud Web
Everyone is invited to contribute. Simply fork the [codebase](https://github.com/owncloud/web/),
check the [issues](https://github.com/owncloud/web/issues?q=is%3Aopen+is%3Aissue+label%3ATopic%3Agood-first-issue)
for a suitable one and open a pull request!
### Linting and Tests
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.owncloud.com/owncloud/web) 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]({{< ref "../testing/_index.md" >}}).
### Changelog Items
In our project, we follow [SemVer](https://semver.org/) and keep a changelog for every change that influences the user experience (where
"users" can be admins, end-users and developers).
Some changes, like refactoring, updating dependencies, writing documentation or adding tests don't require a changelog item.
Please add a changelog item to the `changelog/unreleased/` folder, referencing the issue and pull request numbers, following
the [changelog item template](https://github.com/owncloud/web/blob/master/changelog/TEMPLATE).
## Code Conventions
### Early Returns
We're trying to stick with early returns in our code to make it more performant and simpler to reason about it.
### 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.
### 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.
### Vue 3 and Composition API
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
ownCloud Web repository.
### Dependencies
To keep the bundle size small and reduce the risk of introducing security problems for our users, we try to limit
the amount of dependencies in our code base and keep them as up-to-date as possible.

View File

@@ -0,0 +1,132 @@
---
title: 'Repo Structure and (Published) Packages'
date: 2022-01-28T00:00:00+00:00
weight: 30
geekdocRepo: https://github.com/owncloud/web
geekdocEditPath: edit/master/docs/development
geekdocFilePath: repo-structure.md
---
{{< toc >}}
## Repository Structure
From a developer's perspective, the most important parts of the [ownCloud Web repo](https://github.com/owncloud/web) are the following files and folders:
### dev Folder and docker-compose.yml File
The `/dev` folder contains all the configuration files that are needed in the `docker-compose.yml` file. This docker compose stack
contains all the backend and testing related infrastructure that is needed for an out-of-the-box usable localhost development setup,
as described in the [tooling section]({{< ref "tooling.md" >}}).
### docs Folder
Within the `/docs` folder you will find all the documentation source documents that get published to the [dev docs](https://owncloud.dev/clients/web/).
### packages Folder
We're using the [ownCloud Web repo](https://github.com/owncloud/web) as a mono repo. It contains a variety of packages. Some of them get
published to [npmjs.com](https://npmjs.com), others define the core packages, apps and extensions that are the foundation of
the `ownCloud Web` release artifact.
Having these packages side by side within the `/packages` folder of the repo is possible because of a `pnpm` feature called `Workspaces`. You can learn more about that by visiting the [pnpm docs](https://pnpm.io/workspaces).
### tests Folder
We're using the [Playwright](https://playwright.dev) for UI testing. The UI tests are located in the `/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]({{< ref "../testing/_index.md" >}})
### package.json File
This is probably no surprise: the root level `package.json` file defines the project information, build scripts, dependencies and some more details.
Each package in `/packages` can and most likely will contain another `package.json` which does the same for the respective package.
### vite.config.ts
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]({{< ref "tooling.md" >}}).
## (Published) Packages
Each package in the `/packages` folder can - not exclusively, but most commonly - consist of
- source code (`/src`),
- unit tests (`/tests`),
- translations (`/l10n`) and
- a `package.json` file for package specific details and dependencies.
### Code Style and Build Config
Some of our packages in `/packages` are pure helper packages which ensure a common code style and build configuration for all our
internal (mono repo) and external packages. We encourage you to make use of the very same packages. This helps the community
understand code more easily, even when coming from different developers or vendors in the ownCloud Web ecosystem.
Namely those packages are
- `/packages/babel-preset`
- `/packages/eslint-config`
- `/packages/extension-sdk`
- `/packages/prettier-config`
- `/packages/tsconfig/`
### ownCloud Design System
The ownCloud 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 ownCloud 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://owncloud.design).
The ownCloud 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 [@ownclouders/design-system](https://www.npmjs.com/package/@ownclouders/design-system)
as soon as possible. Since it's bundled with ownCloud Web, you should not bundle it with your app or extension.
### web-client
The client package (`/packages/web-client`) serves as an abstraction layer for the various ownCloud APIs, like
[LibreGraph](https://owncloud.dev/apis/http/graph/), [WebDAV](https://doc.owncloud.com/server/next/developer_manual/webdav_api/) and
[OCS](https://doc.owncloud.com/server/next/developer_manual/core/apis/ocs-capabilities.html). The package provides TypeScript
interfaces for various entities (like files, folders, shares and spaces) and makes sure that raw API responses are properly
transformed so that you can deal with more useful objects. The web-client package gets published
on npmjs.com as [@ownclouders/web-client](https://www.npmjs.com/package/@ownclouders/web-client).
Dedicated documentation for the `web-client` package is not available, yet, since our extension system is still work in progress. However, the package's [README.md](https://github.com/owncloud/web/blob/master/packages/web-client/README.md) gives you a few examples on how to use it.
### web-pkg
The web-pkg package (`/packages/web-pkg`) is a collection of opinionated components, composables, types and other helpers that aim
at making your app and extension developer experience as easy and seamless as possible. The web-pkg package gets published on
npmjs.com as [@ownclouders/web-pkg](https://www.npmjs.com/package/@ownclouders/web-pkg).
Dedicated documentation for the `web-pkg` package is not available, yet, since our extension system is still work in progress.
### web-runtime
At the very heart of ownCloud Web, the `web-runtime` is responsible for dependency injection, app bootstrapping, configuration,
authentication, data preloading and much more.
It is very likely that you will never get in touch with it as most of the developer-facing features are exposed via `web-pkg`. If you
have more questions about this package, please join our [public chat](https://matrix.to/#/#ocis:matrix.org) and simply ask
or write an issue in our [issue tracker](https://github.com/owncloud/web/issues).
### Standalone Core Apps
Both `web-app-admin-settings` and `web-app-files` are standalone apps which are bundled with the default ownCloud Web release artifact.
### 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 ownCloud 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://owncloud.dev/services/app-provider/)
(e.g. OnlyOffice, Collabora Online 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.
### Testing
Additional unit testing code lives in `test-helpers`.

View File

@@ -0,0 +1,52 @@
---
title: 'Tooling'
date: 2022-01-28T00:00:00+00:00
weight: 40
geekdocRepo: https://github.com/owncloud/web
geekdocEditPath: edit/master/docs/development
geekdocFilePath: tooling.md
---
{{< toc >}}
## 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.
## Development Setup
### Prerequisites
- docker
- docker-compose (if not already included in your docker installation)
- pnpm
- node
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.
### 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 ocis`.
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.
### 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.
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.
### Running Web with oC10
Older versions of Web (< 7.1.0) also support running oC10 as server. The development setup is nearly the same as mentioned above, the only differences are:
* The server can be started via `docker-compose up oc10`
* The server port is `8080` (`8081` when running Web via `pnpm vite:oc10`)

View File

@@ -0,0 +1,165 @@
---
title: 'Embed Mode'
date: 2023-10-23T00:00:00+00:00
weight: 60
geekdocRepo: https://github.com/owncloud/web
geekdocEditPath: edit/master/docs/embed-mode
geekdocFilePath: _index.md
geekdocCollapseSection: true
---
{{< toc >}}
The ownCloud 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://owncloud.dev/integration/file_picker/).
## Getting started
To integrate ownCloud Web into your application, add an iframe element pointing to your ownCloud Web deployed instance with additional query parameter `embed=true`.
```html
<iframe src="<web-url>?embed=true"></iframe>
```
## Communication
To establish seamless cross-origin communication between the embedded instance and the parent application, our approach involves emitting events using the `postMessage` method. These events can be conveniently captured by utilizing the standard `window.addEventListener('message', listener)` pattern.
### Target origin
By default, the `postMessage` method does not specify the `targetOrigin` parameter. However, it is recommended best practice to explicitly pass in the URI of the iframe origin (not the parent application). To enhance security, you can specify this value by modifying the config option `options.embed.messagesOrigin`.
### Events
To maintain uniformity and ease of handling, each event encapsulates the same structure within its payload: `{ name: string, data: any }`.
| Name | Data | Description |
| --- | --- | --- |
| **owncloud-embed:select** | Resource[] | Gets emitted when user selects resources or location via the select action |
| **owncloud-embed:share** | string[] | **DEPRECATED**: Gets emitted when user selects resources and shares them via the "Share links" action. Use `owncloud-embed:share-links` instead. |
| **owncloud-embed:share-links** | Array<{ url: string; password?: string }> | Gets emitted when user selects resources and shares them via the "Share link(s)" or "Share link(s) and password(s)" action. Each object contains the link URL and optionally the password (when shared with password). |
| **owncloud-embed:cancel** | null | Gets emitted when user attempts to close the embedded instance via "Cancel" action |
### Example
#### Selecting resources
```html
<iframe src="https://my-owncloud-web-instance?embed=true"></iframe>
<script>
function selectEventHandler(event) {
if (event.data?.name !== 'owncloud-embed:select') {
return
}
const resources = event.data.data
doSomethingWithSelectedResources(resources)
}
window.addEventListener('message', selectEventHandler)
</script>
```
#### Sharing links with password
```html
<iframe src="https://my-owncloud-web-instance?embed=true"></iframe>
<script>
function shareLinksEventHandler(event) {
if (event.data?.name !== 'owncloud-embed:share-links') {
return
}
const links = event.data.data // Array<{ url: string; password?: string }>
links.forEach(link => console.log("Link", link.url, "Password", link.password))
doSomethingWithSharedLinks(links)
}
window.addEventListener('message', shareLinksEventHandler)
</script>
```
## Location picker
By default, the Embed mode allows users to select resources. In certain cases (e.g. uploading a file), this needs to be changed to allow selecting a location. This can be achieved by running the embed mode with additional parameter `embed-target=location`. With this parameter, resource selection is disabled and the selected resources array always includes the current folder as the only item.
In special scenarios you also want the user to set a file name, this can be achieved by adding the `embed-choose-file-name=true` parameter, or if you also want to set a default file name, you can use `embed-choose-file-name-suggestion=my file.text`.
### Example
```html
<iframe src="https://my-owncloud-web-instance?embed=true&embed-target=location"></iframe>
<script>
function selectEventHandler(event) {
if (event.data?.name !== 'owncloud-embed:select') {
return
}
const resources = event.data.data[0]
doSomethingWithSelectedResources(resources)
}
window.addEventListener('message', selectEventHandler)
</script>
```
## File picker
The File Picker mode in ownCloud Web is designed for embedding an interface that allows users to pick a single file.
This mode can be configured to restrict the file types that users can select. To enable the File Picker mode, you need
to include the embed-target=file query parameter in the iframe URL. Furthermore, you can specify allowed file types
using the embed-file-types parameter. The file types can be specified using file extensions, MIME types, or a
combination of both. If the embed-file-types parameter is not provided, all file types will be selectable by default.
### Example
```html
<iframe src="https://my-owncloud-web-instance?embed=true&embed-target=file&embed-file-types=txt,image/png"></iframe>
<script>
function selectEventHandler(event) {
if (event.data?.name !== 'owncloud-embed:file-pick') {
return
}
const file = event.data.data
doSomethingWithPickedFile(file)
}
window.addEventListener('message', selectEventHandler)
</script>
```
## Delegate authentication
If you already have a valid `access_token` that can be used to call the API from within the Embed mode and do not want to force the user to authenticate again, you can delegate the authentication. Delegating authentication will disable internal login form in ownCloud Web and will instead use events to obtain the token and update it.
### Configuration
To allow authentication delegation, you need to set the config option `options.embed.delegateAuthentication` to `true`. This can be achieved via query parameter `embed-delegate-authentication=true`. Because we are using the `postMessage` method to communicate across different origins, it is best practice to verify that the event originated from a known origin and not from some malicious site. We highly recommend to allow this check in production environments. You can enable it by setting the config option `options.embed.delegateAuthenticationOrigin` via query parameter `embed-delegate-authentication-origin=my-origin`. The value of this parameter will be compared against the `MessageEvent.origin` value and if they do not match, the token will be rejected.
### Events
#### Opening Embed mode
As already mentioned, we're using the `postMessage` method to allow communication between the Embed mode and the parent application. When the Embed mode is opened for the first time, the user gets redirected to the `/web-oidc-callback` page where a message with payload `{ name: 'owncloud-embed:request-token', data: undefined }` is sent to request the `access_token` from the parent application. The parent application should set an event listener before opening the Embed mode and once received, it should send a message with payload `{ name: 'owncloud-embed:update-token', data: { access_token: '<bearer-token>' } }`. Once the Embed mode receives this message, it will save the token in the application state and will automatically authenticate the user.
{{< hint info >}}
When passing the token in the message payload, use only the token itself without `Bearer ` string as that will be added automatically in the Embed mode.
{{< /hint >}}
{{< hint info >}}
To save unnecessary duplication of messages with only different names, the name in the message payload above is exactly the same for both the initial authentication and subsequent token updates after renewal.
{{< /hint >}}
#### Updating the token
When authentication is delegated, the automatic renewal of the token inside of ownCloud Web is disabled. In order to update the token, a listener is created which awaits a message with payload `{ name: 'owncloud-embed:update-token', data: { access_token: '<bearer-token>' } }`. The token will then be replaced inside of the Embed mode automatically.

View File

@@ -0,0 +1,172 @@
---
title: 'Extension System'
date: 2024-01-23T00:00:00+00:00
weight: 60
geekdocRepo: https://github.com/owncloud/web
geekdocEditPath: edit/master/docs/extension-system
geekdocFilePath: _index.md
geekdocCollapseSection: true
---
{{< toc >}}
## Concepts and Building Blocks
ownCloud Web can be extended through various entry points with custom **apps** and **extensions**.
### Distinction between Apps and Extensions
An Application in the context of ownCloud Web is an artifact which can be installed in an ownCloud Infinite Scale instance.
It serves two main purposes:
1. It makes the full app viewport (everything below the top bar) available to the application developer for any custom
application code. This includes the ability to define views with routes, navigation items for the left sidebar, and more.
2. Through the `extensions` key in the application interface you can register extensions of any extension type. Those extensions
are then available in standardized extension points. Additionally, they can be queried from the extension registry for
your own purposes.
Both parts are optional. This means that an application can be a file editor without any custom extensions, or even contain
no custom application code at all and only host extensions to be registered in the extension registry, or a combination of both.
### Examples
You can find open source examples for apps and extensions in our [curated list of ownCloud apps and extensions](https://github.com/owncloud/awesome-ocis).
Feel free to contribute or just be inspired for your own apps or extensions.
### Apps
To get started, define a `src/index.ts`. Below is the most basic example of its content:
```typescript
// Install '@ownclouders/web-pkg' as a devDependency first (only relevant for types and autocompletion, dependency is already provided by ownCloud Web at runtime).
import {
AppWrapperRoute,
ApplicationFileExtension,
defineWebApplication
} from '@ownclouders/web-pkg'
export default defineWebApplication({
setup({ applicationConfig }) {
// Here, you have access to the full injection context, meaning you can use all composables that we provide via web-pkg
// Needs to be unique within all installed applications in any ownCloud web instance
// Should be short, unique and expressive as it is used as prefix on all routes within your application
const appId = 'your-extension'
// See extensions section below
const extensions = [
...
]
// See details below
const navItems = [
...
]
// See details below
const routes = [
...
]
return {
appInfo: {
name: $gettext('Your application name'),
id: appId,
icon: 'aliens', // See https://owncloud.design/#/Design%20Tokens/IconList for available options
},
extensions,
navItems,
routes
}
}
})
```
By defining an application via `defineWebApplication` you can provide the following:
- `appInfo` - the application metadata, which is used to make the application available via the app switcher and the app registry.
- `navItems` - the statically defined navigation items for the left sidebar. Only gets rendered when more than 1 navigation item exists at runtime.
Additional dynamic navigation items can be registered via the extension registry.
- `routes` - the routes to the different views of your application. May be referenced within the `navItems`. Authentication requirements can be defined per item.
- `extensions` - the extensions to be registered in the extension registry. For more details see the `Extensions` section below.
If you want to learn how to implement an app for viewing and editing specific file types, please consult the [relevant documentation]({{< ref "viewer-editor-apps.md" >}}) for detailed instructions and guidance.
To learn how to integrate an app into ownCloud Web, please refer to the "Web Apps" section of the Web service docs ("Services" > "Web").
### Extensions
In contrast to applications, extensions usually have a rather small scope and dedicated functionality.
#### Extension Registry
The globally available extension registry provided by the ownCloud Web runtime can be used to both register and query extensions. All extensions
which are being made available via an `app` get registered in the extension registry automatically. In your custom application code you can
then query any of the available extensions by providing an `extensionPoint` entity. Throughout the ownCloud Web platform
and most prominently also in the `files` app we have defined some extension points which automatically use certain extensions, see the
`Extension Points` section below.
#### Extension Types
For building an extension you can choose from the types predefined by the ownCloud Web extension system. See the full list of available extension types below.
1. `ActionExtension` (type `action`) - An extension that can register `Action` items which then get shown in various places (e.g. context menus, batch actions), depending on the
extension points referenced in the extension respectively. Most commonly used for file and folder actions (e.g. copy, rename, delete, etc.). For details, please refer to the [action docs]({{< ref "extension-types/actions.md" >}}).
2. `SearchExtension` (type `search`) - An extension that can register additional search providers. For details, please refer to the [search docs]({{< ref "extension-types/search.md" >}}).
3. `SidebarNavExtension` (type `sidebarNav`) - An extension that can register additional navigation items for the left sidebar. These can be scoped to specific apps, and programmatically enabled/disabled.
For details, please refer to the [sidebar nav docs]({{< ref "extension-types/left-sidebar-menu-item.md" >}}).
4. `SidebarPanelExtension`, (type `sidebarPanel`) - An extension that can register panels for the right sidebar. For details, please refer to the [sidebar panel docs]({{< ref "extension-types/right-sidebar-panels.md" >}}).
5. `FolderViewExtension` (type `folderView`) - An extension that can register additional ways of displaying the content of a folder (resources like spaces, folders or files) to the user.
For details, please refer to the [folder view docs]({{< ref "extension-types/folder-view.md" >}}).
6. `CustomComponentExtension` (type `customComponent`) - An extension that can register a custom component for a render target. For details, please refer to the
[custom component docs]({{< ref "extension-types/custom-components.md" >}})
You're free to introduce your own extension types within your application code and use the extension registry to query the available ones. However, if you have the impression
that an important extension type is missing and would be beneficial for the platform, please reach out to us by opening a [GitHub issue](https://github.com/owncloud/web/issues/new/choose).
#### Extension Base Configuration
Any extension is required to define at least an `id` and a `type` in order to fulfill the generic `Extension` interface.
The `id` is supposed to be unique throughout the ownCloud Web ecosystem. In order to keep `id`s readable for humans we didn't want to enforce uniqueness through e.g. uuids.
Instead, we chose to use dot-formatted namespaces like e.g. `com.github.owncloud.web.files.search`. We'd like to encourage you to follow the same format for your own extensions.
For the `type` you can choose from the ones listed above or define a custom one.
In addition, you can also pass optional `extensionPointIds` to further limit the usage of an extension. With the right click context menu and the batch actions being
two different extension points, this could mean that a file action extension is only allowed in the context menu, but not in the batch actions.
You can find predefined extension point ids in the extension points section below.
#### Extension Points
There are standardized components and places where extensions are being used automatically. The following ones are currently provided by the ownCloud Web runtime or
the `files` app. If you decide to develop an extension which fulfills the type and registers itself for the extensionPointId of the respective extension point,
your extension will be used automatically.
1. Left Sidebar for Navigation. ExtensionPointId `app.${appName}.navItems` (dynamically created for each app). Mounts extensions of type `sidebarNav`.
2. Global top bar
1. Center area. ExtensionPointId `app.runtime.header.center`. Mounts extensions of type `customComponent`.
2. Progress bar for the global loading state. ExtensionPointId `app.runtime.global-progress-bar`. Mounts a single extensions of type `customComponent`. If multiple exist, the user can choose via the account page.
3. Files app
1. Right sidebar. ExtensionPointId `app.files.sidebar`. Mounts extensions of type `sidebarPanel`. Used in any file(s) context (files app, file viewer apps, file editor apps).
2. Folder views for regular folders. ExtensionPointId `app.files.folder-views.folder`. Mounts extensions of type `folderView`.
3. Folder views for the project spaces overview. ExtensionPointId `app.files.folder-views.project-spaces`. Mounts extensions of type `folderView`.
4. Folder views for the favorites page. ExtensionPointId `app.files.folder-views.favorites`. Mounts extensions of type `folderView`.
5. Right click context menu. ExtensionPointId `global.files.context-actions`. Mounts extensions of type `action`.
6. Batch actions in the app bar above file lists. ExtensionPointId `global.files.batch-actions`. Mounts extensions of type `action`.
7. Default actions (left click) on a file. ExtensionPointId `global.files.default-actions`. Mounts extensions of type `action`.
8. Upload menu. ExtensionPointId `app.files.upload-menu`. Mounts extensions of type `action`.
9. Quick actions. ExtensionPointId `app.files.quick-actions`. Mounts extensions of type `action`.
4. Global search providers. ExtensionPointId `app.search.providers`. Utilizes extensions of type `search` as search engines for the search input in the global top bar.
#### User Preferences for Extensions
To allow users to configure extensions, extension points can define user preferences. User preferences are defined as an object on the extension point configuration.
Whenever an extension point declares to accept user preferences, it will get listed with a dropdown on the Preferences page (reachable via top right user menu).
The user can then select one out of all the extensions which have been registered for this extension point.
### Helpful packages
We currently offer the following packages that can be integrated into your app, providing useful utilities and types.
- `web-client` - This package serves as an abstraction layer between the server APIs and an app or extension. It converts raw API data into objects with helpful types and utilities. For details, please refer to the package's [README.md](https://github.com/owncloud/web/blob/master/packages/web-client/README.md).
- `web-pkg` - This package provides utilities, most importantly a variety of components and composables, that can be useful when developing apps and extensions. For details, please refer to the package's [README.md](https://github.com/owncloud/web/blob/master/packages/web-pkg/README.md).

View File

@@ -0,0 +1,12 @@
---
title: "Extension Types"
date: 2024-01-25T00:00:00+00:00
weight: 50
geekdocRepo: https://github.com/owncloud/web
geekdocEditPath: edit/master/docs/extension-system
geekdocFilePath: _index.md
geekdocCollapseSection: true
---
This section is a guide about the different predefined extension types of ownCloud Web. Please refer to the respective
subpages to learn more about the individual extension types.

View File

@@ -0,0 +1,96 @@
---
title: 'Action Extensions'
date: 2024-01-23T00:00:00+00:00
weight: 60
geekdocRepo: https://github.com/owncloud/web
geekdocEditPath: edit/master/docs/extension-system/extension-types
geekdocFilePath: actions.md
geekdocCollapseSection: true
---
{{< toc >}}
## 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.
### Configuration
This is what the `ActionExtension` interface looks like:
```typescript
interface ActionExtension {
id: string
type: 'action'
extensionPointIds?: string[]
action: Action // Please check the Action section below
}
```
For `id`, `type`, and `extensionPointIds`, please see [extension base section]({{< ref "../_index.md#extension-base-configuration" >}}) in top level docs.
#### Action
The most important configuration options are:
- `icon` - The icon to be displayed, can be picked from https://owncloud.design/#/Design%20Tokens/IconList
- `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.
- `href` - The URL to navigate to. The nav item will be a `<a>`tag.
- `handler` - The action to perform upon click. The nav item will be a `<button>` tag.
- `isVisible` - Determines whether the action is displayed to the user
Please check the [`Action` type](https://github.com/owncloud/web/blob/236c185540fc6758dc7bd84985c8834fa4145530/packages/web-pkg/src/composables/actions/types.ts#L6) for a full list of configuration options.
### Example
The following example shows how an action extension for downloading files could look like. Note that the extension is wrapped inside a Vue composable so it can easily be reused. All helper types and composables are being provided via the [web-pkg](https://github.com/owncloud/web/tree/master/packages/web-pkg) package.
```typescript
export const useDownloadFilesExtension = () => {
const { $gettext } = useGettext()
const extension = computed<ActionExtension>(() => ({
id: 'com.github.owncloud.web.files.download-action',
scopes: ['resource'],
type: 'action',
action: {
name: 'download-files',
icon: 'download',
class: 'oc-files-actions-download-files',
label: () => $gettext('Download'),
isVisible: ({ space, resources }) => {
if (resources.length === 0) {
return false
}
return true
},
handler: ({ space, resources }) => {
console.log('Triggering download...')
}
}
}))
return { extension }
}
```
The extension could then be registered in any app like so:
```typescript
export default defineWebApplication({
setup() {
const { extension } = useFileActionDownloadFiles()
return {
appInfo: {
name: $gettext('Download app'),
id: 'download-app'
},
extensions: computed(() => [unref(extension)])
}
}
})
```

View File

@@ -0,0 +1,79 @@
---
title: 'Application Menu Item Extensions'
date: 2024-07-23T00:00:00+00:00
weight: 60
geekdocRepo: https://github.com/owncloud/web
geekdocEditPath: edit/master/docs/extension-system/extension-types
geekdocFilePath: app-menu-items.md
geekdocCollapseSection: true
---
{{< toc >}}
## 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.
### Configuration
The Interface for an `AppMenuItemExtension` looks like so:
```typescript
interface AppMenuItemExtension {
id: string
type: 'appMenuItem'
extensionPointIds?: string[]
label: () => string
color?: string
handler?: () => void
icon?: string
path?: string
priority?: number
url?: string
}
```
For `id`, `type`, and `extensionPointIds`, please see [extension base section]({{< ref "../_index.md#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).
A `path` will result in an `<a>` element that links to an internal page via the vue router. That means the given path needs to exist within the application.
A `url` will result in an `<a>` element that links to an external page. External pages always open in a new tab or window.
At least one of these properties has to be provided when registering an extension. If you define more than one, the priority order is `handler` > `path` > `url`.
`priority` specifies the order of the menu items. 50 is a good number to start with, then go up/down based on where the item should be placed. Defaults to the highest possible number, so the item will most likely end up at the bottom of the list if you don't specify a `priority`. Leave it empty if unsure what to pick.
## Example
The following example shows how an app creates an extension that registers an app menu item, linking to an internal page. All helper types and composables are being provided via the [web-pkg](https://github.com/owncloud/web/tree/master/packages/web-pkg) package.
```typescript
export default defineWebApplication({
setup() {
const { $gettext } = useGettext()
const appId = 'my-cool-app'
const menuItems = computed<AppMenuItemExtension[]>(() => [
{
id: 'com.github.owncloud.web.my-cool-app.menu-item',
type: 'appMenuItem',
label: () => $gettext('My cool app'),
path: urlJoin(appId),
icon: 'star',
color: '#0D856F',
priority: 60
}
])
return {
appInfo: {
name: $gettext('My cool app'),
id: appId
},
extensions: menuItems
}
}
})
```

View File

@@ -0,0 +1,53 @@
---
title: 'Custom Component Extensions'
date: 2024-02-14T00:00:00+00:00
weight: 60
geekdocRepo: https://github.com/owncloud/web
geekdocEditPath: edit/master/docs/extension-system/extension-types
geekdocFilePath: custom-components.md
geekdocCollapseSection: true
---
{{< toc >}}
## Extension Type CustomComponent
CustomComponent extensions need to define one or multiple `extensionPointId`s as render target. A `CustomComponentTarget` component for this very
extension point needs to be mounted in the current view.
### Configuration
To define a custom component extension, you implement the `CustomComponentExtension` interface.
Here's what it looks like:
```typescript
interface CustomComponentExtension {
id: string
type: 'customComponent'
extensionPointIds?: string[]
content: Slot | Component
}
```
For `id`, `type`, and `extensionPointIds`, please see [extension base section]({{< ref "../_index.md#extension-base-configuration" >}}) in the top level docs.
The `content` property specifies a render function or a Component for the target extension point.
### Example
A simple example for a custom component extension could be a `NyanCat` progress bar component, being
targeted at the `global-progress-bar` extension point as render target.
```typescript
const extension = {
id: 'com.github.owncloud.web.app.progress-bars.nyan-cat',
type: 'customComponent',
extensionPointIds: ['app.runtime.global-progress-bar'],
content: (slots) => [h(NyanCat, slots)],
userPreference: {
optionLabel: $gettext('Nyan Cat progress bar')
}
}
```
The `content` property in this example can also be defined as `content: NyanCat`.

View File

@@ -0,0 +1,84 @@
---
title: 'Folder View Extensions'
date: 2024-01-23T00:00:00+00:00
weight: 60
geekdocRepo: https://github.com/owncloud/web
geekdocEditPath: edit/master/docs/extension-system/extension-types
geekdocFilePath: folder-view.md
geekdocCollapseSection: true
---
## Folder view extension type
The folder view is one of the possible extension types. Registered folder view can be used to render multiple resources (folders, files, spaces) in the UI.
### Configuration
This is what the FolderViewExtension interface looks like:
```typescript
interface FolderViewExtension {
id: string
type: 'folderView'
extensionPointIds?: string[]
folderView: FolderView // See FolderView section below
}
```
For `id`, `type`, and `extensionPointIds`, please see [extension base section]({{< ref "../_index.md#extension-base-configuration" >}}) in 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://owncloud.design/#/Design%20Tokens/IconList 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
### Example
The following example shows how an extension for a custom folder view could look like. Note that the extension is wrapped inside a Vue composable so it can easily be reused. All helper types and composables are being provided via the [web-pkg](https://github.com/owncloud/web/tree/master/packages/web-pkg) package.
```typescript
export const useCustomFolderViewExtension = () => {
const { $gettext } = useGettext()
const extension = computed<FolderViewExtension>(() => ({
id: 'com.github.owncloud.web.files.folder-view.custom',
type: 'folderView',
scopes: ['resource', 'space', 'favorite'],
folderView: {
name: 'custom-table',
label: $gettext('Switch to custom folder view'),
icon: {
name: 'menu-line',
fillType: 'none'
},
component: YourCustomFolderViewComponent
}
}))
return { extension }
}
```
The extension could then be registered in any app like so:
```typescript
export default defineWebApplication({
setup() {
const { extension } = useCustomFolderViewExtension()
return {
appInfo: {
name: $gettext('Custom folder view app'),
id: 'custom-folder-view-app'
},
extensions: computed(() => [unref(extension)])
}
}
})
```

View File

@@ -0,0 +1,98 @@
---
title: 'Left Sidebar Menu Item Extensions'
date: 2024-01-23T00:00:00+00:00
weight: 60
geekdocRepo: https://github.com/owncloud/web
geekdocEditPath: edit/master/docs/extension-system/extension-types
geekdocFilePath: left-sidebar-menu-item.md
geekdocCollapseSection: true
---
{{< toc >}}
## 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]({{< ref "../_index.md#extension-base-configuration" >}}) in top level docs.
#### AppNavigationItem
The most important configuration options are:
- `icon` - The icon to be displayed, can be picked from https://owncloud.design/#/Design%20Tokens/IconList
- `name` - The text to be displayed
- `route` - The string/route to navigate to, if the nav item should be a `<router-link>` (Mutually exclusive with `handler`)
- `handler` - The action to perform upon click, if the nav item should be a `<button>` (Mutually exclusive with `route`)
Please check the [`AppNavigationItem` type](https://github.com/owncloud/web/blob/f069ce44919cde5d112c68a519d433e015a4a011/packages/web-pkg/src/apps/types.ts#L14) for a full list of configuration options.
### Example
The following example shows an extension that adds a left sidebar nav item inside the files app, linking to a custom page. Note that the extension is wrapped inside a Vue composable so it can easily be reused. All helper types and composables are being provided via the [web-pkg](https://github.com/owncloud/web/tree/master/packages/web-pkg) package.
```typescript
export const useCustomPageExtension = () => {
const { $gettext } = useGettext()
const extension = computed<SidebarNavExtension>(() => ({
id: 'com.github.owncloud.web.files.left-nav.custom-page',
scopes: ['app.files'],
type: 'sidebarNav',
action: {
name: $gettext('Custom page'),
icon: 'world',
priority: 100,
isActive: () => true,
isVisible: () => true,
route: {
path: '/files/custom-page'
},
activeFor: [{ path: '/files/custom-page' }]
}
}))
return { extension }
}
```
The extension could then be registered in any app like so:
```typescript
export default defineWebApplication({
setup() {
const { extension } = useCustomPageExtension()
return {
appInfo: {
name: $gettext('Custom page app'),
id: 'custom-page-app'
},
routes: {
path: '/files/custom-page',
name: 'files-custom-page',
component: CustomPageComponent,
meta: {
title: $gettext('Custom Page')
}
},
extensions: computed(() => [unref(extension)])
}
}
})
```

View File

@@ -0,0 +1,136 @@
---
title: 'Right Sidebar Panel Extensions'
date: 2024-01-23T00:00:00+00:00
weight: 60
geekdocRepo: https://github.com/owncloud/web
geekdocEditPath: edit/master/docs/extension-system/extension-types
geekdocFilePath: right-sidebar-panels.md
geekdocCollapseSection: true
---
{{< toc >}}
## Extension Type SideBarPanel
The right sidebar is supposed to show information and make context specific actions available for single or multiple selected items.
It is structured in a hierarchical way:
- Panels which are defined as `root` panels get rendered as immediate members of the right sidebar.
- Panels which are defined as non-`root` panels receive a navigation item below the `root` panels so that users can navigate into the respective
sub panel.
### Configuration
To define a right sidebar panel extension, you implement the `SidebarPanelExtension` interface.
It can be found below:
```typescript
interface SidebarPanelExtension<R extends Item, P extends Item, T extends Item> {
id: string
type: 'sidebarPanel'
extensionPointIds?: string[]
panel: SideBarPanel<R, P, T> // Please check the SideBarPanel section below
}
```
For `id`, `type`, and `extensionPointIds`, please see [extension base section]({{< ref "../_index.md#extension-base-configuration" >}}) in the top level docs.
The `panel` object configures the actual sidebar panel. It consists of different properties and functions, where all the functions get called with a
`SideBarPanelContext` entity from the integrating extension points.
#### SideBarPanelContext
```typescript
interface SideBarPanelContext<R extends Item, P extends Item, T extends Item> {
root?: R
parent?: P
items?: T[]
}
```
- `items` - The most important member of the panel context, which denotes all selected items. That can mean all selected files in a files listing,
all selected users in a user listing, the individual current file in a file editor.
- `parent` - The immediate parent of the selected items. For example, if the user selects a file in a file listing, the parent is the parent folder,
or if being in a root of a space, the space itself. Can be `null` for non-hierarchical contexts, e.g. a user listing.
- `root` - The uppermost parent of the selected items. For example, if the user selects a file in a file listing, the root is always the space in which
the selected files reside. Can be `null` for non-hierarchical contexts, e.g. a user listing.
#### SideBarPanel
```typescript
interface SideBarPanel<R extends Item, P extends Item, T extends Item> {
name: string
icon: string
iconFillType?: IconFillType
title(context: SideBarPanelContext<R, P, T>): string
isVisible(context: SideBarPanelContext<R, P, T>): boolean
component: Component
componentAttrs?(context: SideBarPanelContext<R, P, T>): any
isRoot?(context: SideBarPanelContext<R, P, T>): boolean
}
```
- `name` - A human readable id for the panel.
- `icon`, `iconFillType` and `title` - Properties which are used to render the panel itself or right sidebar navigation items for navigating into that panel.
- `isVisible` - Determines if the panel is available for the given panel context.
- `component` - Provides a component that renders the actual sidebar panel.
- `componentAttrs` - Defines additional props for the component with the given panel context.
- `isRoot` - Determines if the panel is a root panel for the given panel context.
## Extension Point FileSideBar
In the context of files (e.g. file listing, text editor for a single file, etc.) we have a dedicated component `FileSideBar` which can be
toggled (shown/hidden) with a button in the top bar. The component queries all extensions of the type `sideBarPanel` from the extension
registry that also fulfill the scope `resource`. By registering an custom extension of type `sideBarPanel` and scope `resource`, your extension
will automatically become available in all environments that display the `FileSideBar` (i.e. any file viewer, file editor, file listing).
## Example
The following example shows how a sidebar panel for displaying exif data for a resource could look like. Note that the extension is wrapped inside a Vue composable so it can easily be reused. All helper types and composables are being provided via the [web-pkg](https://github.com/owncloud/web/tree/master/packages/web-pkg) and the [web-client](https://github.com/owncloud/web/tree/master/packages/web-client) packages.
```typescript
export const useExifDataPanelExtension = () => {
const { $gettext } = useGettext()
const extension = computed<SidebarPanelExtension<SpaceResource, Resource, Resource>>(() => ({
id: 'com.github.owncloud.web.files.sidebar-panel.exif-data',
type: 'sidebarPanel',
scopes: ['resource'],
panel: {
name: 'exif-data',
icon: 'image',
title: () => $gettext('EXIF data'),
component: ExifDataPanelComponent,
isRoot: () => true,
isVisible: ({ items }) => {
if (items?.length !== 1) {
return false
}
return true
}
}
}))
return { extension }
}
```
The extension can then be registered in any app like so:
```typescript
export default defineWebApplication({
setup() {
const { extension } = useExifDataPanelExtension()
return {
appInfo: {
name: $gettext('Exif panel app'),
id: 'exif-panel-app'
},
extensions: computed(() => [unref(extension)])
}
}
})
```

View File

@@ -0,0 +1,141 @@
---
title: 'Search Extensions'
date: 2024-01-23T00:00:00+00:00
weight: 60
geekdocRepo: https://github.com/owncloud/web
geekdocEditPath: edit/master/docs/extension-system/extension-types
geekdocFilePath: search.md
geekdocCollapseSection: true
---
{{< toc >}}
## Search extensions
One possible extension type is search. Registered search extensions are available when using the search field in the topbar. A search extension can consist of a
`list` and a `preview` search. The result of a `preview` search is shown below the search input field while the `list` search result is
### Configuration
An example of a search extension configuration can be found below:
```typescript
interface SearchExtension {
id: string
type: 'search'
extensionPointIds?: string[]
searchProvider: {
id: string
available: boolean
displayName?: string
previewSearch?: SearchPreview // See SearchPreview section below
listSearch?: SearchList // See SearchList section below
}
}
```
For `id`, `type`, and `extensionPointIds`, please see [extension base section]({{< ref "../_index.md#extension-base-configuration" >}}) in top level docs.
The `searchProvider` object configures the actual provider. It consist of the following:
- `id` - Since your extension has an `id` and can only have one searchProvider, you can reuse the same value
- `available` - Can be used to programmatically disable/enable any searchProvider, e.g. by dynamically checking backend capabilities
- `displayName` - Optional, used to add a small hint to indicate the connection between search providers and their corresponding results
- `previewSearch` - See below
- `listSearch` - See below
#### ListSearch
The listSearch object consists of:
- `component` - Vue component that can render the values from the SearchResult below
- `search(term: string)` - Function that exectues the search, based on a given term. The term is formatted in [KQL](https://owncloud.dev/services/search/#query-language). Please note that the returned values needs to be formatted to fit either `SearchResource` or `GenericSearchResultItem` type
#### PreviewSearch
The previewSearch object extends the listSearch with one additional attribute:
- `available` - Indicates whether a preview underneath the search bar is available for this search provider
## Example
The following example shows how a search extension that queries a Solr search engine could look like. Note that the extension is wrapped inside a Vue composable so it can easily be reused. All helper types and composables are being provided via the [web-pkg](https://github.com/owncloud/web/tree/master/packages/web-pkg) and the [web-client](https://github.com/owncloud/web/tree/master/packages/web-client) packages.
```typescript
export const useSolrSearchExtension = () => {
const { $gettext } = useGettext()
const previewSearch: SearchPreview = {
component: SolarSearchComponent, // see the next example snippet
available: () => true,
search: (term) => {
// actual search implementation
console.log('Querying solr search engine...')
}
}
const searchProvider: SearchProvider = {
id: 'solr-search',
available: true,
displayName: 'Solr Search',
previewSearch
}
const extension = computed<SearchExtension>(() => ({
id: 'com.github.owncloud.web.solr-search',
type: 'search',
searchProvider
}))
return { extension }
}
```
The search component for the preview search container may look like this:
```Vue
<template>
<resource-list-item :resource="resource" />
</template>
<script lang="ts">
import { computed, defineComponent, PropType } from 'vue'
import { Resource } from '@ownclouders/web-client'
import { SearchResultValue, ResourceListItem } from '@ownclouders/web-pkg'
export default defineComponent({
name: 'SolarSearchComponent',
components: { ResourceListItem },
props: {
searchResult: {
type: Object as PropType<SearchResultValue>,
default: () => ({})
}
},
setup(props) {
const resource = computed<Resource>(() => props.searchResult.data)
return { resource }
}
})
</script>
```
The extension can then be registered in any app like so:
```typescript
export default defineWebApplication({
setup() {
const { extension } = useSolrSearchExtension()
return {
appInfo: {
name: $gettext('Solr search app'),
id: 'solrs-search-app'
},
extensions: computed(() => [unref(extension)])
}
}
})
```

View File

@@ -0,0 +1,128 @@
---
title: 'Viewer and Editor Apps'
date: 2024-03-12T00:00:00+00:00
weight: 60
geekdocRepo: https://github.com/owncloud/web
geekdocEditPath: edit/master/docs/extension-system
geekdocFilePath: viewer-editor-apps.md
geekdocCollapseSection: true
---
{{< toc >}}
## Viewer and editor apps
ownCloud Web allows developers to implement apps for viewing and editing specific file types. For instance, the built-in preview app serves as the default application for opening media files like images, videos, or audio.
This section will guide you through the process of implementing such an app within ownCloud Web.
### Basic app structure
An app is essentially a distinct package that must be specified as an external application in the Web configuration.
The structure of an app is quite simple and straightforward. Consider, for example, the [pdf-viewer app](https://github.com/owncloud/web/tree/master/packages/web-app-pdf-viewer). It consists of a `package.json` file, a `src` directory containing all the source code, and a `l10n` directory for translations. Optionally, you may also include a `tests` directory if your application requires testing.
To learn more about apps in general, please refer to the [Web app docs]({{< ref "_index.md#apps" >}}).
### App setup
Inside the `src` folder you will need an `index.ts` file that sets up the app so it can be registered by the Web runtime. It follows the basic structure as described in [the apps section]({{< ref "_index.md#apps" >}}), so it may look like this:
```typescript
import { AppWrapperRoute, defineWebApplication, AppMenuItemExtension } from '@ownclouders/web-pkg'
import translations from '../l10n/translations.json'
import { useGettext } from 'vue3-gettext'
import { computed } from 'vue'
// This is the base component of your app.
import App from './App.vue'
export default defineWebApplication({
setup() {
// The ID of your app.
const appId = 'advanced-pdf-viewer'
const { $gettext } = useGettext()
// This creates a route under which your app can be opened.
// Later, this route will be bound to one or more file extensions.
const routes = [
{
name: 'advanced-pdf-viewer',
path: '/:driveAliasAndItem(.*)?',
component: AppWrapperRoute(App, {
applicationId: appId
}),
meta: {
authContext: 'hybrid',
title: $gettext('Advanced PDF Viewer'),
patchCleanPath: true
}
}
]
// if you want your app to be present in the app menu on the top left.
const menuItems = computed<AppMenuItemExtension[]>(() => [
{
label: () => $gettext('Advanced PDF Viewer'),
type: 'appMenuItem',
handler: () => {
// do stuff...
}
}
])
return {
appInfo: {
name: 'Advanced PDF Viewer',
id: appId,
defaultExtension: 'pdf',
extensions: [
// This makes sure all files with the "pdf" extension will be routed to your app when being opened.
// See the `ApplicationFileExtension` interface down below for a list of all possible properties.
{
extension: 'pdf',
routeName: 'advanced-pdf-viewer',
// Add this if you want your app to be present in the "New" file menu.
newFileMenu: {
menuTitle() {
return $gettext('PDF document')
}
}
}
]
},
routes,
translations,
extensions: menuItems
}
}
})
```
Here is the interface defining the `extensions` property of the `appInfo` object.
```typescript
interface ApplicationFileExtension {
app?: string
extension?: string
createFileHandler?: (arg: {
fileName: string
space: SpaceResource
currentFolder: Resource
}) => Promise<Resource>
hasPriority?: boolean
label?: string
name?: string
icon?: string
mimeType?: string
newFileMenu?: { menuTitle: () => string }
routeName?: string
customHandler? (
fileActionOptions: FileActionOptions,
extension: string,
appFileExtension: ApplicationFileExtension
) => Promise<void> | void
}
```

110
web/docs/getting-started.md Normal file
View File

@@ -0,0 +1,110 @@
---
title: 'Getting Started'
date: 2018-05-02T00:00:00+00:00
weight: 10
geekdocRepo: https://github.com/owncloud/web
geekdocEditPath: edit/master/docs
geekdocFilePath: getting-started.md
---
{{< toc >}}
## Source Code
The source code is hosted at [https://github.com/owncloud/web](https://github.com/owncloud/web).
Please refer to the [build documentation for Web]({{< ref "./building.md" >}}).
## Installation
Make sure to have Docker, Docker-Compose, [Node.js](https://nodejs.org/en/download) and [pnpm](https://pnpm.io/installation) installed.
If you plan to work with translations, you also need to install the [Transifex Client](https://developers.transifex.com/docs/cli). Note when installing the Transifex Client, change to your `~/.local/bin` directory first because it installs at the current location.
{{< hint info >}}
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 [his changes](https://github.com/egoist/rollup-plugin-postcss/pull/384) and build them locally if you absolutely want to work on Windows.
</details>
{{< /hint >}}
After cloning the [source code](https://github.com/owncloud/web), install the dependencies via `pnpm install` and bundle the frontend code by running `pnpm build:w`.
### Docker
Then, you can start the server by running `docker-compose up ocis` and access it via [https://host.docker.internal:9200](https://host.docker.internal:9200). 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 the `host.docker.internal` links work.
The bundled frontend code automatically gets mounted into the Docker containers, recompiles on changes and you can log in using the demo user (admin/admin) and take a look around!
For more details on how to set up Web for development, please see [tooling]({{< ref "tooling.md#development-setup" >}}).
## Configuration
Depending on the backend you are using, there are sample config files provided in the [config folder](https://github.com/owncloud/web/tree/master/config) of the ownCloud Web git repository. See below for available backends. Also, find some of the configuration details below.
- `customTranslations` You can specify one or multiple files to overwrite existing translations. For example set this option to `[{url: "https://localhost:9200/customTranslations.json"}]`.
#### Options
- `options.accountEditLink` This accepts an object with the following optional fields to have a link on the account page:
- `options.accountEditLink.href` Set a different target URL for the edit link. Make sure to prepend it with `http(s)://`.
- `options.disableFeedbackLink` Set this option to `true` to disable the feedback link in the topbar. Keeping it enabled (value `false` or absence of the option)
allows ownCloud to get feedback from your user base through a dedicated survey website.
- `options.feedbackLink` This accepts an object with the following optional fields to customize the feedback link in the topbar:
- `options.feedbackLink.href` Set a different target URL for the feedback link. Make sure to prepend it with `http(s)://`. Defaults to `https://owncloud.com/web-design-feedback`.
- `options.feedbackLink.ariaLabel` Since the link only has an icon, you can set an e.g. screen reader accessible label. Defaults to `ownCloud feedback survey`.
- `options.feedbackLink.description` Provide any description you want to see as tooltip and as accessible description. Defaults to `Provide your feedback: We'd like to improve the web design and would be happy to hear your feedback. Thank you! Your ownCloud team.`
- `options.sharingRecipientsPerPage` Sets the amount of users shown as recipients in the dropdown when sharing resources. Default amount is 200.
- `options.runningOnEos` Set this option to `true` if running on an [EOS storage backend](https://eos-web.web.cern.ch/eos-web/) to enable its specific features. Defaults to `false`, and we recommend reaching out to [the ownCloud web team](https://matrix.to/#/#ocis:matrix.org) if you're not CERN and thinking about enabling this feature flag.
- `options.cernFeatures` Enabling this will activate CERN-specific features. Defaults to `false`.
- `options.editor.autosaveEnabled` Specifies if the autosave for the editor apps is enabled.
- `options.editor.autosaveInterval` Specifies the time interval for the autosave of editor apps in seconds.
- `options.editor.openAsPreview` Specifies if non-personal files i.e. files in shares, spaces or public links are being opened in read only mode so the user needs to manually switch to edit mode. Can be set to `true`, `false` or an array of web app/editor names.
- `options.contextHelpersReadMore` Specifies whether the "Read more" link should be displayed or not.
- `options.tokenStorageLocal` Specifies whether the access token will be stored in the local storage when set to `true` or in the session storage when set to `false`. If stored in the local storage, login state will be persisted across multiple browser tabs, means no additional logins are required. Defaults to `true`.
- `options.loginUrl` Specifies the target URL to the login page. This is helpful when an external IdP is used. This option is disabled by default. Example URL like: 'https://www.myidp.com/login'.
- `options.logoutUrl` Adds a link to the user's profile page to point him to an external page, where he can manage his session and devices. This is helpful when an external IdP is used. This option is disabled by default.
- `options.userListRequiresFilter` Defines whether one or more filters must be set in order to list users in the Web admin settings. Set this option to 'true' if running in an environment with a lot of users and listing all users could slow down performance. Defaults to `false`.
- `options.concurrentRequests` This accepts an object with the following optional fields to customize the maximum number of concurrent requests in code paths where we limit concurrent requests
- `resourceBatchActions` Concurrent number of file/folder/space batch actions like e.g. accepting shares. Defaults to 4.
- `sse` Concurrent number of SSE event handlers. Defaults to 4.
- `shares` Accepts an object regarding the following sharing related options:
- `create` Concurrent number of share invites. Defaults to 4.
- `list` Concurrent number of individually loaded shares. Defaults to 2.
#### Scripts and Styles
Web supports adding additional CSS and JavaScript files to further customize the user experience and adapt it to your specific needs. Please consider opening a feature request if you feel like your customization could be a benefit to the upstream project, and keep an eye open for future major releases of `web` since this API may change.
- `styles` expects an array of objects that specify a `href` attribute, pointing to the path/URL of your stylesheet, like `[{ "href": "css/custom.css" }]`.
- `scripts` expects an array of objects that specify a `src` attribute, pointing to the path/URL of your script, and an optional `async` attribute (defaults to false), like `[{ "src": "js/custom.js", "async": true }]`.
### Sentry
Web supports [Sentry](https://sentry.io/welcome/) to provide monitoring and error tracking.
To enable sending data to a Sentry instance, you can use the following configuration keys:
- `sentry.dsn` Should contain the DSN for your sentry project.
- `sentry.environment`: Lets you specify the environment to use in Sentry. Defaults to `production`.
Any other key under `sentry` will be forwarded to the Sentry initialization. You can find out more
settings in the [Sentry docs](https://docs.sentry.io/platforms/javascript/configuration/).
{{< hint info >}}
If you are using an old version of Sentry (9 and before), you might want to add the setting `sentry.autoSessionTracking: false` to avoid errors related to breaking changes introduced in the
integration libraries.
{{< /hint >}}
## Setting up backend and running
Newer versions of Web (> 7.0.2) can only run against [oCIS](https://github.com/owncloud/ocis), whereas older versions (< 7.1.0) can run against [ownCloud Classic](https://github.com/owncloud/core/) as well.
Depending which one you chose, please check the matching section:
- [Setting up with oCIS as backend]({{< ref "backend-ocis.md" >}})
- [Setting up with ownCloud as backend]({{< ref "backend-oc10.md" >}})
## Running
- [Running with oCIS as backend]({{< ref "backend-ocis.md#running-web" >}})
- [Running with ownCloud as backend]({{< ref "backend-oc10.md#running-web" >}})

View File

@@ -0,0 +1,13 @@
---
title: 'Releasing'
date: 2025-06-16T00:00:00+00:00
weight: 50
geekdocRepo: https://github.com/owncloud/web
geekdocEditPath: edit/master/docs/releasing
geekdocFilePath: _index.md
geekdocCollapseSection: true
---
{{< toc >}}
This section serves as a guide for releasing ownCloud Web and managing important deprecations for a release.

View File

@@ -0,0 +1,46 @@
---
title: 'Deprecations and Migrations'
date: 2025-06-11T00:00:00+00:00
weight: 70
geekdocRepo: https://github.com/owncloud/web
geekdocEditPath: edit/master/docs/deprecations
geekdocFilePath: deprecations.md
geekdocCollapseSection: true
---
This guide tracks deprecations, planned removals, and migration paths for ownCloud Web. Developers should reference this guide when upgrading between major versions to ensure compatibility and adopt recommended practices.
{{< toc >}}
## Upcoming Deprecations
The following features are deprecated and **will be removed** in the next major version.
| Component/Feature | Deprecated | Migration | Reference | Reasoning |
|---|---|---|---|---|---|
| `owncloud-embed:share` event | November 12, 2025 | Use `owncloud-embed:share-links` event instead | [PR #13296](https://github.com/owncloud/web/pull/13296) | New event provides structured data with both URL and optional password |
## Migration History
The following features **are already removed**.
| Component/Feature | Removed in Version | Deprecated | Migration | Reference | Reasoning |
|---|---|---|---|---|---|
| `CollapsibleOcTable` component | v12 | May 16, 2025 | Use `OcTable` instead | [PR #12567](https://github.com/owncloud/web/pull/12567) | No longer needed by original implementers |
| `ocsUserContext` and `ocsPublicLinkContext` of `ClientService` | v12 | September 26, 2024 | Use `ocs` instead | [PR #11656](https://github.com/owncloud/web/pull/11656) | These methods were only a wrapper around the `ocs` |
| Web Client initialisation | v12 | September 26, 2024 | Use `graph()`, `ocs()` and `webdav()` to initialize and use clients | [PR #11656](https://github.com/owncloud/web/pull/11656) | More transparency to developers |
| `type` prop of `ApplicationInformation` | v12 | July 26, 2024 | N/A | [Commit 5e8ac91](https://github.com/owncloud/web/commit/5e8ac918de780f0b03ad79a85b8c25e4ba1fe4df) | The `type` prop is not used anymore |
| `isFileEditor` prop of `ApplicationInformation` | v12 | July 26, 2024 | N/A | [Commit 67ce21c](https://github.com/owncloud/web/commit/67ce21ce1bcc449d18f53e4930d180198a19faa0) | The `isFileEditor` prop is not used anymore |
| `ApplicationMenuItem` and `applicationMenu` prop of `ApplicationInformation` | v12 | July 24, 2024 | Register app menu items via the `appMenuExtensionPoint` instead | [PR #11258](https://github.com/owncloud/web/pull/11258) | Transitioning to the new extension points system |
| `ApplicationQuickAction` | v12 | December 1, 2023 | Register quick actions as extension instead | [PR #10102](https://github.com/owncloud/web/pull/10102) | Transitioning to the new extension points system |
| Vuex Store | v9 | January 22, 2024 | Migrate to Pinia stores | [PR #10372](https://github.com/owncloud/web/pull/10372) | Better TypeScript support and Composition API integration |
| Home Folder Option | v9 | January 5, 2024 | Use spaces functionality | [PR #10122](https://github.com/owncloud/web/pull/10122) | No longer needed by original implementers |
| OCS User API | v9 | January 3, 2024 | Use Graph user from `@ownclouders/web-client/src/helpers` and `useUserStore` | [PR #10240](https://github.com/owncloud/web/pull/10240) | The OCS API is deprecated and we're slowly transitioning to the Graph API and we want to get rid of the vuex store |
| Vuex Modal Implementation | v9 | December 22, 2023 | Use `useModals()` composable | [PR #10212](https://github.com/owncloud/web/pull/10212) | Remove Vuex store dependency |
| App: `user-management` | v8 | January 4, 2023 | Use the name `admin-settings` when referencing the app (in your configs for example) | [PR #8175](https://github.com/owncloud/web/pull/8175) | The app is supposed to hold a variety of general settings in the future, not just user-related settings |
| `mediaSource` helper & `v-image-source` directive | v6 | July 27, 2022 | Use `loadPreview` from web-pkg | N/A | `loadPreview` is the new default mechanism. We want to get rid of magical everywhere-available helpers |
| `getToken` getter | v6 | July 7, 2022 | Use `runtime/auth/accessToken` getter | N/A | `user` state is not supposed to deal with authentication details. We introduced the namespaced `auth` module for `user` and `public-link` related authentication contexts |
## Getting Help
For questions about specific migrations, refer to the linked pull requests and commits for detailed implementation examples and discussion.

View File

@@ -0,0 +1,19 @@
---
title: 'Releasing'
weight: 25
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/web/docs
geekdocFilePath: releasing.md
---
{{< toc >}}
## Releasing
ownCloud Web no longer has a standalone release process. Its source lives in-tree under
`web/` in the [ocis repository](https://github.com/owncloud/ocis) and is built and released
as part of oCIS itself. See [oCIS Web service / Releasing](/services/web/releasing) for the
current process.
The final standalone release of ownCloud Web was `v12.5.0` (also tagged `last-agpl-release`),
after which the [owncloud/web](https://github.com/owncloud/web) repository was archived.

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

BIN
web/docs/static/oauth2.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

@@ -0,0 +1,11 @@
---
title: "Tests"
date: 2022-01-28T00:00:00+00:00
weight: 55
geekdocRepo: https://github.com/owncloud/web
geekdocEditPath: edit/master/docs/testing
geekdocFilePath: _index.md
geekdocCollapseSection: true
---
Guides on running different kinds of tests in ownCloud Web.

View File

@@ -0,0 +1,48 @@
---
title: 'Accessibility'
date: 2025-11-10T00:00:00+00:00
weight: 60
geekdocRepo: https://github.com/owncloud/web
geekdocEditPath: edit/master/docs/testing
geekdocFilePath: accessibility.md
---
{{< toc >}}
## Introduction
Accessibility is a crucial aspect of web development. It ensures that web applications are usable by everyone, including people with disabilities.
## What Tools We Use
### eslint-plugin-vuejs-accessibility
We use [eslint-plugin-vuejs-accessibility](https://github.com/vue-a11y/eslint-plugin-vuejs-accessibility) to quickly catch accessibility issues in the codebase. This plugin is used in the [@ownclouders/eslint-config](https://www.npmjs.com/package/@ownclouders/eslint-config).
### @axe-core/playwright
We use [@axe-core/playwright](https://github.com/dequelabs/axe-core-npm) to automatically test the accessibility of the ownCloud Web client. All tests are run automatically on every PR and on commits to the `master` branch. We are not running dedicated accessibility tests and instead make them part of the E2E tests. This way we do not have to maintain duplicate tests and we can granularly add accessibility tests to the specific steps of the tests. The tests are considered failed if any `serious` or `critical` accessibility violations are found.
#### Running Accessibility Tests
To run the accessibility tests, you can simply run our existing E2E tests using the following command:
```bash
pnpm test:e2e:playwright
```
#### Skipping Accessibility Tests Locally
If you want to skip the accessibility tests, you can add the `SKIP_A11Y_TESTS` environment variable to your command.
```bash
SKIP_A11Y_TESTS=true pnpm test:e2e:playwright
```
#### Skipping Accessibility Tests in CI
If you want to skip the accessibility tests in CI, you can add the `[skip-a11y]` flag into the title of the PR.
#### Accessibility Report
After the tests are run, a JSON accessibility report is generated in the `reports/e2e/a11y-report.json` file. This report contains detailed information about the accessibility violations found in the tests.

View File

@@ -0,0 +1,266 @@
---
title: 'End-to-End (E2E) Test Standards'
date: 2024-09-11T00:00:00+00:00
weight: 60
geekdocRepo: https://github.com/owncloud/web
geekdocEditPath: edit/master/docs/testing
geekdocFilePath: e2e-testing-standards.md
---
{{< toc >}}
## Introduction
In ownCloud, we use Playwright for webUI test automation. We benefit from lower barriers to entry, readability, and usability when test standards are consistent across repositories. For example:
- **Reusability:** Enhances reusability by making it easier to reuse functions, locators, shared steps, and other test code. Finding the necessary components and functionalities will be simple for someone working on a test resulting in reduced duplication and the requirement for rework after the initiation of a code review.
- **Facilitates reviews:** Code can be examined more quickly. Since you can quickly determine what the test code is doing, it eases the mental strain of code review.
- **Faster onboarding:** By following naming conventions, new contributors are onboarded more rapidly and feel comfortable enough to contribute to the codebase.
Here are the test standards and guidelines we adhere to when creating Playwright tests at ownCloud.
## Folder Structure:
- `tests/:`
- `e2e/`: Main folder containing all (end-to-end) E2E test-related files.
- `specs/`: Main folder containing all test-related files.
- `<test-suite-folder>/`: Collection house for "**related"** spec files.
- `<aSpecFile>.spec.ts`: A spec file.
- `steps/`: Holds the files that defines actions of user.
- `hooks/`: Test hooks for setting up and tearing down test environments.
- `hooks.ts`: Contains `Before`, `After`, and other lifecycle hooks.
- `support/`: Playwright (Test implementation)
- `api/`: Contains API-related test files and configurations.
- `<api-folder>/ `: Specific API tests for a particular service.
- `objects/`: Contains the Page Object classes.
- `<specific-page-object-folder>/`: Collection house for related page objects for each webpage or component.
- `<individualPageObject>.ts`: Page Object for each webpage or component.
- `utils/`: Utility functions and common helpers.
- `helpers.ts`: Common utility functions (e.g., date formatting, data generation).
- `test-data/`: Static test data files or folders for upload.
- `filesForUpload/`: Static test data files for upload.
- `config/`: Configuration files for Playwright and other tools.
- `playwright.config.ts`: Playwright configuration.
- `reports/`: Generated test reports (e.g., HTML, JSON).
- `screenshots/`: Captured screenshots during test execution.
- `videos/`: Recorded videos of test runs.
## Test Structure - Arrange, Act, Assert:
We can follow the AAA (Arrange, Act, Assert) pattern when structuring the tests. In most cases, the Arrange step can be included in a Before block(hook).
Consider including comments defining each section to ease readability.
```typescript
// arrange, set up the initial conditions for the test
// create a property
await createProperty()
// act, perform the action that you want to test
// raise a charge
// this could involve calling methods or functions defined in your page objects
await raiseCharge()
// assert, verify that the action had the expected outcome
// confirm charge has been raised
expect(charge).toBe('raised')
```
## Page Object Model (POM)
Every page should possess one POM file to enhance maintainability and scalability of our tests. It should include all the selectors and functions which are needed to interact with the UI page or component(s).
All interactions should be done using the page objects, no selectors in your tests.
All assertions should be in your test, no assertion in the POM
DO 👍
```typescript
// POM file './pageOobjects/foo/'
// add all locators and functions related to the page.
// allowing all tests to reuse
import {expect, Locator, Page} from '@playwright/test';
export class FooPage {
readonly errorMessage: Locator;
constructor(page: Page) {
this.page = page;
this.errorMessage = page.locator('.error-message');
}
}
// test file './steps/foo.ts'
import {FooPage} from './pageObjects/foo';
let fooPage: FooPage;
await errorMessageShouldBeVisible({page}) {
const fooPage = new FooPage({page});
await expect(fooPage.errorMessage).toBeVisible();
}
```
DO NOT ⚔️
```typescript
// test file './steps/foo.ts'
// include locators directly in test
import { Locator, Page } from '@playwright/test';
await errorMessageShouldBeVisible({page}) {
await expect(page.locator('.error-message')).toBeVisible();
}
```
## Waiting:
Playwright uses auto-waiting, so we avoid artificial waiting, the exception being if it is really necessary.
DO NOT ⚔️
```typescript
await page.waitForTimeout(5000)
```
This can cause flaky tests as we can rarely be certain the amount of wait time is enough. It can also unnecessarily increase the test run time. Instead, we can try:
DO 👍
```typescript
await page.goto(fooBarURL, {
waitUntil: 'domcontentloaded'
});
```
DO 👍
```typescript
const element = page.locator("some-locator-path");
element.waitFor({ visible: true });
```
DO 👍
```typescript
await fooPage.buttonFoo.click();
await expect(fooPage.titlePage).toBeVisible();
```
## Selectors
Avoid selectors tied to implementation and page structure.
Instead, we can prioritize the below, based on [testing-library guiding principles](https://testing-library.com/docs/queries/about/#priority)
- `getByRole` (this aids accessibility, reflects how users and assistive technology perceive the page)
- `getByText`
- `getByTestId` (add them when needed)
DO NOT ⚔️
```javascript
page.locator('.opt-u > div > .summary > div:nth-child(4) > div')
```
DO 👍
```javascript
page.locator('#foo-button');
page.getByText('OK');
```
## Naming Conventions
### Files and folders
- **Files**: Declare in **_camelCase_**
- **Folders**: Declare in **_kebab-case_**
### Variables
Declare in **_camelCase_**.
### Booleans
Start with ‘is’, ‘has’, ‘are’, ‘have’. This helps spot that this is a boolean while skimming the code. Still declared in ***camelCase***.
```typescript
let isTurnedOn = false
```
### Page Objects / Classes
Declare in **_PascalCase_**.
Use descriptive naming, which can help the reader quickly identify what page or page component this is covering. Use as much context as needed from your product to make the name meaningful.
DO NOT ⚔️
```typescript
export class newModal
```
DO 👍
```typescript
export class AddWorksOrderModal
```
### Locators
Use descriptive naming, which can help the reader quickly identify what element the locator is targeting.
As an example, you can use a naming structure that contains ***“action / name of element” + “type of element”***.
***Defining type of element*** - These are your basic HTML element types, they’ll be defined and named in the design system, or as a team you can align on a consistent naming of the elements. Example: checkbox, tickbox, button, tooltip
***Defining action / name -*** Think about what action this element will perform when interacted with. Or any existing name/text of the element
DO 👍
```typescript
// This element is a submit button for the user registration form
const submitButton = await page.locator("<locator-path>");
```
DO 👍
```typescript
// This element is a button for uploading a profile picture
const uploadProfilePictureButton = await page.locator("<locator-path>");
```
### Function names
Always start function names with a ***“verb”***, followed by the ***“component context”*** that the function is interacting with i.e. what entity it is having an effect on.
DO 👍
```typescript
getWorksOrder()
printTransactions()
deleteProperty()
```

Some files were not shown because too many files have changed in this diff Show More