--- name: qvw-preserve-interface description: > Protect QVW interface edits (sheets, tableboxes, charts, listboxes) from being destroyed by reload-save cycles. Sets up local git tracking of the -prj/ folder, enables QlikView's native auto-backup, installs a rolling 20-slot QVW backup, and wraps the reload BAT with pre/post-reload git commits so every interface edit is recoverable even if the QVW binary gets clobbered. Use this skill when the user says "my interface disappeared", "reload overwrote my edits", "protect my QVW objects", "version-control the QlikView app", "set up git for the QVW project", or mentions losing tableboxes/charts after a reload. Also apply proactively when scaffolding any new QVW project that will be reloaded repeatedly. Uses the COM GetProperties/SetProperties pattern (NOT SetScript — which doesn't exist on modern QV Document). --- # QVW Interface Preservation (git-backed) You are setting up a git-based safety net for QlikView Desktop projects so that **every interface edit survives reload cycles**. Without this, QV's default behaviour can silently drop charts/tableboxes whose source fields change during a reload. ## Why this is needed (the failure mode) 1. User opens `app.qvw` in QlikView, adds a tablebox or chart, saves. 2. Reload BAT fires (`qv.exe /r app.qvw`) — QV re-executes the script, which may rename/drop fields, then saves. 3. Objects referencing dropped/renamed fields are **silently removed** from the saved `.qvw` binary. 4. QV's native ring-buffer backup (`BackupKeepCopies=4` by default) gets evicted within a day of reload cycles → user's edit is **unrecoverable**. The fix: put every `-prj/` XML under git **before** each reload. ## Step 1: Gather inputs Ask the user for: 1. **Project root** — e.g. `C:\Users\...\MyProject\`. Must contain the QVW and the reload BAT. 2. **QVW filename** — e.g. `MyProject_v3.qvw`. (If multiple QVWs, ask which one.) 3. **Reload BAT filename** — e.g. `Reload_MyProject.bat`. (Often in `8.BAT\`.) Read the project layout to confirm those exist before proceeding. ## Step 2: Enable QlikView's native auto-backup Check `%APPDATA%\QlikTech\QlikView\Settings.ini` for these keys: ```ini [Settings 7] BackupBeforeReload=1 BackupEnable=1 BackupKeepCopies=4 ; QV default; user can raise AlwaysGenerateProject=1 ; required so -prj/ is populated on save ``` If any are missing, add them. Explain to the user that `AlwaysGenerateProject=1` is essential — without it the `-prj/` folder doesn't get the XML files that git tracks. ## Step 3: Initialize git in the project root ```bash cd git init git config user.email "" git config user.name "" ``` ## Step 4: Write the `.gitignore` Critical: **Windows git is case-insensitive by default**, so `*.qvw` would match the folder `4.Apps.QVW/` and ignore everything inside it (including the precious `-prj/` subfolders). Use the `.gitignore` template `templates/.gitignore` from this skill, which has the case-insensitive fix: - Ignores `**/*.qvw`, `**/*.qvf`, `**/*.qvd`, `**/*.qvw.bak*` (actual binary files) - Ignores `/4.Apps.QVW/backups/**` and `/4.Apps.QVW/_recovery/**` - **Re-includes** `/4.Apps.QVW/**/*-prj/` and its contents (the `!` rules come AFTER the ignore rules) - Ignores logs, `.DS_Store`, `Thumbs.db`, `*.tmp` - Ignores `4.Apps.QVW/Version * of *` (QV's native backup files, too big) Copy the template to `/.gitignore` and adapt paths if the project doesn't follow the QQinfo `4.Apps.QVW/` convention — ask the user. ## Step 5: Install `Backup_QVW.ps1` (rolling buffer) Copy `templates/Backup_QVW.ps1` into `/8.BAT/` (or wherever BATs live). Default retention is **20 slots** (parameter `-Keep`), so a day of reloads can't evict a good edit. This runs BEFORE each reload as a fallback safety net in case git isn't enough (e.g. if the user forgot to enable `AlwaysGenerateProject`). ## Step 6: Wrap the reload BAT with git commits The reload BAT must do, in order: 1. **Pre-reload `git add -A && git commit`** — captures whatever manual edits the user made since the last reload. 2. Backup QVW to rolling buffer (`Backup_QVW.ps1 -Keep 20`). 3. `qv.exe /r ` — the actual reload. 4. **Post-reload `git add -A && git commit`** — captures script-side changes so you can diff "user edits" vs "reload output". Use the template `templates/Reload_wrapped.bat`. Substitute: - `%PROJECT_ROOT%` — the project root - `%APP_PATH%` — the QVW to reload - `%LOG_FILE%` — where to append reload log (usually `10.QQlog\`) Warn user: all `git commit` commands use `--allow-empty` so they never fail even when nothing changed. ## Step 6b: Populating tableboxes programmatically QlikView's COM `TableBoxProperties.Fields.Add()` is BROKEN on modern QV (returns "null-valued expression"). The working pattern is `$tableBox.AddField($fieldName)` — called directly on the SheetObject, NOT on its properties. Use template `templates/populate_tablebox.ps1`: ```powershell powershell -File populate_tablebox.ps1 ` -QvwPath "C:\path\to\app.qvw" ` -SheetName "Cash Flow" ` -Fields @("%ProdPODateKey","cf_category","cf_payment_date","cf_amount_ron") ``` The script creates the sheet if missing (case-insensitive substring match on name), creates a fresh TableBox on it, and calls AddField per entry. Fields that don't exist in the data model fail silently — pass `-ReplaceExisting $true` to purge existing TBs on the sheet first (removes duplicates when re-running with corrected field lists). Common gotchas: - Field must exist in a RESIDENT table at save time. `Dim*` / `Fact*` tables often get dropped in a final-schema-reduction step — their fields won't populate. Check the `1700.ExportCSV.qvs`-style DROP list. - `%CompoundKey`-style field names (`%ProdPODateKey`, `%SupplierPOKey`) work fine — the `%` prefix is literal. - For Dim-only fields that DO survive (e.g. after renaming a drop list), run the `qvw-extract-script` skill first to audit what's actually in the final QVW schema. ## Step 7: Changing the script include path (if needed) If the QVW's embedded script points at an old `9.QVSvN` folder and needs to target a new one (e.g. during a version bump), use COM script injection via `GetProperties / SetProperties`. The legacy `SetScript()` method does NOT exist on modern QV Document COM. Template at `templates/inject_include.ps1`. Usage: ```powershell powershell -File inject_include.ps1 ` -QvwPath "C:\path\to\app.qvw" ` -NewInclude "C:\path\to\9.QVSv9\0100.MustInclude.qvs" ``` The script calls `$doc.GetProperties()` → sets `.Script` → `$doc.SetProperties($props)` → `.Save()`. ## Step 8: Make the initial commit ```bash cd git add -A git commit -m "Initial commit: QVS/config/-prj tracked; binaries excluded" git tag initial ``` Then verify with `git log --oneline` and confirm the `-prj/*.xml` files made it into the commit (not just `.qvs`/`.csv`). Run `git check-ignore -v 4.Apps.QVW/-prj/TB01.xml` to confirm NOT ignored. ## Step 9: Tell the user what to do when disaster strikes If a reload destroys an object: 1. `git log --oneline --all -- 4.Apps.QVW/-prj/` — find the last commit that had it. 2. `git show :4.Apps.QVW/-prj/TB05.xml` — recover the XML. 3. Paste the XML back into the `-prj/` folder and "Import from project" in QlikView, OR restore the whole QVW from the rolling buffer: `cp 4.Apps.QVW/backups/_.qvw 4.Apps.QVW/.qvw`. ## Step 10: Post-install verification Run the reload BAT once end-to-end. Confirm: - Two new git commits appear (`pre-reload` + `post-reload`). - A new `.qvw` lands in `4.Apps.QVW/backups/`. - The `-prj/` folder is populated with fresh XML timestamps. - `git check-ignore -v` on any `-prj/*.xml` returns empty (NOT ignored). If any of those fail, diagnose before declaring success. ## Common gotchas - **Filename with spaces/typos** (e.g. `QQpo_v2 inerface preps.qvw`) — QV COM `OpenDoc` returns null silently. Rename to a clean path before scripting. - **`.qvw.bak.qvf`** is QV's native one-off backup (same content, renamed). Safe to keep — gitignore already excludes. - **`Version N of .qvw`** — also QV native backups. Gitignored. - **Tableboxes in "show all fields of table" mode** self-heal after field renames. Tableboxes with explicit field lists do NOT — user has to re-edit. - **Branch protection** — the local-only setup has no remote by design. If the user wants off-site backup, run `git remote add origin ...` as a follow-up step (Gitea / GitHub / Forgejo).