Commit possible fixes for build

This commit is contained in:
shahondin1624
2026-04-07 21:46:41 +02:00
parent d36c1a59ca
commit 7b582639e1
11 changed files with 351 additions and 2 deletions
+9
View File
@@ -0,0 +1,9 @@
# MariaDB
MYSQL_ROOT_PASSWORD=changeme_root
MYSQL_DATABASE=nextcloud
MYSQL_USER=nextcloud
MYSQL_PASSWORD=changeme_nc
# Nextcloud admin
NEXTCLOUD_ADMIN_USER=admin
NEXTCLOUD_ADMIN_PASSWORD=changeme_admin
+6
View File
@@ -21,3 +21,9 @@ composer.lock
# npm # npm
package-lock.json package-lock.json
# Secrets
.env
# Docker
.build_done
+55
View File
@@ -0,0 +1,55 @@
# Issue #124: Nav sidebar clicks don't navigate between views
## Summary
The `NcAppNavigationItem` components in `App.vue` use `@click` handlers to call `router.push()`,
but the component internally renders an `<a href="#">` that intercepts the click event, navigating
to `#` (root hash) before the Vue click handler fires. The fix is to use `NcAppNavigationItem`'s
built-in `:to` prop which renders the element as a `<router-link>`, handling navigation natively.
## Plan
### Step 1: Modify `src/App.vue` navigation items
For each `NcAppNavigationItem`:
1. Replace `@click="navigate('routeName')"` with `:to="{ name: 'routeName' }"`
2. Remove the `:active` binding since `NcAppNavigationItem` auto-detects active state from `:to`
3. Keep icon template slots unchanged
### Step 2: Remove the `navigate()` function and `useRouter` import
Since navigation is now handled by the `:to` prop:
- Remove `const router = useRouter()`
- Remove the `navigate()` function
- Remove `useRouter` from the import (keep `useRoute` since `currentRoute` still needs it)
### Step 3: Keep `currentRoute` if needed, OR remove
Actually, with `:to` prop, `NcAppNavigationItem` automatically sets active state. But for routes
like `member-detail` that should highlight "Mitglieder", we need the `:active` prop for parent
route matching. The `:to` prop only auto-activates on exact route match.
**Decision**: Keep `:active` bindings for nav items that have sub-routes (Mitglieder, Familien, Lager)
to handle parent-route highlighting. For items with no sub-routes (Beiträge, Berichte, Audit-Log,
Einstellungen), `:to` auto-active is sufficient — but for consistency, keep all `:active` bindings.
Actually, let me reconsider: the `:to` prop with vue-router uses `router-link-active` class which
matches prefix. So `/members/5` would still match `{ name: 'members' }` route... but only if
the path matches. Since named routes have exact paths, it depends on `router-link` behavior.
**Safest approach**: Keep `:active` bindings for items with child routes, remove them for simple routes.
No -- for consistency and zero regression risk, keep ALL `:active` bindings.
### Step 4: Verify build compiles
Run `npm run build` to ensure no errors.
## Acceptance Criteria Checklist
1. [ ] Each `NcAppNavigationItem` uses `:to` prop with the correct route object
2. [ ] No `@click="navigate(...)"` handlers remain on navigation items
3. [ ] The `navigate()` function is removed
4. [ ] The `useRouter` import is removed (no longer needed)
5. [ ] `:active` bindings are preserved for parent-route highlighting
6. [ ] Build succeeds without errors
7. [ ] All existing routes still work (no route names changed)
+72
View File
@@ -0,0 +1,72 @@
# Plan: Issue #18 — Set up DB migrations for members table
## Summary
Create a Nextcloud OCP migration class that sets up the `oc_mv_members` table with all columns specified in the issue and requirements section 5.2. The migration follows Nextcloud's migration framework using `\OCP\Migration\SimpleMigrationStep` and Doctrine DBAL schema. Foreign key columns for `stufe_id` and `family_id` are created as nullable integer columns (FK constraints will be added when those tables are created in issues #30 and #27 respectively).
## Implementation Steps
### Step 1: Create Migration Class
- File: `lib/Migration/Version000001Date20260407000000.php`
- Namespace: `OCA\Mitgliederverwaltung\Migration`
- Extends: `SimpleMigrationStep`
- Method: `changeSchema(IOutput $output, Closure $schemaClosure, array $options)`
### Step 2: Define Table Schema — `oc_mv_members`
Columns (from issue #18 specification):
| Column | Type | Constraints |
|--------|------|------------|
| `id` | bigint | PK, autoincrement, unsigned |
| `vorname` | string(255) | NOT NULL |
| `nachname` | string(255) | NOT NULL |
| `geburtsdatum` | date | NOT NULL |
| `geschlecht` | string(20) | nullable |
| `rolle` | string(30) | NOT NULL, default 'mitglied' |
| `stufe_id` | bigint | nullable, unsigned (FK to oc_mv_stufen, added later) |
| `eintritt` | date | NOT NULL |
| `austritt` | date | nullable |
| `status` | string(20) | NOT NULL, default 'aktiv' |
| `allergien_encrypted` | text | nullable |
| `notizen` | text | nullable |
| `zusatz_notizen` | text | nullable |
| `kv_typ` | string(20) | nullable |
| `kv_name` | string(255) | nullable |
| `family_id` | bigint | nullable, unsigned (FK to oc_mv_families, added later) |
| `frozen_fee_rate` | decimal(10,2) | nullable |
| `calendar_event_uri` | string(512) | nullable |
| `contact_vcard_uri` | string(512) | nullable |
| `created_at` | datetime | NOT NULL, default CURRENT_TIMESTAMP |
| `updated_at` | datetime | NOT NULL, default CURRENT_TIMESTAMP |
| `deleted_at` | datetime | nullable |
### Step 3: Add Indexes
- Index on `status` (frequent filtering)
- Index on `family_id` (joins)
- Index on `stufe_id` (joins)
- Index on `nachname` (sorting/searching)
- Index on `deleted_at` (soft-delete queries)
- Composite index on `status, deleted_at` (common query pattern: active non-deleted members)
### Step 4: Verify Migration Structure
- Ensure the class is properly namespaced and autoloadable via PSR-4
- Ensure the table name uses Nextcloud's table prefix convention (just use `mv_members` — Nextcloud adds `oc_` prefix)
## Acceptance Criteria Checklist
1. [ ] Migration file exists at `lib/Migration/Version000001Date20260407000000.php`
2. [ ] Class extends `SimpleMigrationStep` and implements `changeSchema`
3. [ ] Table `mv_members` is created with all 20 columns from the spec
4. [ ] Column types match the specification (string for enums, bigint for FKs, decimal for fee rate, etc.)
5. [ ] `id` is primary key, autoincrement, unsigned bigint
6. [ ] NOT NULL constraints applied to: vorname, nachname, geburtsdatum, rolle, eintritt, status, created_at, updated_at
7. [ ] Nullable columns: geschlecht, stufe_id, austritt, allergien_encrypted, notizen, zusatz_notizen, kv_typ, kv_name, family_id, frozen_fee_rate, calendar_event_uri, contact_vcard_uri, deleted_at
8. [ ] Default values set for: rolle='mitglied', status='aktiv'
9. [ ] Appropriate indexes are created
10. [ ] PHP syntax is valid (no parse errors)
11. [ ] File follows Nextcloud migration conventions (namespace, class name pattern)
12. [ ] Migration is idempotent (checks if table exists before creating)
+75
View File
@@ -0,0 +1,75 @@
.PHONY: build deps up down setup deploy redeploy logs clean
# Install dependencies (composer via Docker since PHP may not be local)
deps:
npm install --no-audit --no-fund
docker run --rm -v "$$(pwd):/app" -w /app composer:2 install --no-dev --optimize-autoloader --no-interaction
# Build frontend
build: deps
npx webpack --node-env production --progress
# Start containers (detached)
up:
docker compose up -d
# Wait for NC to be ready, install it, copy app in, enable it
setup:
@echo "Waiting for Nextcloud container to be ready..."
@until docker compose exec -T nextcloud test -f config/CAN_INSTALL 2>/dev/null || \
docker compose exec -T nextcloud test -f config/config.php 2>/dev/null; do \
sleep 3; \
echo " still waiting..."; \
done
@sleep 5
@echo "Fixing custom_apps ownership..."
docker compose exec nextcloud chown www-data:www-data /var/www/html/custom_apps
@echo "Installing Nextcloud..."
docker compose exec -u www-data nextcloud php occ maintenance:install \
--database=mysql \
--database-host=db \
--database-name=$${MYSQL_DATABASE:-nextcloud} \
--database-user=$${MYSQL_USER:-nextcloud} \
--database-pass=$$(grep MYSQL_PASSWORD .env | head -1 | cut -d= -f2) \
--admin-user=$$(grep NEXTCLOUD_ADMIN_USER .env | cut -d= -f2) \
--admin-pass=$$(grep NEXTCLOUD_ADMIN_PASSWORD .env | cut -d= -f2) \
2>&1 || true
@echo "Copying app into Nextcloud..."
docker compose exec nextcloud mkdir -p /var/www/html/custom_apps/mitgliederverwaltung
docker compose exec nextcloud cp -a /app-src/appinfo /var/www/html/custom_apps/mitgliederverwaltung/
docker compose exec nextcloud cp -a /app-src/lib /var/www/html/custom_apps/mitgliederverwaltung/
docker compose exec nextcloud cp -a /app-src/templates /var/www/html/custom_apps/mitgliederverwaltung/
docker compose exec nextcloud cp -a /app-src/js /var/www/html/custom_apps/mitgliederverwaltung/
docker compose exec nextcloud cp -a /app-src/vendor /var/www/html/custom_apps/mitgliederverwaltung/
docker compose exec nextcloud chown -R www-data:www-data /var/www/html/custom_apps/mitgliederverwaltung
@echo "Enabling app..."
docker compose exec -u www-data nextcloud php occ app:enable mitgliederverwaltung
@echo ""
@echo "Done! Nextcloud is running at http://localhost:8080"
@echo "Login with credentials from .env (NEXTCLOUD_ADMIN_USER / NEXTCLOUD_ADMIN_PASSWORD)"
# Full deploy: build, start, install, enable
deploy: build up setup
# Rebuild and redeploy app into running NC
redeploy: build
docker compose exec nextcloud rm -rf /var/www/html/custom_apps/mitgliederverwaltung
docker compose exec nextcloud mkdir -p /var/www/html/custom_apps/mitgliederverwaltung
docker compose exec nextcloud cp -a /app-src/appinfo /var/www/html/custom_apps/mitgliederverwaltung/
docker compose exec nextcloud cp -a /app-src/lib /var/www/html/custom_apps/mitgliederverwaltung/
docker compose exec nextcloud cp -a /app-src/templates /var/www/html/custom_apps/mitgliederverwaltung/
docker compose exec nextcloud cp -a /app-src/js /var/www/html/custom_apps/mitgliederverwaltung/
docker compose exec nextcloud cp -a /app-src/vendor /var/www/html/custom_apps/mitgliederverwaltung/
docker compose exec nextcloud chown -R www-data:www-data /var/www/html/custom_apps/mitgliederverwaltung
docker compose exec -u www-data nextcloud php occ upgrade 2>/dev/null || true
@echo "App redeployed."
down:
docker compose down
logs:
docker compose logs -f nextcloud
# Remove volumes (full reset)
clean:
docker compose down -v
+1 -1
View File
@@ -5,7 +5,7 @@
<name>Mitgliederverwaltung</name> <name>Mitgliederverwaltung</name>
<summary>Mitgliederverwaltung für Pfadfindervereine</summary> <summary>Mitgliederverwaltung für Pfadfindervereine</summary>
<description><![CDATA[Verwaltung von Mitgliedern, Familien, Beiträgen, Lagern und mehr für Pfadfindervereine. Integriert sich in Nextcloud Kalender, Kontakte und Dateien.]]></description> <description><![CDATA[Verwaltung von Mitgliedern, Familien, Beiträgen, Lagern und mehr für Pfadfindervereine. Integriert sich in Nextcloud Kalender, Kontakte und Dateien.]]></description>
<version>0.0.1</version> <version>0.0.3</version>
<licence>agpl</licence> <licence>agpl</licence>
<author>shahondin1624</author> <author>shahondin1624</author>
<namespace>Mitgliederverwaltung</namespace> <namespace>Mitgliederverwaltung</namespace>
+32
View File
@@ -0,0 +1,32 @@
services:
db:
image: mariadb:10.11
restart: unless-stopped
env_file: .env
volumes:
- db_data:/var/lib/mysql
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
interval: 10s
timeout: 5s
retries: 5
nextcloud:
image: nextcloud:28-apache
restart: unless-stopped
ports:
- "8080:80"
env_file: .env
environment:
MYSQL_HOST: db
NEXTCLOUD_TRUSTED_DOMAINS: "localhost"
volumes:
- nc_data:/var/www/html
- ./:/app-src:ro
depends_on:
db:
condition: service_healthy
volumes:
db_data:
nc_data:
+24
View File
@@ -0,0 +1,24 @@
<?php
declare(strict_types=1);
namespace OCA\Mitgliederverwaltung\Controller;
use OCA\Mitgliederverwaltung\AppInfo\Application;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\IRequest;
class PageController extends Controller {
public function __construct(IRequest $request) {
parent::__construct(Application::APP_ID, $request);
}
/**
* @NoAdminRequired
* @NoCSRFRequired
*/
public function index(): TemplateResponse {
return new TemplateResponse(Application::APP_ID, 'index');
}
}
+21
View File
@@ -6,5 +6,26 @@
"build": "webpack --node-env production --progress", "build": "webpack --node-env production --progress",
"dev": "webpack --node-env development --progress", "dev": "webpack --node-env development --progress",
"watch": "webpack --node-env development --progress --watch" "watch": "webpack --node-env development --progress --watch"
},
"dependencies": {
"@nextcloud/axios": "^2.5.0",
"@nextcloud/router": "^3.0.0",
"@nextcloud/vue": "^9.6.0",
"pinia": "^2.1.7",
"vue": "^3.4.0",
"vue-material-design-icons": "^5.3.0",
"vue-router": "^4.2.5"
},
"devDependencies": {
"@babel/core": "^7.24.0",
"@babel/preset-env": "^7.24.0",
"babel-loader": "^9.1.3",
"css-loader": "^6.10.0",
"sass": "^1.71.0",
"sass-loader": "^14.1.0",
"style-loader": "^3.3.4",
"vue-loader": "^17.4.2",
"webpack": "^5.90.0",
"webpack-cli": "^5.1.4"
} }
} }
+1 -1
View File
@@ -6,7 +6,7 @@ use OCP\Util;
$appId = OCA\Mitgliederverwaltung\AppInfo\Application::APP_ID; $appId = OCA\Mitgliederverwaltung\AppInfo\Application::APP_ID;
Util::addScript($appId, $appId . '-main'); Util::addScript($appId, $appId . '-main');
Util::addStyle($appId, 'main');
?> ?>
<div id="app-content"> <div id="app-content">
+55
View File
@@ -0,0 +1,55 @@
const path = require('path')
const webpack = require('webpack')
const { VueLoaderPlugin } = require('vue-loader')
module.exports = {
entry: {
'mitgliederverwaltung-main': path.join(__dirname, 'src', 'main.js'),
},
output: {
path: path.resolve(__dirname, 'js'),
publicPath: '/custom_apps/mitgliederverwaltung/js/',
filename: '[name].js',
chunkFilename: '[name]-[contenthash].js',
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/,
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
{
test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader'],
},
{
test: /\.(png|jpe?g|gif|svg|woff2?|eot|ttf|otf)$/,
type: 'asset/resource',
},
],
},
plugins: [
new VueLoaderPlugin(),
new webpack.optimize.LimitChunkCountPlugin({
maxChunks: 1,
}),
],
optimization: {
splitChunks: false,
},
resolve: {
extensions: ['.js', '.vue'],
alias: {
vue$: 'vue/dist/vue.esm-bundler.js',
},
},
}