retold-facto 0.2.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/.github/workflows/publish-image.yml +66 -0
  2. package/BUILDING-AND-PUBLISHING.md +140 -0
  3. package/Dockerfile +7 -4
  4. package/docs/_brand.json +18 -0
  5. package/docs/index.html +0 -2
  6. package/package.json +67 -27
  7. package/source/services/web-app/Facto-Brand.js +18 -0
  8. package/source/services/web-app/pict-app/views/PictView-Facto-Catalog.js +11 -11
  9. package/source/services/web-app/pict-app/views/PictView-Facto-Datasets.js +3 -3
  10. package/source/services/web-app/pict-app/views/PictView-Facto-Ingest.js +6 -6
  11. package/source/services/web-app/pict-app/views/PictView-Facto-Layout.js +24 -24
  12. package/source/services/web-app/pict-app/views/PictView-Facto-Projections.js +6 -6
  13. package/source/services/web-app/pict-app/views/PictView-Facto-Records.js +3 -3
  14. package/source/services/web-app/pict-app/views/PictView-Facto-Scanner.js +10 -10
  15. package/source/services/web-app/pict-app/views/PictView-Facto-Sources.js +4 -4
  16. package/source/services/web-app/pict-app/views/PictView-Facto-Throughput.js +3 -3
  17. package/source/services/web-app/pict-app-full/Pict-Application-Facto-Full.js +15 -47
  18. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-BottomBar.js +5 -5
  19. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Connections.js +7 -7
  20. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Dashboard.js +2 -2
  21. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Dashboards.js +21 -21
  22. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Datasets.js +2 -2
  23. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-MappingEditor.js +3 -3
  24. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-ProjectionDetail.js +25 -25
  25. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Projections.js +1 -1
  26. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-RecordViewer.js +29 -29
  27. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Records.js +25 -25
  28. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Scanner.js +17 -17
  29. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-SchemaDetail.js +48 -48
  30. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-SchemaDocEditor.js +94 -94
  31. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-SchemaEditor.js +18 -18
  32. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-SchemaResearch.js +6 -6
  33. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-SourceDetail.js +51 -51
  34. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-SourceEditor.js +94 -94
  35. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-SourceResearch.js +8 -8
  36. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Throughput.js +30 -30
  37. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-TopBar.js +31 -50
  38. package/source/services/web-app/web/codemirror-bundle.js +7 -7
  39. package/source/services/web-app/web/css/facto.css +83 -67
  40. package/source/services/web-app/web/favicons/apple-touch-icon.png +0 -0
  41. package/source/services/web-app/web/favicons/favicon-16.png +0 -0
  42. package/source/services/web-app/web/favicons/favicon-192.png +0 -0
  43. package/source/services/web-app/web/favicons/favicon-32.png +0 -0
  44. package/source/services/web-app/web/favicons/favicon-48.png +0 -0
  45. package/source/services/web-app/web/favicons/favicon-512.png +0 -0
  46. package/source/services/web-app/web/favicons/favicon-64.png +0 -0
  47. package/source/services/web-app/web/favicons/favicon-dark.svg +29 -0
  48. package/source/services/web-app/web/favicons/favicon-light.svg +29 -0
  49. package/source/services/web-app/web/favicons/favicon.svg +29 -0
  50. package/source/services/web-app/web/index.html +3 -7
  51. package/source/services/web-app/web/pict.min.js +12 -0
  52. package/source/services/web-app/web/retold-facto.js +7821 -2606
  53. package/source/services/web-app/web/retold-facto.js.map +1 -1
  54. package/source/services/web-app/web/retold-facto.min.js +34 -1
  55. package/source/services/web-app/web/retold-facto.min.js.map +1 -1
  56. package/test/Facto_Smoke_tests.js +127 -0
  57. package/docs/css/docuserve.css +0 -327
  58. package/source/services/web-app/web/css/facto-themes.css +0 -467
@@ -0,0 +1,66 @@
1
+ # Publish a container image to GitHub Container Registry on every
2
+ # version tag push (e.g. `v1.2.3`). Generated by `quack docker-init`.
3
+ #
4
+ # Image lands at:
5
+ # ghcr.io/stevenvelozo/retold-facto:<version>
6
+ # ghcr.io/stevenvelozo/retold-facto:latest (only on stable tags)
7
+
8
+ name: Publish container image
9
+
10
+ on:
11
+ push:
12
+ tags:
13
+ - 'v*.*.*'
14
+ workflow_dispatch:
15
+ inputs:
16
+ tag:
17
+ description: 'Tag to apply (e.g. dev or 1.2.3-test). `latest` is reserved for stable tag pushes.'
18
+ required: true
19
+ default: 'dev'
20
+
21
+ permissions:
22
+ contents: read
23
+ packages: write
24
+
25
+ jobs:
26
+ build-and-push:
27
+ runs-on: ubuntu-latest
28
+ steps:
29
+ - name: Checkout
30
+ uses: actions/checkout@v4
31
+
32
+ - name: Set up QEMU (multi-arch support)
33
+ uses: docker/setup-qemu-action@v3
34
+
35
+ - name: Set up Docker Buildx
36
+ uses: docker/setup-buildx-action@v3
37
+
38
+ - name: Log in to GHCR
39
+ uses: docker/login-action@v3
40
+ with:
41
+ registry: ghcr.io
42
+ username: ${{ github.actor }}
43
+ password: ${{ secrets.GITHUB_TOKEN }}
44
+
45
+ - name: Compute image tags
46
+ id: meta
47
+ uses: docker/metadata-action@v5
48
+ with:
49
+ images: ghcr.io/${{ github.repository_owner }}/retold-facto
50
+ tags: |
51
+ type=semver,pattern={{version}}
52
+ type=semver,pattern={{major}}.{{minor}}
53
+ type=semver,pattern={{major}}
54
+ type=raw,value=${{ github.event.inputs.tag }},enable=${{ github.event_name == 'workflow_dispatch' }}
55
+
56
+ - name: Build and push
57
+ uses: docker/build-push-action@v5
58
+ with:
59
+ context: .
60
+ file: ./Dockerfile
61
+ platforms: linux/amd64,linux/arm64
62
+ push: true
63
+ tags: ${{ steps.meta.outputs.tags }}
64
+ labels: ${{ steps.meta.outputs.labels }}
65
+ cache-from: type=gha
66
+ cache-to: type=gha,mode=max
@@ -0,0 +1,140 @@
1
+ # Building and Publishing
2
+
3
+ How to ship `retold-facto` to npm and to GitHub Container Registry
4
+ (GHCR). Generated by `quack docker-init`; the structure matches the
5
+ shared template across all dockerized retold tools.
6
+
7
+ `retold-facto` is a **long-running service**. Restart policy in compose / k8s should be `unless-stopped` (or equivalent). The Dockerfile should declare a HEALTHCHECK against the service's health endpoint.
8
+
9
+ ---
10
+
11
+ ## TL;DR
12
+
13
+ ```bash
14
+ # npm-only release (the default — most common case)
15
+ npm run release:patch
16
+
17
+ # npm release that ALSO rebuilds the GHCR image
18
+ npm run release:patch:image
19
+ ```
20
+
21
+ The default release is npm-only. Docker images are deliberate, opt-in
22
+ artifacts because each multi-arch build burns several minutes of CI
23
+ time. Use `:image` (or set `BUILD_DOCKER=1`) when runtime code,
24
+ dependencies, env-var contract, or the Dockerfile changed.
25
+
26
+ ---
27
+
28
+ ## Prerequisites (one-time setup)
29
+
30
+ - **npm login** — `npm whoami` should print your username.
31
+ - **Git remote configured** — `git remote get-url origin` should print
32
+ `git@github.com:stevenvelozo/retold-facto.git` (or the
33
+ HTTPS equivalent).
34
+ - **Push access to the repo** — required so `postversion` /
35
+ `postpublish` hooks can push commits and tags.
36
+ - **Docker** (only if you want to test the image locally before tag).
37
+
38
+ ---
39
+
40
+ ## Ecosystem convention: lockfiles are gitignored
41
+
42
+ `package-lock.json` is in this repo's `.gitignore` (Quackage convention
43
+ shared across the retold ecosystem). The Dockerfile must use `npm install`,
44
+ not `npm ci` — `npm ci` requires the lockfile to be in the build context
45
+ and CI runners only check out what's in git. If you see EUSAGE errors in
46
+ GHCR build logs, change `RUN npm ci` to `RUN npm install` in the
47
+ Dockerfile.
48
+
49
+ ---
50
+
51
+ ## Releasing
52
+
53
+ | Command | npm registry | GHCR image rebuild |
54
+ |--------------------------------------|--------------|--------------------|
55
+ | `npm run release:patch` | yes | no |
56
+ | `npm run release:patch:image` | yes | yes |
57
+ | `npm run release:minor` | yes | no |
58
+ | `npm run release:minor:image` | yes | yes |
59
+ | `npm run release:major` | yes | no |
60
+ | `npm run release:major:image` | yes | yes |
61
+
62
+ The non-`:image` variants are the default because most patch releases
63
+ don't change runtime behavior. The `:image` variants tell the pipeline
64
+ "this release does change runtime — build me a new image."
65
+
66
+ ### Direct CLI (also works)
67
+
68
+ ```bash
69
+ npm publish # npm only
70
+ npm run publish:docker # npm + docker (sets BUILD_DOCKER=1)
71
+ ```
72
+
73
+ ### From `retold-manager` TUI
74
+
75
+ - `[!]` Publish — npm only
76
+ - `[D]` Publish with docker image — npm + GHCR build
77
+
78
+ ### Promoting a previous npm release to docker later
79
+
80
+ If you released `v<x>` to npm only, then later decide you do want a
81
+ docker image:
82
+
83
+ ```bash
84
+ git push origin v<x> # pushes the local tag → GHCR fires
85
+ ```
86
+
87
+ The local tag is still sitting there from the original `npm version`
88
+ step. Pushing it triggers the workflow without touching npm.
89
+
90
+ ---
91
+
92
+ ## The chain
93
+
94
+ The lifecycle hooks all live in `package.json` and delegate to
95
+ `npx quack release …`. Default path (`BUILD_DOCKER` unset):
96
+
97
+ ```
98
+ npm publish
99
+ → prepublishOnly: npm test ← test gate
100
+ → publish to npm
101
+ → postpublish: BUILD_DOCKER unset → no-op ← image NOT triggered
102
+ ```
103
+
104
+ Docker-included path (`BUILD_DOCKER=1`):
105
+
106
+ ```
107
+ BUILD_DOCKER=1 npm publish (or: npm run publish:docker)
108
+ → prepublishOnly: npm test
109
+ → publish to npm
110
+ → postpublish: BUILD_DOCKER=1 → tag + push ← image trigger
111
+ → .github/workflows/publish-image.yml fires
112
+ → docker buildx build linux/amd64,linux/arm64
113
+ → docker push ghcr.io/stevenvelozo/retold-facto:<version>
114
+ ```
115
+
116
+ ---
117
+
118
+ ## Verifying a release
119
+
120
+ 1. **npm**: `npm view retold-facto version`
121
+ 2. **Workflow**: `https://github.com/stevenvelozo/retold-facto/actions`
122
+ 3. **Image**: `docker pull ghcr.io/stevenvelozo/retold-facto:latest`
123
+
124
+ If the first `docker pull` returns `denied`, the package is private by
125
+ default — flip visibility to public via Package Settings → Danger Zone
126
+ on the package page.
127
+
128
+ ---
129
+
130
+ ## Image consumption
131
+
132
+ ```bash
133
+ docker pull ghcr.io/stevenvelozo/retold-facto:latest
134
+ docker run --rm ghcr.io/stevenvelozo/retold-facto:latest
135
+ ```
136
+
137
+ Configuration via env vars: see this module's README for the supported
138
+ `<MODULE>_*` variables. Any secret-bearing var also accepts `<NAME>_FILE`
139
+ pointing at a file whose contents become the value (mysql/postgres
140
+ convention; works with docker secrets and k8s Secrets).
package/Dockerfile CHANGED
@@ -1,8 +1,11 @@
1
1
  # Stage 1: Build
2
- FROM node:20-slim AS builder
2
+ FROM node:22-slim AS builder
3
3
  WORKDIR /app
4
4
  COPY package*.json ./
5
- RUN npm ci
5
+ # `npm install`, not `npm ci` — package-lock.json is gitignored per
6
+ # the Quackage convention shared across the retold ecosystem, so the
7
+ # build context never has it. See BUILDING-AND-PUBLISHING.md.
8
+ RUN npm install
6
9
  COPY .quackage.json ./
7
10
  COPY source/ source/
8
11
  COPY bin/ bin/
@@ -13,10 +16,10 @@ RUN npx quack build
13
16
  RUN cp node_modules/pict/dist/pict.min.js source/services/web-app/web/pict.min.js 2>/dev/null || true
14
17
 
15
18
  # Stage 2: Runtime
16
- FROM node:20-slim
19
+ FROM node:22-slim
17
20
  WORKDIR /app
18
21
  COPY package*.json ./
19
- RUN npm ci --omit=dev
22
+ RUN npm install --omit=dev
20
23
  COPY --from=builder /app/source/ source/
21
24
  COPY --from=builder /app/bin/ bin/
22
25
  COPY --from=builder /app/test/model/ test/model/
@@ -0,0 +1,18 @@
1
+ {
2
+ "Hash": "retold-facto",
3
+ "Name": "Retold Facto",
4
+ "Tagline": "Data warehouse and knowledge graph storage for the Retold ecosystem.",
5
+ "Palette": "mix",
6
+ "Icon": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 96 96\" width=\"96\" height=\"96\">\n\t\t<defs>\n\t\t\t<clipPath id=\"frame-retold-facto-filled-light\">\n\t\t\t\t<path d=\"M 24 2\n\t\tH 72\n\t\tQ 94 2 94 24\n\t\tV 72\n\t\tQ 94 94 72 94\n\t\tH 24\n\t\tQ 2 94 2 72\n\t\tV 24\n\t\tQ 2 2 24 2 Z\"/>\n\t\t\t</clipPath>\n\t\t</defs>\n\t\t<path d=\"M 24 2\n\t\tH 72\n\t\tQ 94 2 94 24\n\t\tV 72\n\t\tQ 94 94 72 94\n\t\tH 24\n\t\tQ 2 94 2 72\n\t\tV 24\n\t\tQ 2 2 24 2 Z\" fill=\"#2e8ab5\"/>\n\t\t<g clip-path=\"url(#frame-retold-facto-filled-light)\"><rect x=\"26\" y=\"14\" width=\"18\" height=\"68\" rx=\"4\" fill=\"rgba(255,255,255,0.18)\"/><rect x=\"52\" y=\"14\" width=\"18\" height=\"68\" rx=\"4\" fill=\"#da9859\"/></g>\n\t\t<text x=\"48\" y=\"50\" text-anchor=\"middle\" dominant-baseline=\"central\"\n\t\t\tfont-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif\"\n\t\t\tfont-size=\"38\" font-weight=\"700\"\n\t\t\tfill=\"#ffffff\" letter-spacing=\"-1\">RF</text>\n\t</svg>",
7
+ "IconType": "svg",
8
+ "Favicon": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 96 96\" width=\"96\" height=\"96\">\n\t\t<defs>\n\t\t\t<clipPath id=\"fav-retold-facto-light\">\n\t\t\t\t<path d=\"M 24 2\n\t\tH 72\n\t\tQ 94 2 94 24\n\t\tV 72\n\t\tQ 94 94 72 94\n\t\tH 24\n\t\tQ 2 94 2 72\n\t\tV 24\n\t\tQ 2 2 24 2 Z\"/>\n\t\t\t</clipPath>\n\t\t</defs>\n\t\t<path d=\"M 24 2\n\t\tH 72\n\t\tQ 94 2 94 24\n\t\tV 72\n\t\tQ 94 94 72 94\n\t\tH 24\n\t\tQ 2 94 2 72\n\t\tV 24\n\t\tQ 2 2 24 2 Z\" fill=\"#2e8ab5\"/>\n\t\t<g clip-path=\"url(#fav-retold-facto-light)\"><rect x=\"20\" y=\"14\" width=\"56\" height=\"68\" rx=\"4\" fill=\"rgba(255,255,255,0.22)\"/></g>\n\t\t<text x=\"48\" y=\"50\" text-anchor=\"middle\" dominant-baseline=\"central\"\n\t\t\tfont-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif\"\n\t\t\tfont-size=\"60\" font-weight=\"800\"\n\t\t\tfill=\"#ffffff\" letter-spacing=\"-1\">R</text>\n\t</svg>",
9
+ "FaviconDark": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 96 96\" width=\"96\" height=\"96\">\n\t\t<defs>\n\t\t\t<clipPath id=\"fav-retold-facto-dark\">\n\t\t\t\t<path d=\"M 24 2\n\t\tH 72\n\t\tQ 94 2 94 24\n\t\tV 72\n\t\tQ 94 94 72 94\n\t\tH 24\n\t\tQ 2 94 2 72\n\t\tV 24\n\t\tQ 2 2 24 2 Z\"/>\n\t\t\t</clipPath>\n\t\t</defs>\n\t\t<path d=\"M 24 2\n\t\tH 72\n\t\tQ 94 2 94 24\n\t\tV 72\n\t\tQ 94 94 72 94\n\t\tH 24\n\t\tQ 2 94 2 72\n\t\tV 24\n\t\tQ 2 2 24 2 Z\" fill=\"#6cb2d3\"/>\n\t\t<g clip-path=\"url(#fav-retold-facto-dark)\"><rect x=\"20\" y=\"14\" width=\"56\" height=\"68\" rx=\"4\" fill=\"rgba(255,255,255,0.22)\"/></g>\n\t\t<text x=\"48\" y=\"50\" text-anchor=\"middle\" dominant-baseline=\"central\"\n\t\t\tfont-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif\"\n\t\t\tfont-size=\"60\" font-weight=\"800\"\n\t\t\tfill=\"#101418\" letter-spacing=\"-1\">R</text>\n\t</svg>",
10
+ "Colors": {
11
+ "Primary": "#2e8ab5",
12
+ "Secondary": "#da9859",
13
+ "PrimaryLight": "#2e8ab5",
14
+ "PrimaryDark": "#6cb2d3",
15
+ "SecondaryLight": "#da9859",
16
+ "SecondaryDark": "#e7c7a7"
17
+ }
18
+ }
package/docs/index.html CHANGED
@@ -8,8 +8,6 @@
8
8
 
9
9
  <title>Retold Facto v0.1.0 Documentation</title>
10
10
 
11
- <!-- Application Stylesheet -->
12
- <link href="css/docuserve.css" rel="stylesheet">
13
11
  <!-- KaTeX stylesheet for LaTeX equation rendering -->
14
12
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/katex.min.css">
15
13
  <!-- PICT Dynamic View CSS Container -->
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "retold-facto",
3
- "version": "0.2.0",
3
+ "version": "1.0.1",
4
4
  "description": "Data warehouse and knowledge graph storage for the Retold ecosystem.",
5
5
  "main": "source/Retold-Facto.js",
6
6
  "bin": {
@@ -11,14 +11,29 @@
11
11
  "coverage": "npx quack coverage",
12
12
  "test": "npx quack test",
13
13
  "test-browser": "npx mocha test/Facto_Browser_Integration_tests.js -u tdd --exit --timeout 120000",
14
+ "brand": "node node_modules/pict-section-theme/bin/pict-section-theme-brand.js --manifest ../../../Retold-Modules-Manifest.json --module retold-facto --favicons source/services/web-app/web/favicons",
15
+ "prebuild": "npm run brand",
14
16
  "build": "npx quack build",
15
17
  "build-codemirror": "npx esbuild source/services/web-app/codemirror-entry.js --bundle --outfile=source/services/web-app/web/codemirror-bundle.js --format=iife --global-name=CodeMirrorModules --platform=browser --target=es2018",
16
18
  "build-test-model": "cd test && npx stricture -i model/ddl/Facto.ddl",
17
19
  "docker-build": "docker build -t retold-facto .",
18
- "docker-run": "docker run -p 8386:8386 retold-facto"
20
+ "docker-run": "docker run -p 8386:8386 retold-facto",
21
+ "prepublishOnly": "npm test",
22
+ "postversion": "npx quack release postversion",
23
+ "postpublish": "npx quack release postpublish",
24
+ "publish:docker": "npx quack release publish --image",
25
+ "release:patch": "npx quack release patch",
26
+ "release:minor": "npx quack release minor",
27
+ "release:major": "npx quack release major",
28
+ "release:patch:image": "npx quack release patch --image",
29
+ "release:minor:image": "npx quack release minor --image",
30
+ "release:major:image": "npx quack release major --image"
19
31
  },
20
32
  "mocha": {
21
- "spec": "test/RetoldFacto_tests.js",
33
+ "spec": [
34
+ "test/RetoldFacto_tests.js",
35
+ "test/Facto_Smoke_tests.js"
36
+ ],
22
37
  "diff": true,
23
38
  "extension": [
24
39
  "js"
@@ -93,40 +108,65 @@
93
108
  },
94
109
  "homepage": "https://github.com/stevenvelozo/retold-facto",
95
110
  "devDependencies": {
96
- "chai": "^6.2.2",
97
- "pict-docuserve": "^0.1.5",
111
+ "chai": "^4.5.0",
112
+ "jsdom": "^25.0.1",
113
+ "mocha": "^11.0.1",
114
+ "pict-docuserve": "^1.3.2",
98
115
  "puppeteer": "^24.40.0",
99
- "quackage": "^1.1.3",
100
- "stricture": "^4.0.2",
116
+ "quackage": "^1.2.3",
117
+ "retold-sharp": "^1.0.0",
118
+ "stricture": "^4.0.3",
101
119
  "supertest": "^7.2.2"
102
120
  },
103
121
  "dependencies": {
104
122
  "@codemirror/lang-markdown": "^6.5.0",
105
123
  "@codemirror/state": "^6.6.0",
106
- "meadow-connection-sqlite": "^1.0.19",
107
124
  "@codemirror/view": "^6.41.0",
108
- "bibliograph": "^0.1.6",
125
+ "bibliograph": "^1.0.0",
109
126
  "codemirror": "^6.0.2",
110
- "fable": "^3.1.71",
127
+ "fable": "^3.1.73",
111
128
  "fable-serviceproviderbase": "^3.0.19",
112
129
  "fast-xml-parser": "^5.5.10",
113
- "meadow": "^2.0.37",
114
- "meadow-connection-manager": "^1.1.0",
115
- "meadow-connection-mysql": "^1.0.18",
116
- "meadow-endpoints": "^4.0.17",
117
- "meadow-integration": "^1.0.38",
118
- "orator": "^6.1.0",
119
- "orator-serviceserver-restify": "^2.0.10",
120
- "orator-static-server": "^2.1.3",
121
- "pict": "^1.0.365",
122
- "pict-router": "^1.0.9",
123
- "pict-section-connection-form": "^0.0.1",
124
- "pict-section-flow": "^0.0.17",
125
- "pict-section-histogram": "^1.0.0",
126
- "pict-section-markdowneditor": "^1.0.10",
127
- "pict-section-modal": "^0.0.5",
128
- "pict-section-objecteditor": "^1.0.1",
129
- "stricture": "^4.0.2",
130
+ "meadow": "^2.0.39",
131
+ "meadow-connection-manager": "^1.1.2",
132
+ "meadow-connection-mysql": "^1.0.19",
133
+ "meadow-connection-sqlite": "^1.0.20",
134
+ "meadow-endpoints": "^4.0.21",
135
+ "meadow-integration": "^1.0.40",
136
+ "orator": "^6.1.2",
137
+ "orator-serviceserver-restify": "^2.0.11",
138
+ "orator-static-server": "^2.1.4",
139
+ "pict": "^1.0.369",
140
+ "pict-provider-theme": "^1.0.1",
141
+ "pict-router": "^1.0.10",
142
+ "pict-section-connection-form": "^1.0.0",
143
+ "pict-section-flow": "^1.0.1",
144
+ "pict-section-histogram": "^1.0.1",
145
+ "pict-section-markdowneditor": "^1.0.15",
146
+ "pict-section-modal": "^1.1.1",
147
+ "pict-section-objecteditor": "^1.0.3",
148
+ "pict-section-theme": "^1.0.5",
149
+ "stricture": "^4.0.3",
130
150
  "xlsx": "^0.18.5"
151
+ },
152
+ "retold": {
153
+ "brand": {
154
+ "Hash": "retold-facto",
155
+ "Name": "Retold Facto",
156
+ "Tagline": "Data warehouse and knowledge graph storage",
157
+ "Palette": "forest",
158
+ "Icon": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 96 96\" width=\"96\" height=\"96\">\n\t\t<defs>\n\t\t\t<clipPath id=\"frame-retold-facto-filled-light\">\n\t\t\t\t<path d=\"M 24 2\n\t\tH 72\n\t\tQ 94 2 94 24\n\t\tV 72\n\t\tQ 94 94 72 94\n\t\tH 24\n\t\tQ 2 94 2 72\n\t\tV 24\n\t\tQ 2 2 24 2 Z\"/>\n\t\t\t</clipPath>\n\t\t</defs>\n\t\t<path d=\"M 24 2\n\t\tH 72\n\t\tQ 94 2 94 24\n\t\tV 72\n\t\tQ 94 94 72 94\n\t\tH 24\n\t\tQ 2 94 2 72\n\t\tV 24\n\t\tQ 2 2 24 2 Z\" fill=\"#419638\"/>\n\t\t<g clip-path=\"url(#frame-retold-facto-filled-light)\"><rect x=\"26\" y=\"14\" width=\"18\" height=\"68\" rx=\"4\" fill=\"rgba(255,255,255,0.18)\"/><rect x=\"52\" y=\"14\" width=\"18\" height=\"68\" rx=\"4\" fill=\"#c8bd52\"/></g>\n\t\t<text x=\"48\" y=\"50\" text-anchor=\"middle\" dominant-baseline=\"central\"\n\t\t\tfont-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif\"\n\t\t\tfont-size=\"38\" font-weight=\"700\"\n\t\t\tfill=\"#ffffff\" letter-spacing=\"-1\">RF</text>\n\t</svg>",
159
+ "IconType": "svg",
160
+ "Favicon": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 96 96\" width=\"96\" height=\"96\">\n\t\t<defs>\n\t\t\t<clipPath id=\"fav-retold-facto-light\">\n\t\t\t\t<path d=\"M 24 2\n\t\tH 72\n\t\tQ 94 2 94 24\n\t\tV 72\n\t\tQ 94 94 72 94\n\t\tH 24\n\t\tQ 2 94 2 72\n\t\tV 24\n\t\tQ 2 2 24 2 Z\"/>\n\t\t\t</clipPath>\n\t\t</defs>\n\t\t<path d=\"M 24 2\n\t\tH 72\n\t\tQ 94 2 94 24\n\t\tV 72\n\t\tQ 94 94 72 94\n\t\tH 24\n\t\tQ 2 94 2 72\n\t\tV 24\n\t\tQ 2 2 24 2 Z\" fill=\"#419638\"/>\n\t\t<g clip-path=\"url(#fav-retold-facto-light)\"><rect x=\"20\" y=\"14\" width=\"56\" height=\"68\" rx=\"4\" fill=\"rgba(255,255,255,0.22)\"/></g>\n\t\t<text x=\"48\" y=\"50\" text-anchor=\"middle\" dominant-baseline=\"central\"\n\t\t\tfont-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif\"\n\t\t\tfont-size=\"60\" font-weight=\"800\"\n\t\t\tfill=\"#ffffff\" letter-spacing=\"-1\">R</text>\n\t</svg>",
161
+ "FaviconDark": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 96 96\" width=\"96\" height=\"96\">\n\t\t<defs>\n\t\t\t<clipPath id=\"fav-retold-facto-dark\">\n\t\t\t\t<path d=\"M 24 2\n\t\tH 72\n\t\tQ 94 2 94 24\n\t\tV 72\n\t\tQ 94 94 72 94\n\t\tH 24\n\t\tQ 2 94 2 72\n\t\tV 24\n\t\tQ 2 2 24 2 Z\"/>\n\t\t\t</clipPath>\n\t\t</defs>\n\t\t<path d=\"M 24 2\n\t\tH 72\n\t\tQ 94 2 94 24\n\t\tV 72\n\t\tQ 94 94 72 94\n\t\tH 24\n\t\tQ 2 94 2 72\n\t\tV 24\n\t\tQ 2 2 24 2 Z\" fill=\"#73bf6b\"/>\n\t\t<g clip-path=\"url(#fav-retold-facto-dark)\"><rect x=\"20\" y=\"14\" width=\"56\" height=\"68\" rx=\"4\" fill=\"rgba(255,255,255,0.22)\"/></g>\n\t\t<text x=\"48\" y=\"50\" text-anchor=\"middle\" dominant-baseline=\"central\"\n\t\t\tfont-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif\"\n\t\t\tfont-size=\"60\" font-weight=\"800\"\n\t\t\tfill=\"#101418\" letter-spacing=\"-1\">R</text>\n\t</svg>",
162
+ "Colors": {
163
+ "Primary": "#419638",
164
+ "Secondary": "#c8bd52",
165
+ "PrimaryLight": "#419638",
166
+ "PrimaryDark": "#73bf6b",
167
+ "SecondaryLight": "#c8bd52",
168
+ "SecondaryDark": "#dad49c"
169
+ }
170
+ }
131
171
  }
132
172
  }
@@ -0,0 +1,18 @@
1
+ 'use strict';
2
+
3
+ // Brand wrapper — deterministic brand block emitted by `npm run brand`
4
+ // (which calls pict-section-theme-brand with the Branding entry from
5
+ // Retold-Modules-Manifest.json). Passed to Theme-Section as the `Brand`
6
+ // option so the BrandMark wordmark + --brand-color-* variables are
7
+ // wired into every themed surface.
8
+
9
+ // services/web-app/Facto-Brand.js → three levels up to the package.json
10
+ const tmpPackage = require('../../../package.json');
11
+
12
+ if (!tmpPackage.retold || !tmpPackage.retold.brand)
13
+ {
14
+ throw new Error('retold-facto: package.json is missing retold.brand — '
15
+ + 'run `npm run brand` (which calls pict-section-theme-brand) before building');
16
+ }
17
+
18
+ module.exports = tmpPackage.retold.brand;
@@ -29,7 +29,7 @@ class FactoCatalogView extends libPictView
29
29
  let tmpEntries = this.pict.AppData.Facto.CatalogEntries;
30
30
  if (!tmpEntries || tmpEntries.length === 0)
31
31
  {
32
- tmpContainer.innerHTML = '<p style="color:#888; font-style:italic;">No catalog entries yet. Add sources to your research catalog.</p>';
32
+ tmpContainer.innerHTML = '<p style="color:var(--theme-color-text-muted, #888); font-style:italic;">No catalog entries yet. Add sources to your research catalog.</p>';
33
33
  return;
34
34
  }
35
35
 
@@ -37,7 +37,7 @@ class FactoCatalogView extends libPictView
37
37
  for (let i = 0; i < tmpEntries.length; i++)
38
38
  {
39
39
  let tmpEntry = tmpEntries[i];
40
- let tmpVerified = tmpEntry.Verified ? '<span style="color:#28a745;">&#10003;</span>' : '<span style="color:#ccc;">&#10007;</span>';
40
+ let tmpVerified = tmpEntry.Verified ? '<span style="color:var(--theme-color-status-success, #28a745);">&#10003;</span>' : '<span style="color:var(--theme-color-border-default, #ccc);">&#10007;</span>';
41
41
  tmpHtml += '<tr>';
42
42
  tmpHtml += '<td>' + (tmpEntry.IDSourceCatalogEntry || '') + '</td>';
43
43
  tmpHtml += '<td>' + (tmpEntry.Agency || '') + '</td>';
@@ -171,11 +171,11 @@ class FactoCatalogView extends libPictView
171
171
  (pResponse) =>
172
172
  {
173
173
  let tmpDatasets = (pResponse && pResponse.Datasets) ? pResponse.Datasets : [];
174
- let tmpHtml = '<h3 style="margin-bottom:8px; font-size:1em; color:#444;">Dataset Definitions for Entry #' + pIDEntry + '</h3>';
174
+ let tmpHtml = '<h3 style="margin-bottom:8px; font-size:1em; color:var(--theme-color-text-secondary, #444);">Dataset Definitions for Entry #' + pIDEntry + '</h3>';
175
175
 
176
176
  if (tmpDatasets.length === 0)
177
177
  {
178
- tmpHtml += '<p style="color:#888; font-style:italic; margin-bottom:8px;">No dataset definitions yet.</p>';
178
+ tmpHtml += '<p style="color:var(--theme-color-text-muted, #888); font-style:italic; margin-bottom:8px;">No dataset definitions yet.</p>';
179
179
  }
180
180
  else
181
181
  {
@@ -184,8 +184,8 @@ class FactoCatalogView extends libPictView
184
184
  {
185
185
  let tmpDS = tmpDatasets[i];
186
186
  let tmpStatusLabel = tmpDS.Provisioned
187
- ? '<span style="color:#28a745;">Provisioned (Source #' + tmpDS.IDSource + ', Dataset #' + tmpDS.IDDataset + ')</span>'
188
- : '<span style="color:#888;">Not provisioned</span>';
187
+ ? '<span style="color:var(--theme-color-status-success, #28a745);">Provisioned (Source #' + tmpDS.IDSource + ', Dataset #' + tmpDS.IDDataset + ')</span>'
188
+ : '<span style="color:var(--theme-color-text-muted, #888);">Not provisioned</span>';
189
189
  let tmpActionBtn = '';
190
190
  if (tmpDS.Provisioned)
191
191
  {
@@ -209,7 +209,7 @@ class FactoCatalogView extends libPictView
209
209
  }
210
210
 
211
211
  // Add dataset definition form
212
- tmpHtml += '<h4 style="margin-top:12px; margin-bottom:8px; font-size:0.95em; color:#555;">Add Dataset Definition</h4>';
212
+ tmpHtml += '<h4 style="margin-top:12px; margin-bottom:8px; font-size:0.95em; color:var(--theme-color-text-secondary, #555);">Add Dataset Definition</h4>';
213
213
  tmpHtml += '<div class="inline-group">';
214
214
  tmpHtml += '<div><label for="facto-catds-name">Name</label><input type="text" id="facto-catds-name" placeholder="e.g. Monthly Earthquake Feed"></div>';
215
215
  tmpHtml += '<div><label for="facto-catds-format">Format</label>';
@@ -418,7 +418,7 @@ module.exports.default_configuration =
418
418
  <span class="accordion-toggle">&#9660;</span>
419
419
  </div>
420
420
  <div class="accordion-body">
421
- <p style="margin-bottom:12px; color:#666; font-size:0.9em;">Research and catalog potential data sources before provisioning them as runtime Sources and Datasets.</p>
421
+ <p style="margin-bottom:12px; color:var(--theme-color-text-secondary, #666); font-size:0.9em;">Research and catalog potential data sources before provisioning them as runtime Sources and Datasets.</p>
422
422
 
423
423
  <!-- Search -->
424
424
  <div class="inline-group" style="margin-bottom:12px;">
@@ -437,7 +437,7 @@ module.exports.default_configuration =
437
437
  <div id="facto-catalog-detail" style="margin-top:12px;"></div>
438
438
 
439
439
  <!-- Add entry form -->
440
- <h3 style="margin-top:16px; margin-bottom:8px; font-size:1em; color:#444;">Add Catalog Entry</h3>
440
+ <h3 style="margin-top:16px; margin-bottom:8px; font-size:1em; color:var(--theme-color-text-secondary, #444);">Add Catalog Entry</h3>
441
441
  <div class="inline-group">
442
442
  <div>
443
443
  <label for="facto-catalog-agency">Agency / Organization</label>
@@ -504,8 +504,8 @@ module.exports.default_configuration =
504
504
  <button class="primary" onclick="pict.views['Facto-Catalog'].addEntry()">Add Catalog Entry</button>
505
505
 
506
506
  <!-- Import / Export -->
507
- <h3 style="margin-top:16px; margin-bottom:8px; font-size:1em; color:#444;">Import / Export</h3>
508
- <textarea id="facto-catalog-import-json" rows="4" style="width:100%; font-family:monospace; font-size:0.85em; padding:8px; border:1px solid #ccc; border-radius:4px; margin-bottom:8px;" placeholder="Paste JSON array of catalog entries here..."></textarea>
507
+ <h3 style="margin-top:16px; margin-bottom:8px; font-size:1em; color:var(--theme-color-text-secondary, #444);">Import / Export</h3>
508
+ <textarea id="facto-catalog-import-json" rows="4" style="width:100%; font-family:monospace; font-size:0.85em; padding:8px; border:1px solid var(--theme-color-border-default, #ccc); border-radius:4px; margin-bottom:8px;" placeholder="Paste JSON array of catalog entries here..."></textarea>
509
509
  <button class="primary" onclick="pict.views['Facto-Catalog'].importCatalog()">Import JSON</button>
510
510
  <button class="secondary" onclick="pict.views['Facto-Catalog'].exportCatalog()">Export Catalog</button>
511
511
 
@@ -28,7 +28,7 @@ class FactoDatasetsView extends libPictView
28
28
  let tmpDatasets = this.pict.AppData.Facto.Datasets;
29
29
  if (!tmpDatasets || tmpDatasets.length === 0)
30
30
  {
31
- tmpContainer.innerHTML = '<p style="color:#888; font-style:italic;">No datasets created yet.</p>';
31
+ tmpContainer.innerHTML = '<p style="color:var(--theme-color-text-muted, #888); font-style:italic;">No datasets created yet.</p>';
32
32
  return;
33
33
  }
34
34
 
@@ -131,10 +131,10 @@ module.exports.default_configuration =
131
131
  <span class="accordion-toggle">&#9660;</span>
132
132
  </div>
133
133
  <div class="accordion-body">
134
- <p style="margin-bottom:12px; color:#666; font-size:0.9em;">Datasets are named collections of records. Types: Raw (ingested), Compositional (merged), Projection (flattened), Derived (computed).</p>
134
+ <p style="margin-bottom:12px; color:var(--theme-color-text-secondary, #666); font-size:0.9em;">Datasets are named collections of records. Types: Raw (ingested), Compositional (merged), Projection (flattened), Derived (computed).</p>
135
135
  <div id="facto-datasets-list"></div>
136
136
 
137
- <h3 style="margin-top:16px; margin-bottom:8px; font-size:1em; color:#444;">Create Dataset</h3>
137
+ <h3 style="margin-top:16px; margin-bottom:8px; font-size:1em; color:var(--theme-color-text-secondary, #444);">Create Dataset</h3>
138
138
  <div class="inline-group">
139
139
  <div>
140
140
  <label for="facto-dataset-name">Name</label>
@@ -28,7 +28,7 @@ class FactoIngestView extends libPictView
28
28
  let tmpJobs = this.pict.AppData.Facto.IngestJobs;
29
29
  if (!tmpJobs || tmpJobs.length === 0)
30
30
  {
31
- tmpContainer.innerHTML = '<p style="color:#888; font-style:italic;">No ingest jobs yet.</p>';
31
+ tmpContainer.innerHTML = '<p style="color:var(--theme-color-text-muted, #888); font-style:italic;">No ingest jobs yet.</p>';
32
32
  return;
33
33
  }
34
34
 
@@ -197,10 +197,10 @@ module.exports.default_configuration =
197
197
  <span class="accordion-toggle">&#9660;</span>
198
198
  </div>
199
199
  <div class="accordion-body">
200
- <p style="margin-bottom:12px; color:#666; font-size:0.9em;">Track data ingest operations from configured sources into datasets.</p>
200
+ <p style="margin-bottom:12px; color:var(--theme-color-text-secondary, #666); font-size:0.9em;">Track data ingest operations from configured sources into datasets.</p>
201
201
  <div id="facto-ingest-list"></div>
202
202
 
203
- <h3 style="margin-top:16px; margin-bottom:8px; font-size:1em; color:#444;">Create Ingest Job</h3>
203
+ <h3 style="margin-top:16px; margin-bottom:8px; font-size:1em; color:var(--theme-color-text-secondary, #444);">Create Ingest Job</h3>
204
204
  <div class="inline-group">
205
205
  <div>
206
206
  <label for="facto-ingest-source">Source ID</label>
@@ -215,8 +215,8 @@ module.exports.default_configuration =
215
215
 
216
216
  <pre id="facto-ingest-log" style="display:none; margin-top:12px; padding:12px; background:#f8f9fa; border:1px solid #e9ecef; border-radius:4px; font-size:0.85em; max-height:200px; overflow:auto; white-space:pre-wrap;"></pre>
217
217
 
218
- <h3 style="margin-top:20px; margin-bottom:8px; font-size:1em; color:#444;">Paste &amp; Ingest</h3>
219
- <p style="margin-bottom:8px; color:#666; font-size:0.85em;">Paste CSV or JSON content directly to ingest records.</p>
218
+ <h3 style="margin-top:20px; margin-bottom:8px; font-size:1em; color:var(--theme-color-text-secondary, #444);">Paste &amp; Ingest</h3>
219
+ <p style="margin-bottom:8px; color:var(--theme-color-text-secondary, #666); font-size:0.85em;">Paste CSV or JSON content directly to ingest records.</p>
220
220
  <div class="inline-group">
221
221
  <div>
222
222
  <label for="facto-ingest-paste-dataset">Dataset ID</label>
@@ -239,7 +239,7 @@ module.exports.default_configuration =
239
239
  <input type="text" id="facto-ingest-paste-type" placeholder="data">
240
240
  </div>
241
241
  </div>
242
- <textarea id="facto-ingest-paste-content" rows="6" style="width:100%; padding:8px 12px; border:1px solid #ccc; border-radius:4px; font-size:0.9em; font-family:monospace; margin-bottom:10px;" placeholder="Paste CSV or JSON data here..."></textarea>
242
+ <textarea id="facto-ingest-paste-content" rows="6" style="width:100%; padding:8px 12px; border:1px solid var(--theme-color-border-default, #ccc); border-radius:4px; font-size:0.9em; font-family:monospace; margin-bottom:10px;" placeholder="Paste CSV or JSON data here..."></textarea>
243
243
  <button class="primary" onclick="pict.views['Facto-Ingest'].ingestPastedContent()">Ingest</button>
244
244
 
245
245
  </div>