retold-facto 1.0.0 → 1.0.2
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.
- package/Dockerfile +2 -2
- package/bin/retold-facto.js +31 -0
- package/docs/_brand.json +18 -0
- package/docs/index.html +0 -2
- package/package.json +58 -26
- package/source/Retold-Facto.js +11 -0
- package/source/services/Retold-Facto-BeaconProvider.js +46 -0
- package/source/services/web-app/Facto-Brand.js +18 -0
- package/source/services/web-app/pict-app/Pict-Application-Facto.js +86 -2
- package/source/services/web-app/pict-app/views/PictView-Facto-Catalog.js +11 -11
- package/source/services/web-app/pict-app/views/PictView-Facto-Datasets.js +3 -3
- package/source/services/web-app/pict-app/views/PictView-Facto-Ingest.js +6 -6
- package/source/services/web-app/pict-app/views/PictView-Facto-Layout.js +24 -24
- package/source/services/web-app/pict-app/views/PictView-Facto-Login.js +91 -0
- package/source/services/web-app/pict-app/views/PictView-Facto-Projections.js +6 -6
- package/source/services/web-app/pict-app/views/PictView-Facto-Records.js +3 -3
- package/source/services/web-app/pict-app/views/PictView-Facto-Scanner.js +10 -10
- package/source/services/web-app/pict-app/views/PictView-Facto-Sources.js +4 -4
- package/source/services/web-app/pict-app/views/PictView-Facto-Throughput.js +3 -3
- package/source/services/web-app/pict-app-full/Pict-Application-Facto-Full.js +15 -47
- package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-BottomBar.js +5 -5
- package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Connections.js +7 -7
- package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Dashboard.js +2 -2
- package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Dashboards.js +21 -21
- package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Datasets.js +2 -2
- package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-MappingEditor.js +3 -3
- package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-ProjectionDetail.js +25 -25
- package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Projections.js +1 -1
- package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-RecordViewer.js +29 -29
- package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Records.js +25 -25
- package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Scanner.js +17 -17
- package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-SchemaDetail.js +48 -48
- package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-SchemaDocEditor.js +94 -94
- package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-SchemaEditor.js +18 -18
- package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-SchemaResearch.js +6 -6
- package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-SourceDetail.js +51 -51
- package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-SourceEditor.js +94 -94
- package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-SourceResearch.js +8 -8
- package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Throughput.js +30 -30
- package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-TopBar.js +31 -50
- package/source/services/web-app/web/codemirror-bundle.js +7 -7
- package/source/services/web-app/web/css/facto.css +83 -67
- package/source/services/web-app/web/favicons/apple-touch-icon.png +0 -0
- package/source/services/web-app/web/favicons/favicon-16.png +0 -0
- package/source/services/web-app/web/favicons/favicon-192.png +0 -0
- package/source/services/web-app/web/favicons/favicon-32.png +0 -0
- package/source/services/web-app/web/favicons/favicon-48.png +0 -0
- package/source/services/web-app/web/favicons/favicon-512.png +0 -0
- package/source/services/web-app/web/favicons/favicon-64.png +0 -0
- package/source/services/web-app/web/favicons/favicon-dark.svg +29 -0
- package/source/services/web-app/web/favicons/favicon-light.svg +29 -0
- package/source/services/web-app/web/favicons/favicon.svg +29 -0
- package/source/services/web-app/web/index.html +3 -7
- package/source/services/web-app/web/pict.min.js +12 -0
- package/source/services/web-app/web/retold-facto.js +8136 -2412
- package/source/services/web-app/web/retold-facto.js.map +1 -1
- package/source/services/web-app/web/retold-facto.min.js +34 -1
- package/source/services/web-app/web/retold-facto.min.js.map +1 -1
- package/test/Facto_Smoke_tests.js +127 -0
- package/docs/css/docuserve.css +0 -327
- package/source/services/web-app/web/css/facto-themes.css +0 -467
package/Dockerfile
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# Stage 1: Build
|
|
2
|
-
FROM node:
|
|
2
|
+
FROM node:22-slim AS builder
|
|
3
3
|
WORKDIR /app
|
|
4
4
|
COPY package*.json ./
|
|
5
5
|
# `npm install`, not `npm ci` — package-lock.json is gitignored per
|
|
@@ -16,7 +16,7 @@ RUN npx quack build
|
|
|
16
16
|
RUN cp node_modules/pict/dist/pict.min.js source/services/web-app/web/pict.min.js 2>/dev/null || true
|
|
17
17
|
|
|
18
18
|
# Stage 2: Runtime
|
|
19
|
-
FROM node:
|
|
19
|
+
FROM node:22-slim
|
|
20
20
|
WORKDIR /app
|
|
21
21
|
COPY package*.json ./
|
|
22
22
|
RUN npm install --omit=dev
|
package/bin/retold-facto.js
CHANGED
|
@@ -327,6 +327,37 @@ function commandServe()
|
|
|
327
327
|
_Fable.log.info(`API: http://localhost:${_Settings.APIServerPort}/1.0/`);
|
|
328
328
|
_Fable.log.info(`Facto: http://localhost:${_Settings.APIServerPort}/facto/`);
|
|
329
329
|
_Fable.log.info(`Web UI: http://localhost:${_Settings.APIServerPort}/`);
|
|
330
|
+
|
|
331
|
+
// Optional auto-connect to an Ultravisor coordinator. Only
|
|
332
|
+
// runs when FACTO_ULTRAVISOR_URL is set; standalone users
|
|
333
|
+
// with no Ultravisor in the loop see no behavior change.
|
|
334
|
+
// Failures are logged but don't kill the process — facto
|
|
335
|
+
// stays useful as a local REST surface. This also triggers
|
|
336
|
+
// the beacon-side WebAuth proxy install, which gates the web
|
|
337
|
+
// UI's session-bearing routes against UV's auth beacon when
|
|
338
|
+
// the upstream UV is in non-promiscuous mode.
|
|
339
|
+
let tmpUVUrl = process.env.FACTO_ULTRAVISOR_URL || '';
|
|
340
|
+
if (tmpUVUrl && _Fable.RetoldFactoBeaconProvider)
|
|
341
|
+
{
|
|
342
|
+
let tmpBeaconConfig =
|
|
343
|
+
{
|
|
344
|
+
ServerURL: tmpUVUrl,
|
|
345
|
+
Name: process.env.FACTO_BEACON_NAME || 'retold-facto',
|
|
346
|
+
Password: process.env.FACTO_BEACON_PASSWORD || '',
|
|
347
|
+
MaxConcurrent: parseInt(process.env.FACTO_MAX_CONCURRENT || '2', 10)
|
|
348
|
+
};
|
|
349
|
+
_Fable.log.info(`Auto-connecting to Ultravisor at ${tmpUVUrl} as "${tmpBeaconConfig.Name}"...`);
|
|
350
|
+
_Fable.RetoldFactoBeaconProvider.connectBeacon(tmpBeaconConfig,
|
|
351
|
+
(pConnectError) =>
|
|
352
|
+
{
|
|
353
|
+
if (pConnectError)
|
|
354
|
+
{
|
|
355
|
+
_Fable.log.error(`Ultravisor auto-connect failed: ${pConnectError.message || pConnectError}`);
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
_Fable.log.info(`Ultravisor auto-connect succeeded — registered as "${tmpBeaconConfig.Name}".`);
|
|
359
|
+
});
|
|
360
|
+
}
|
|
330
361
|
});
|
|
331
362
|
}
|
|
332
363
|
|
package/docs/_brand.json
ADDED
|
@@ -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": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Data warehouse and knowledge graph storage for the Retold ecosystem.",
|
|
5
5
|
"main": "source/Retold-Facto.js",
|
|
6
6
|
"bin": {
|
|
@@ -11,6 +11,8 @@
|
|
|
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",
|
|
@@ -28,7 +30,10 @@
|
|
|
28
30
|
"release:major:image": "npx quack release major --image"
|
|
29
31
|
},
|
|
30
32
|
"mocha": {
|
|
31
|
-
"spec":
|
|
33
|
+
"spec": [
|
|
34
|
+
"test/RetoldFacto_tests.js",
|
|
35
|
+
"test/Facto_Smoke_tests.js"
|
|
36
|
+
],
|
|
32
37
|
"diff": true,
|
|
33
38
|
"extension": [
|
|
34
39
|
"js"
|
|
@@ -103,40 +108,67 @@
|
|
|
103
108
|
},
|
|
104
109
|
"homepage": "https://github.com/stevenvelozo/retold-facto",
|
|
105
110
|
"devDependencies": {
|
|
106
|
-
"chai": "^
|
|
107
|
-
"
|
|
111
|
+
"chai": "^4.5.0",
|
|
112
|
+
"jsdom": "^25.0.1",
|
|
113
|
+
"mocha": "^11.0.1",
|
|
114
|
+
"pict-docuserve": "^1.3.2",
|
|
108
115
|
"puppeteer": "^24.40.0",
|
|
109
|
-
"quackage": "^1.2.
|
|
110
|
-
"
|
|
116
|
+
"quackage": "^1.2.3",
|
|
117
|
+
"retold-sharp": "^1.0.0",
|
|
118
|
+
"stricture": "^4.0.6",
|
|
111
119
|
"supertest": "^7.2.2"
|
|
112
120
|
},
|
|
113
121
|
"dependencies": {
|
|
114
122
|
"@codemirror/lang-markdown": "^6.5.0",
|
|
115
123
|
"@codemirror/state": "^6.6.0",
|
|
116
|
-
"meadow-connection-sqlite": "^1.0.19",
|
|
117
124
|
"@codemirror/view": "^6.41.0",
|
|
118
|
-
"bibliograph": "^0.
|
|
125
|
+
"bibliograph": "^1.0.0",
|
|
119
126
|
"codemirror": "^6.0.2",
|
|
120
|
-
"fable": "^3.1.
|
|
127
|
+
"fable": "^3.1.75",
|
|
121
128
|
"fable-serviceproviderbase": "^3.0.19",
|
|
122
129
|
"fast-xml-parser": "^5.5.10",
|
|
123
|
-
"meadow": "^2.0.
|
|
124
|
-
"meadow-connection-manager": "^1.1.
|
|
125
|
-
"meadow-connection-mysql": "^1.0.
|
|
126
|
-
"meadow-
|
|
127
|
-
"meadow-
|
|
128
|
-
"
|
|
129
|
-
"orator
|
|
130
|
-
"orator-
|
|
131
|
-
"
|
|
132
|
-
"pict
|
|
133
|
-
"pict-
|
|
134
|
-
"pict-
|
|
135
|
-
"pict-section-
|
|
136
|
-
"pict-section-
|
|
137
|
-
"pict-section-
|
|
138
|
-
"pict-section-
|
|
139
|
-
"
|
|
130
|
+
"meadow": "^2.0.41",
|
|
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.22",
|
|
135
|
+
"meadow-integration": "^1.0.41",
|
|
136
|
+
"orator": "^6.1.2",
|
|
137
|
+
"orator-serviceserver-restify": "^2.0.11",
|
|
138
|
+
"orator-static-server": "^2.1.4",
|
|
139
|
+
"pict": "^1.0.371",
|
|
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-login": "^1.0.0",
|
|
146
|
+
"pict-section-markdowneditor": "^1.0.15",
|
|
147
|
+
"pict-section-modal": "^1.1.1",
|
|
148
|
+
"pict-section-objecteditor": "^1.0.3",
|
|
149
|
+
"pict-section-theme": "^1.0.5",
|
|
150
|
+
"stricture": "^4.0.6",
|
|
151
|
+
"ultravisor-beacon": "^1.0.1",
|
|
140
152
|
"xlsx": "^0.18.5"
|
|
153
|
+
},
|
|
154
|
+
"retold": {
|
|
155
|
+
"brand": {
|
|
156
|
+
"Hash": "retold-facto",
|
|
157
|
+
"Name": "Retold Facto",
|
|
158
|
+
"Tagline": "Data warehouse and knowledge graph storage",
|
|
159
|
+
"Palette": "forest",
|
|
160
|
+
"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>",
|
|
161
|
+
"IconType": "svg",
|
|
162
|
+
"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>",
|
|
163
|
+
"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>",
|
|
164
|
+
"Colors": {
|
|
165
|
+
"Primary": "#419638",
|
|
166
|
+
"Secondary": "#c8bd52",
|
|
167
|
+
"PrimaryLight": "#419638",
|
|
168
|
+
"PrimaryDark": "#73bf6b",
|
|
169
|
+
"SecondaryLight": "#c8bd52",
|
|
170
|
+
"SecondaryDark": "#dad49c"
|
|
171
|
+
}
|
|
172
|
+
}
|
|
141
173
|
}
|
|
142
174
|
}
|
package/source/Retold-Facto.js
CHANGED
|
@@ -22,6 +22,7 @@ const libRetoldFactoRecordManager = require('./services/Retold-Facto-RecordManag
|
|
|
22
22
|
const libRetoldFactoDatasetManager = require('./services/Retold-Facto-DatasetManager.js');
|
|
23
23
|
const libRetoldFactoIngestEngine = require('./services/Retold-Facto-IngestEngine.js');
|
|
24
24
|
const libRetoldFactoProjectionEngine = require('./services/Retold-Facto-ProjectionEngine.js');
|
|
25
|
+
const libRetoldFactoBeaconProvider = require('./services/Retold-Facto-BeaconProvider.js');
|
|
25
26
|
const libRetoldFactoCatalogManager = require('./services/Retold-Facto-CatalogManager.js');
|
|
26
27
|
const libRetoldFactoStoreConnectionManager = require('./services/Retold-Facto-StoreConnectionManager.js');
|
|
27
28
|
const libRetoldFactoDataLakeService = require('./services/Retold-Facto-DataLakeService.js');
|
|
@@ -356,6 +357,16 @@ class RetoldFacto extends libFableServiceProviderBase
|
|
|
356
357
|
RoutePrefix: this.options.Facto.RoutePrefix
|
|
357
358
|
});
|
|
358
359
|
|
|
360
|
+
// BeaconProvider — exposes connectBeacon() so the CLI can wire
|
|
361
|
+
// facto into the Ultravisor mesh at startup. Registering the
|
|
362
|
+
// type here doesn't initiate a connection; bin/retold-facto.js
|
|
363
|
+
// invokes connectBeacon() when FACTO_ULTRAVISOR_URL is set.
|
|
364
|
+
this.fable.serviceManager.addServiceType('RetoldFactoBeaconProvider', libRetoldFactoBeaconProvider);
|
|
365
|
+
this.fable.serviceManager.instantiateServiceProvider('RetoldFactoBeaconProvider',
|
|
366
|
+
{
|
|
367
|
+
RoutePrefix: this.options.Facto.RoutePrefix
|
|
368
|
+
});
|
|
369
|
+
|
|
359
370
|
this.fable.serviceManager.addServiceType('RetoldFactoCatalogManager', libRetoldFactoCatalogManager);
|
|
360
371
|
this.fable.serviceManager.instantiateServiceProvider('RetoldFactoCatalogManager',
|
|
361
372
|
{
|
|
@@ -461,10 +461,56 @@ class RetoldFactoBeaconProvider extends libFableServiceProviderBase
|
|
|
461
461
|
}
|
|
462
462
|
|
|
463
463
|
this.log.info(`RetoldFactoBeaconProvider: beacon connected as ${pBeaconInfo.BeaconID}`);
|
|
464
|
+
// Install the beacon-side web-UI auth proxy now that
|
|
465
|
+
// connectBeacon has succeeded. Same pattern as the
|
|
466
|
+
// databeacon — see Ultravisor-Beacon-WebAuth.cjs for the
|
|
467
|
+
// install signature. Non-fatal if it fails (the beacon
|
|
468
|
+
// is still useful; the UI just stays open).
|
|
469
|
+
try { this._installWebAuth(pBeaconConfig); }
|
|
470
|
+
catch (pWebAuthErr)
|
|
471
|
+
{
|
|
472
|
+
this.log.warn(`RetoldFactoBeaconProvider: WebAuth install skipped: ${pWebAuthErr && pWebAuthErr.message}`);
|
|
473
|
+
}
|
|
464
474
|
return fCallback(null, pBeaconInfo);
|
|
465
475
|
});
|
|
466
476
|
}
|
|
467
477
|
|
|
478
|
+
/**
|
|
479
|
+
* Wire the SDK's WebAuth helper into facto's Orator server so the
|
|
480
|
+
* web UI's login flow proxies through UV's auth beacon. Idempotent
|
|
481
|
+
* — calling twice just re-registers the same routes (the helper's
|
|
482
|
+
* internal WeakMap tracks installs). Gating list scopes the gate
|
|
483
|
+
* to facto's own data-mutating routes; static assets + the auth
|
|
484
|
+
* routes themselves are always public.
|
|
485
|
+
*/
|
|
486
|
+
_installWebAuth(pBeaconConfig)
|
|
487
|
+
{
|
|
488
|
+
if (!libBeaconService || !libBeaconService.WebAuth)
|
|
489
|
+
{
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
if (!this.fable.OratorServiceServer)
|
|
493
|
+
{
|
|
494
|
+
this.log.warn('RetoldFactoBeaconProvider: WebAuth install: OratorServiceServer unavailable on fable; skipping.');
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
this._WebAuthHandle = libBeaconService.WebAuth.install(this.fable.OratorServiceServer,
|
|
498
|
+
{
|
|
499
|
+
UltravisorURL: pBeaconConfig.ServerURL,
|
|
500
|
+
BeaconName: pBeaconConfig.Name || 'retold-facto',
|
|
501
|
+
BeaconID: () => this._BeaconService && this._BeaconService.getBeaconID
|
|
502
|
+
? this._BeaconService.getBeaconID() : '',
|
|
503
|
+
CookieName: 'SessionID',
|
|
504
|
+
RoutePrefix: '/1.0/',
|
|
505
|
+
StatusPath: '/status',
|
|
506
|
+
// Gate facto's mutation + read endpoints. Auth + status
|
|
507
|
+
// + static UI stay public so login itself can render.
|
|
508
|
+
GatedPathPrefixes: ['/1.0/Source', '/1.0/Dataset', '/1.0/Record', '/1.0/Ingest'],
|
|
509
|
+
Log: this.fable.log
|
|
510
|
+
});
|
|
511
|
+
this.log.info('RetoldFactoBeaconProvider: WebAuth mounted /1.0/{Authenticate,Deauthenticate,CheckSession} + /status proxy');
|
|
512
|
+
}
|
|
513
|
+
|
|
468
514
|
/**
|
|
469
515
|
* Disconnect the beacon from the Ultravisor coordinator.
|
|
470
516
|
*
|
|
@@ -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;
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
const libPictApplication = require('pict-application');
|
|
2
2
|
|
|
3
3
|
const libPictSectionModal = require('pict-section-modal');
|
|
4
|
+
const libPictSectionLogin = require('pict-section-login');
|
|
5
|
+
const libBeaconWebAuthClient = require('ultravisor-beacon/webinterface/Pict-Beacon-WebAuth-Client.js');
|
|
4
6
|
const libProvider = require('./providers/Pict-Provider-Facto.js');
|
|
5
7
|
|
|
6
8
|
const libViewLayout = require('./views/PictView-Facto-Layout.js');
|
|
9
|
+
const libViewLogin = require('./views/PictView-Facto-Login.js');
|
|
7
10
|
const libViewSources = require('./views/PictView-Facto-Sources.js');
|
|
8
11
|
const libViewRecords = require('./views/PictView-Facto-Records.js');
|
|
9
12
|
const libViewDatasets = require('./views/PictView-Facto-Datasets.js');
|
|
@@ -27,6 +30,7 @@ class FactoApplication extends libPictApplication
|
|
|
27
30
|
|
|
28
31
|
// Register views
|
|
29
32
|
this.pict.addView('Facto-Layout', libViewLayout.default_configuration, libViewLayout);
|
|
33
|
+
this.pict.addView('Facto-Login', libViewLogin.default_configuration, libViewLogin);
|
|
30
34
|
this.pict.addView('Facto-Sources', libViewSources.default_configuration, libViewSources);
|
|
31
35
|
this.pict.addView('Facto-Records', libViewRecords.default_configuration, libViewRecords);
|
|
32
36
|
this.pict.addView('Facto-Datasets', libViewDatasets.default_configuration, libViewDatasets);
|
|
@@ -35,6 +39,29 @@ class FactoApplication extends libPictApplication
|
|
|
35
39
|
this.pict.addView('Facto-Catalog', libViewCatalog.default_configuration, libViewCatalog);
|
|
36
40
|
this.pict.addView('Facto-Scanner', libViewScanner.default_configuration, libViewScanner);
|
|
37
41
|
this.pict.addView('Facto-Throughput', libViewThroughput.default_configuration, libViewThroughput);
|
|
42
|
+
|
|
43
|
+
// Beacon-side login section + client helper. The helper hooks
|
|
44
|
+
// pict-section-login's lifecycle callbacks back into this
|
|
45
|
+
// application so login success / logout / session-check flow
|
|
46
|
+
// through `_showLoginOverlay()` and `_hideLoginOverlay()`. See
|
|
47
|
+
// modules/fable/ultravisor-beacon/webinterface/Pict-Beacon-
|
|
48
|
+
// WebAuth-Client.js for the install signature. When facto's
|
|
49
|
+
// server-side WebAuth proxy reports the UV is in promiscuous
|
|
50
|
+
// mode, the gate stays armed but invisible.
|
|
51
|
+
this._WebAuthClient = libBeaconWebAuthClient.install(this.pict,
|
|
52
|
+
{
|
|
53
|
+
Section: libPictSectionLogin,
|
|
54
|
+
AuthStateAddress: 'AppData.Facto.Auth',
|
|
55
|
+
LoginRoute: 'Facto-Login',
|
|
56
|
+
HomeRoute: 'Facto-Layout',
|
|
57
|
+
StatusURL: '/status',
|
|
58
|
+
LoginEndpoint: '/1.0/Authenticate',
|
|
59
|
+
LogoutEndpoint: '/1.0/Deauthenticate',
|
|
60
|
+
CheckSessionEndpoint: '/1.0/CheckSession',
|
|
61
|
+
OnAfterLogin: () => this._hideLoginOverlay(),
|
|
62
|
+
OnAfterLogout: () => this._showLoginOverlay(),
|
|
63
|
+
OnSessionChecked: (pSess) => { if (!(pSess && pSess.LoggedIn)) { this._showLoginOverlay(); } else { this._hideLoginOverlay(); } }
|
|
64
|
+
});
|
|
38
65
|
}
|
|
39
66
|
|
|
40
67
|
onAfterInitializeAsync(fCallback)
|
|
@@ -58,10 +85,67 @@ class FactoApplication extends libPictApplication
|
|
|
58
85
|
// Make pict available for inline onclick handlers
|
|
59
86
|
window.pict = this.pict;
|
|
60
87
|
|
|
61
|
-
//
|
|
88
|
+
// Ensure the login overlay mount point exists in the DOM
|
|
89
|
+
// before the section view tries to render into it. This is
|
|
90
|
+
// a one-time append so re-renders of the wrapper view don't
|
|
91
|
+
// stack additional overlays.
|
|
92
|
+
this._ensureLoginOverlayMount();
|
|
93
|
+
|
|
94
|
+
// Render layout (which cascades child view renders). We render
|
|
95
|
+
// the layout regardless of auth state; the overlay sits on top
|
|
96
|
+
// of it (z-index 9999) so an unauthenticated user simply can't
|
|
97
|
+
// interact with the underlying UI.
|
|
62
98
|
this.pict.views['Facto-Layout'].render();
|
|
63
99
|
|
|
64
|
-
|
|
100
|
+
// Boot gate: fetch /status to discover whether UV is running in
|
|
101
|
+
// authenticated mode. In promiscuous mode the overlay stays
|
|
102
|
+
// hidden and the UI works as before. In authenticated mode the
|
|
103
|
+
// pict-section-login's CheckSessionOnLoad fires (its default is
|
|
104
|
+
// true); the helper's OnSessionChecked hook then shows/hides
|
|
105
|
+
// the overlay based on whether the user's cookie is still good.
|
|
106
|
+
this._WebAuthClient.loadAuthStatus((pStatusErr) =>
|
|
107
|
+
{
|
|
108
|
+
if (pStatusErr)
|
|
109
|
+
{
|
|
110
|
+
this.pict.log.warn('Facto: /status fetch failed during boot: ' + pStatusErr.message);
|
|
111
|
+
}
|
|
112
|
+
let tmpAuth = (this.pict.AppData.Facto && this.pict.AppData.Facto.Auth) || {};
|
|
113
|
+
if (tmpAuth.Mode === 'authenticated')
|
|
114
|
+
{
|
|
115
|
+
// Show overlay; the section's auto-CheckSession will
|
|
116
|
+
// hide it back if there's a valid cookie.
|
|
117
|
+
this._showLoginOverlay();
|
|
118
|
+
this.pict.views['Facto-Login'].render();
|
|
119
|
+
}
|
|
120
|
+
return fCallback();
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Append `<div id="Facto-Login-Overlay">` to <body> if it isn't
|
|
126
|
+
* already there. The Facto-Login wrapper view targets this element
|
|
127
|
+
* via its DefaultDestinationAddress, so it must exist before the
|
|
128
|
+
* wrapper's first render() call.
|
|
129
|
+
*/
|
|
130
|
+
_ensureLoginOverlayMount()
|
|
131
|
+
{
|
|
132
|
+
if (typeof document === 'undefined') { return; }
|
|
133
|
+
if (document.getElementById('Facto-Login-Overlay')) { return; }
|
|
134
|
+
let tmpDiv = document.createElement('div');
|
|
135
|
+
tmpDiv.id = 'Facto-Login-Overlay';
|
|
136
|
+
document.body.appendChild(tmpDiv);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
_showLoginOverlay()
|
|
140
|
+
{
|
|
141
|
+
let tmpEl = (typeof document !== 'undefined') && document.getElementById('Facto-Login-Overlay');
|
|
142
|
+
if (tmpEl) { tmpEl.classList.add('is-active'); }
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
_hideLoginOverlay()
|
|
146
|
+
{
|
|
147
|
+
let tmpEl = (typeof document !== 'undefined') && document.getElementById('Facto-Login-Overlay');
|
|
148
|
+
if (tmpEl) { tmpEl.classList.remove('is-active'); }
|
|
65
149
|
}
|
|
66
150
|
}
|
|
67
151
|
|
|
@@ -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
|
|
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
|
|
40
|
+
let tmpVerified = tmpEntry.Verified ? '<span style="color:var(--theme-color-status-success, #28a745);">✓</span>' : '<span style="color:var(--theme-color-border-default, #ccc);">✗</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
|
|
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
|
|
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
|
|
188
|
-
: '<span style="color
|
|
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
|
|
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">▼</span>
|
|
419
419
|
</div>
|
|
420
420
|
<div class="accordion-body">
|
|
421
|
-
<p style="margin-bottom:12px; color
|
|
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
|
|
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
|
|
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
|
|
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">▼</span>
|
|
132
132
|
</div>
|
|
133
133
|
<div class="accordion-body">
|
|
134
|
-
<p style="margin-bottom:12px; color
|
|
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
|
|
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
|
|
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">▼</span>
|
|
198
198
|
</div>
|
|
199
199
|
<div class="accordion-body">
|
|
200
|
-
<p style="margin-bottom:12px; color
|
|
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
|
|
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
|
|
219
|
-
<p style="margin-bottom:8px; color
|
|
218
|
+
<h3 style="margin-top:20px; margin-bottom:8px; font-size:1em; color:var(--theme-color-text-secondary, #444);">Paste & 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>
|