@sensolus/create-snt-agent-app 0.1.1 → 0.2.0
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/index.js +2 -1
- package/package.json +1 -1
- package/template/README.md +16 -0
- package/template/_env.example +14 -4
- package/template/backend/app.py +12 -0
- package/template/package.json +1 -1
- package/template/src/App.jsx +24 -5
- package/template/src/AppConfigContext.jsx +45 -0
- package/template/src/i18n/translations/de.js +0 -24
- package/template/src/i18n/translations/en.js +0 -24
- package/template/src/i18n/translations/es.js +0 -24
- package/template/src/i18n/translations/fr.js +0 -24
- package/template/src/i18n/translations/nl.js +0 -24
- package/template/src/main.jsx +1 -4
- package/template/src/pages/OrganisationDetail.jsx +4 -0
- package/template/src/pages/WidgetShowcase.jsx +8 -8
- package/template/src/styles/app.css +1 -1
package/index.js
CHANGED
|
@@ -39,7 +39,7 @@ async function substitute(dir) {
|
|
|
39
39
|
for (const entry of await readdir(dir)) {
|
|
40
40
|
const p = path.join(dir, entry)
|
|
41
41
|
if ((await stat(p)).isDirectory()) { await substitute(p); continue }
|
|
42
|
-
if (!/\.(json|js|jsx|html|md|py|txt|sh|css)$|^\.[a-z]
|
|
42
|
+
if (!/\.(json|js|jsx|html|md|py|txt|sh|css|yml|yaml|ini|mako)$|^\.[a-z][a-z.]*$|^(Jenkinsfile|Dockerfile|Makefile)$/i.test(entry)) continue
|
|
43
43
|
const content = await readFile(p, 'utf8')
|
|
44
44
|
if (content.includes('{{APP_NAME}}')) {
|
|
45
45
|
await writeFile(p, content.replaceAll('{{APP_NAME}}', appName))
|
|
@@ -53,6 +53,7 @@ Created ${appName}/
|
|
|
53
53
|
|
|
54
54
|
Next steps:
|
|
55
55
|
cd ${appName}
|
|
56
|
+
cp .env.example .env # then fill in MAPBOX_KEY + LOCATIONIQ_KEY (required for SntMap)
|
|
56
57
|
npm install
|
|
57
58
|
pip install -r backend/requirements.txt
|
|
58
59
|
npm run dev # frontend on :3000
|
package/package.json
CHANGED
package/template/README.md
CHANGED
|
@@ -11,6 +11,22 @@ A modern React + Flask dashboard for querying the Sensolus public API. This appl
|
|
|
11
11
|
|
|
12
12
|
## Quick Start
|
|
13
13
|
|
|
14
|
+
### Environment Variables (.env)
|
|
15
|
+
|
|
16
|
+
Copy `.env.example` to `.env` and fill in the map provider keys (ask your team
|
|
17
|
+
or check the vault). They are **required** for the map pages (`SntMap`):
|
|
18
|
+
|
|
19
|
+
```env
|
|
20
|
+
MAPBOX_KEY=pk....
|
|
21
|
+
LOCATIONIQ_KEY=pk....
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
The Flask backend loads `.env` at startup and serves the keys to the frontend
|
|
25
|
+
at runtime via `/api/config` (so they are not baked into the build, and one
|
|
26
|
+
Docker image can deploy across environments — in Docker, pass them with
|
|
27
|
+
`-e MAPBOX_KEY=... -e LOCATIONIQ_KEY=...`). The real `.env` is gitignored;
|
|
28
|
+
never commit keys.
|
|
29
|
+
|
|
14
30
|
### Local Development (Recommended)
|
|
15
31
|
|
|
16
32
|
Run both the frontend dev server and Flask backend in separate terminals:
|
package/template/_env.example
CHANGED
|
@@ -1,4 +1,14 @@
|
|
|
1
|
-
# Copy to .env
|
|
2
|
-
#
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
# Copy to .env and fill in — never commit the real .env (it is gitignored).
|
|
2
|
+
#
|
|
3
|
+
# Map provider keys (get them from your team vault). Required for SntMap:
|
|
4
|
+
# the Flask backend reads them at request time and serves them to the
|
|
5
|
+
# frontend via /api/config, so one Docker image works across environments.
|
|
6
|
+
MAPBOX_KEY=
|
|
7
|
+
LOCATIONIQ_KEY=
|
|
8
|
+
|
|
9
|
+
# PostgreSQL connection (defaults shown; see README "Database Configuration")
|
|
10
|
+
#DB_HOST=localhost
|
|
11
|
+
#DB_PORT=5432
|
|
12
|
+
#DB_NAME={{APP_NAME}}
|
|
13
|
+
#DB_USER=snt
|
|
14
|
+
#DB_PASSWORD=snt
|
package/template/backend/app.py
CHANGED
|
@@ -401,6 +401,18 @@ def get_devices_by_filter():
|
|
|
401
401
|
|
|
402
402
|
|
|
403
403
|
LOCATIONIQ_KEY = os.environ.get('LOCATIONIQ_KEY', '')
|
|
404
|
+
MAPBOX_KEY = os.environ.get('MAPBOX_KEY', '')
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
@app.route('/api/config')
|
|
408
|
+
def app_config():
|
|
409
|
+
"""Runtime config served to the frontend. Lets one Docker image deploy
|
|
410
|
+
across dev/demo/prod by reading keys from the container's env at request
|
|
411
|
+
time instead of baking them into the bundle at build time."""
|
|
412
|
+
return jsonify({
|
|
413
|
+
'mapboxKey': MAPBOX_KEY,
|
|
414
|
+
'locationiqKey': LOCATIONIQ_KEY,
|
|
415
|
+
}), 200
|
|
404
416
|
|
|
405
417
|
|
|
406
418
|
@app.route('/api/geocode')
|
package/template/package.json
CHANGED
package/template/src/App.jsx
CHANGED
|
@@ -1,14 +1,33 @@
|
|
|
1
|
-
import { BrowserRouter, Routes, Route } from 'react-router-dom'
|
|
1
|
+
import { BrowserRouter, Routes, Route, useNavigate } from 'react-router-dom'
|
|
2
|
+
import { SntUiProvider } from '@sensolus/snt-agent-kit'
|
|
3
|
+
import { LocaleProvider, messages } from './i18n'
|
|
4
|
+
import { AppConfigProvider } from './AppConfigContext'
|
|
2
5
|
import { Home } from './pages/Home'
|
|
3
6
|
import { OrganisationDetail } from './pages/OrganisationDetail'
|
|
4
7
|
|
|
8
|
+
// SntUiProvider decouples kit widgets from the router and backend:
|
|
9
|
+
// pass `navigate` (and optionally `api`) so widgets like SntPageHeader work.
|
|
10
|
+
// LocaleProvider sits inside it so it fetches login info via the api adapter.
|
|
11
|
+
function AppShell() {
|
|
12
|
+
const navigate = useNavigate()
|
|
13
|
+
return (
|
|
14
|
+
<SntUiProvider navigate={navigate}>
|
|
15
|
+
<LocaleProvider messages={messages}>
|
|
16
|
+
<AppConfigProvider>
|
|
17
|
+
<Routes>
|
|
18
|
+
<Route path="/" element={<Home />} />
|
|
19
|
+
<Route path="/organisation/:id" element={<OrganisationDetail />} />
|
|
20
|
+
</Routes>
|
|
21
|
+
</AppConfigProvider>
|
|
22
|
+
</LocaleProvider>
|
|
23
|
+
</SntUiProvider>
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
|
|
5
27
|
function App() {
|
|
6
28
|
return (
|
|
7
29
|
<BrowserRouter>
|
|
8
|
-
<
|
|
9
|
-
<Route path="/" element={<Home />} />
|
|
10
|
-
<Route path="/organisation/:id" element={<OrganisationDetail />} />
|
|
11
|
-
</Routes>
|
|
30
|
+
<AppShell />
|
|
12
31
|
</BrowserRouter>
|
|
13
32
|
)
|
|
14
33
|
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { createContext, useContext, useEffect, useState } from 'react'
|
|
2
|
+
import { SntLoadingOverlay } from '@sensolus/snt-agent-kit'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Fetches runtime config (map tile keys, etc.) from the Flask backend's
|
|
6
|
+
* /api/config endpoint and gates the app on it. Lets one Docker image
|
|
7
|
+
* deploy across environments — keys come from the container's env vars
|
|
8
|
+
* at runtime instead of being baked into the bundle at `vite build` time.
|
|
9
|
+
*/
|
|
10
|
+
const AppConfigContext = createContext(null)
|
|
11
|
+
|
|
12
|
+
export function AppConfigProvider({ children }) {
|
|
13
|
+
const [config, setConfig] = useState(null)
|
|
14
|
+
const [error, setError] = useState(null)
|
|
15
|
+
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
let cancelled = false
|
|
18
|
+
fetch('/api/config')
|
|
19
|
+
.then(r => r.ok ? r.json() : Promise.reject(new Error(`HTTP ${r.status}`)))
|
|
20
|
+
.then(data => { if (!cancelled) setConfig(data) })
|
|
21
|
+
.catch(err => { if (!cancelled) setError(err) })
|
|
22
|
+
return () => { cancelled = true }
|
|
23
|
+
}, [])
|
|
24
|
+
|
|
25
|
+
if (error) {
|
|
26
|
+
return (
|
|
27
|
+
<div style={{ padding: 40, color: 'var(--snt-red)' }}>
|
|
28
|
+
Failed to load app config from /api/config: {error.message}
|
|
29
|
+
</div>
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
if (!config) return <SntLoadingOverlay message="Loading config..." />
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<AppConfigContext.Provider value={config}>
|
|
36
|
+
{children}
|
|
37
|
+
</AppConfigContext.Provider>
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function useAppConfig() {
|
|
42
|
+
const ctx = useContext(AppConfigContext)
|
|
43
|
+
if (!ctx) throw new Error('useAppConfig must be used inside AppConfigProvider')
|
|
44
|
+
return ctx
|
|
45
|
+
}
|
|
@@ -17,34 +17,10 @@ export default {
|
|
|
17
17
|
// Table widget
|
|
18
18
|
|
|
19
19
|
// CheckboxList widget
|
|
20
|
-
'checkboxList.selectAll': 'Alle auswählen',
|
|
21
|
-
'checkboxList.deselectAll': 'Alle abwählen',
|
|
22
20
|
|
|
23
21
|
// Sidepanel
|
|
24
|
-
'sidepanel.collapse': 'Panel einklappen',
|
|
25
|
-
'sidepanel.expand': 'Panel ausklappen',
|
|
26
22
|
|
|
27
23
|
// DateRangePicker presets
|
|
28
|
-
'dateRange.period': 'Zeitraum:',
|
|
29
|
-
'dateRange.from': 'Von',
|
|
30
|
-
'dateRange.to': 'Bis',
|
|
31
|
-
'dateRange.preset.this_month': 'Dieser Monat',
|
|
32
|
-
'dateRange.preset.last_month': 'Letzter Monat',
|
|
33
|
-
'dateRange.preset.last_3_months': 'Letzte 3 Monate',
|
|
34
|
-
'dateRange.preset.last_6_months': 'Letzte 6 Monate',
|
|
35
|
-
'dateRange.preset.last_12_months': 'Letzte 12 Monate',
|
|
36
|
-
'dateRange.preset.last_24_months': 'Letzte 24 Monate',
|
|
37
|
-
'dateRange.preset.last_36_months': 'Letzte 36 Monate',
|
|
38
|
-
'dateRange.preset.this_year': 'Dieses Jahr',
|
|
39
|
-
'dateRange.preset.last_year': 'Letztes Jahr',
|
|
40
|
-
'dateRange.preset.all_time': 'Gesamter Zeitraum',
|
|
41
|
-
'dateRange.preset.custom': 'Benutzerdefiniert',
|
|
42
|
-
'dateRange.preset.next_3_months': 'Nächste 3 Monate',
|
|
43
|
-
'dateRange.preset.next_6_months': 'Nächste 6 Monate',
|
|
44
|
-
'dateRange.preset.next_12_months': 'Nächste 12 Monate',
|
|
45
|
-
'dateRange.preset.this_quarter': 'Dieses Quartal',
|
|
46
|
-
'dateRange.preset.next_quarter': 'Nächstes Quartal',
|
|
47
|
-
'dateRange.preset.rolling_12_months': 'Rollende 12 Monate',
|
|
48
24
|
|
|
49
25
|
// OrganisationList page
|
|
50
26
|
'orgList.title': 'Organisationen',
|
|
@@ -17,34 +17,10 @@ export default {
|
|
|
17
17
|
// Table widget
|
|
18
18
|
|
|
19
19
|
// CheckboxList widget
|
|
20
|
-
'checkboxList.selectAll': 'Select all',
|
|
21
|
-
'checkboxList.deselectAll': 'Deselect all',
|
|
22
20
|
|
|
23
21
|
// Sidepanel
|
|
24
|
-
'sidepanel.collapse': 'Collapse panel',
|
|
25
|
-
'sidepanel.expand': 'Expand panel',
|
|
26
22
|
|
|
27
23
|
// DateRangePicker presets
|
|
28
|
-
'dateRange.period': 'Period:',
|
|
29
|
-
'dateRange.from': 'From',
|
|
30
|
-
'dateRange.to': 'To',
|
|
31
|
-
'dateRange.preset.this_month': 'This month',
|
|
32
|
-
'dateRange.preset.last_month': 'Last month',
|
|
33
|
-
'dateRange.preset.last_3_months': 'Last 3 months',
|
|
34
|
-
'dateRange.preset.last_6_months': 'Last 6 months',
|
|
35
|
-
'dateRange.preset.last_12_months': 'Last 12 months',
|
|
36
|
-
'dateRange.preset.last_24_months': 'Last 24 months',
|
|
37
|
-
'dateRange.preset.last_36_months': 'Last 36 months',
|
|
38
|
-
'dateRange.preset.this_year': 'This year',
|
|
39
|
-
'dateRange.preset.last_year': 'Last year',
|
|
40
|
-
'dateRange.preset.all_time': 'All time',
|
|
41
|
-
'dateRange.preset.custom': 'Custom',
|
|
42
|
-
'dateRange.preset.next_3_months': 'Next 3 months',
|
|
43
|
-
'dateRange.preset.next_6_months': 'Next 6 months',
|
|
44
|
-
'dateRange.preset.next_12_months': 'Next 12 months',
|
|
45
|
-
'dateRange.preset.this_quarter': 'This quarter',
|
|
46
|
-
'dateRange.preset.next_quarter': 'Next quarter',
|
|
47
|
-
'dateRange.preset.rolling_12_months': 'Rolling 12 months',
|
|
48
24
|
|
|
49
25
|
// Auth dialog
|
|
50
26
|
'auth.dialog.title': 'Sensolus API key required',
|
|
@@ -17,34 +17,10 @@ export default {
|
|
|
17
17
|
// Table widget
|
|
18
18
|
|
|
19
19
|
// CheckboxList widget
|
|
20
|
-
'checkboxList.selectAll': 'Seleccionar todo',
|
|
21
|
-
'checkboxList.deselectAll': 'Deseleccionar todo',
|
|
22
20
|
|
|
23
21
|
// Sidepanel
|
|
24
|
-
'sidepanel.collapse': 'Contraer panel',
|
|
25
|
-
'sidepanel.expand': 'Expandir panel',
|
|
26
22
|
|
|
27
23
|
// DateRangePicker presets
|
|
28
|
-
'dateRange.period': 'Período:',
|
|
29
|
-
'dateRange.from': 'Desde',
|
|
30
|
-
'dateRange.to': 'Hasta',
|
|
31
|
-
'dateRange.preset.this_month': 'Este mes',
|
|
32
|
-
'dateRange.preset.last_month': 'Mes pasado',
|
|
33
|
-
'dateRange.preset.last_3_months': 'Últimos 3 meses',
|
|
34
|
-
'dateRange.preset.last_6_months': 'Últimos 6 meses',
|
|
35
|
-
'dateRange.preset.last_12_months': 'Últimos 12 meses',
|
|
36
|
-
'dateRange.preset.last_24_months': 'Últimos 24 meses',
|
|
37
|
-
'dateRange.preset.last_36_months': 'Últimos 36 meses',
|
|
38
|
-
'dateRange.preset.this_year': 'Este año',
|
|
39
|
-
'dateRange.preset.last_year': 'Año pasado',
|
|
40
|
-
'dateRange.preset.all_time': 'Todo el período',
|
|
41
|
-
'dateRange.preset.custom': 'Personalizado',
|
|
42
|
-
'dateRange.preset.next_3_months': 'Próximos 3 meses',
|
|
43
|
-
'dateRange.preset.next_6_months': 'Próximos 6 meses',
|
|
44
|
-
'dateRange.preset.next_12_months': 'Próximos 12 meses',
|
|
45
|
-
'dateRange.preset.this_quarter': 'Este trimestre',
|
|
46
|
-
'dateRange.preset.next_quarter': 'Próximo trimestre',
|
|
47
|
-
'dateRange.preset.rolling_12_months': '12 meses continuos',
|
|
48
24
|
|
|
49
25
|
// OrganisationList page
|
|
50
26
|
'orgList.title': 'Organizaciones',
|
|
@@ -17,34 +17,10 @@ export default {
|
|
|
17
17
|
// Table widget
|
|
18
18
|
|
|
19
19
|
// CheckboxList widget
|
|
20
|
-
'checkboxList.selectAll': 'Tout sélectionner',
|
|
21
|
-
'checkboxList.deselectAll': 'Tout désélectionner',
|
|
22
20
|
|
|
23
21
|
// Sidepanel
|
|
24
|
-
'sidepanel.collapse': 'Réduire le panneau',
|
|
25
|
-
'sidepanel.expand': 'Développer le panneau',
|
|
26
22
|
|
|
27
23
|
// DateRangePicker presets
|
|
28
|
-
'dateRange.period': 'Période :',
|
|
29
|
-
'dateRange.from': 'Du',
|
|
30
|
-
'dateRange.to': 'Au',
|
|
31
|
-
'dateRange.preset.this_month': 'Ce mois-ci',
|
|
32
|
-
'dateRange.preset.last_month': 'Le mois dernier',
|
|
33
|
-
'dateRange.preset.last_3_months': '3 derniers mois',
|
|
34
|
-
'dateRange.preset.last_6_months': '6 derniers mois',
|
|
35
|
-
'dateRange.preset.last_12_months': '12 derniers mois',
|
|
36
|
-
'dateRange.preset.last_24_months': '24 derniers mois',
|
|
37
|
-
'dateRange.preset.last_36_months': '36 derniers mois',
|
|
38
|
-
'dateRange.preset.this_year': 'Cette année',
|
|
39
|
-
'dateRange.preset.last_year': 'L\'année dernière',
|
|
40
|
-
'dateRange.preset.all_time': 'Tout',
|
|
41
|
-
'dateRange.preset.custom': 'Personnalisé',
|
|
42
|
-
'dateRange.preset.next_3_months': '3 prochains mois',
|
|
43
|
-
'dateRange.preset.next_6_months': '6 prochains mois',
|
|
44
|
-
'dateRange.preset.next_12_months': '12 prochains mois',
|
|
45
|
-
'dateRange.preset.this_quarter': 'Ce trimestre',
|
|
46
|
-
'dateRange.preset.next_quarter': 'Trimestre prochain',
|
|
47
|
-
'dateRange.preset.rolling_12_months': '12 mois glissants',
|
|
48
24
|
|
|
49
25
|
// OrganisationList page
|
|
50
26
|
'orgList.title': 'Organisations',
|
|
@@ -17,34 +17,10 @@ export default {
|
|
|
17
17
|
// Table widget
|
|
18
18
|
|
|
19
19
|
// CheckboxList widget
|
|
20
|
-
'checkboxList.selectAll': 'Alles selecteren',
|
|
21
|
-
'checkboxList.deselectAll': 'Alles deselecteren',
|
|
22
20
|
|
|
23
21
|
// Sidepanel
|
|
24
|
-
'sidepanel.collapse': 'Paneel inklappen',
|
|
25
|
-
'sidepanel.expand': 'Paneel uitklappen',
|
|
26
22
|
|
|
27
23
|
// DateRangePicker presets
|
|
28
|
-
'dateRange.period': 'Periode:',
|
|
29
|
-
'dateRange.from': 'Van',
|
|
30
|
-
'dateRange.to': 'Tot',
|
|
31
|
-
'dateRange.preset.this_month': 'Deze maand',
|
|
32
|
-
'dateRange.preset.last_month': 'Vorige maand',
|
|
33
|
-
'dateRange.preset.last_3_months': 'Laatste 3 maanden',
|
|
34
|
-
'dateRange.preset.last_6_months': 'Laatste 6 maanden',
|
|
35
|
-
'dateRange.preset.last_12_months': 'Laatste 12 maanden',
|
|
36
|
-
'dateRange.preset.last_24_months': 'Laatste 24 maanden',
|
|
37
|
-
'dateRange.preset.last_36_months': 'Laatste 36 maanden',
|
|
38
|
-
'dateRange.preset.this_year': 'Dit jaar',
|
|
39
|
-
'dateRange.preset.last_year': 'Vorig jaar',
|
|
40
|
-
'dateRange.preset.all_time': 'Alles',
|
|
41
|
-
'dateRange.preset.custom': 'Aangepast',
|
|
42
|
-
'dateRange.preset.next_3_months': 'Volgende 3 maanden',
|
|
43
|
-
'dateRange.preset.next_6_months': 'Volgende 6 maanden',
|
|
44
|
-
'dateRange.preset.next_12_months': 'Volgende 12 maanden',
|
|
45
|
-
'dateRange.preset.this_quarter': 'Dit kwartaal',
|
|
46
|
-
'dateRange.preset.next_quarter': 'Volgend kwartaal',
|
|
47
|
-
'dateRange.preset.rolling_12_months': 'Rollende 12 maanden',
|
|
48
24
|
|
|
49
25
|
// OrganisationList page
|
|
50
26
|
'orgList.title': 'Organisaties',
|
package/template/src/main.jsx
CHANGED
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import ReactDOM from 'react-dom/client'
|
|
3
3
|
import App from './App'
|
|
4
|
-
import { LocaleProvider, messages } from './i18n'
|
|
5
4
|
import '@sensolus/snt-agent-kit/theme.css'
|
|
6
5
|
import './styles/app.css'
|
|
7
6
|
|
|
8
7
|
ReactDOM.createRoot(document.getElementById('root')).render(
|
|
9
8
|
<React.StrictMode>
|
|
10
|
-
<
|
|
11
|
-
<App />
|
|
12
|
-
</LocaleProvider>
|
|
9
|
+
<App />
|
|
13
10
|
</React.StrictMode>
|
|
14
11
|
)
|
|
@@ -9,10 +9,12 @@ import {
|
|
|
9
9
|
SntSpinner,
|
|
10
10
|
} from '@sensolus/snt-agent-kit'
|
|
11
11
|
import { useLocale, formatNumber } from '../i18n'
|
|
12
|
+
import { useAppConfig } from '../AppConfigContext'
|
|
12
13
|
|
|
13
14
|
export function OrganisationDetail() {
|
|
14
15
|
const { id } = useParams()
|
|
15
16
|
const { t, intlLocale } = useLocale()
|
|
17
|
+
const config = useAppConfig()
|
|
16
18
|
|
|
17
19
|
// Try to get org data from sessionStorage
|
|
18
20
|
const organisation = useMemo(() => {
|
|
@@ -213,6 +215,8 @@ export function OrganisationDetail() {
|
|
|
213
215
|
</div>
|
|
214
216
|
) : (
|
|
215
217
|
<SntMap
|
|
218
|
+
mapboxKey={config.mapboxKey}
|
|
219
|
+
locationiqKey={config.locationiqKey}
|
|
216
220
|
height="500px"
|
|
217
221
|
devices={devices}
|
|
218
222
|
orgId={id}
|
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
SntToolbarSpacer,
|
|
29
29
|
getDefaultDateRange,
|
|
30
30
|
} from '@sensolus/snt-agent-kit'
|
|
31
|
+
import { useAppConfig } from '../AppConfigContext'
|
|
31
32
|
|
|
32
33
|
function Section({ title, description, children }) {
|
|
33
34
|
return (
|
|
@@ -88,12 +89,13 @@ const TAB_DEFS = [
|
|
|
88
89
|
]
|
|
89
90
|
|
|
90
91
|
export function WidgetShowcase() {
|
|
92
|
+
const config = useAppConfig()
|
|
91
93
|
const [inputValue, setInputValue] = useState('Hello world')
|
|
92
94
|
const [selectValue, setSelectValue] = useState('eu')
|
|
93
95
|
const [groupValue, setGroupValue] = useState('cards')
|
|
94
96
|
const [switchOn, setSwitchOn] = useState(true)
|
|
95
97
|
const [checkboxSelected, setCheckboxSelected] = useState(['Trackers', 'Geozones'])
|
|
96
|
-
const [dateRange, setDateRange] = useState(() => getDefaultDateRange('
|
|
98
|
+
const [dateRange, setDateRange] = useState(() => getDefaultDateRange('week'))
|
|
97
99
|
const [dialogOpen, setDialogOpen] = useState(false)
|
|
98
100
|
const [showOverlay, setShowOverlay] = useState(false)
|
|
99
101
|
const [sidepanelOpen, setSidepanelOpen] = useState(true)
|
|
@@ -245,14 +247,10 @@ export function WidgetShowcase() {
|
|
|
245
247
|
{/* ------------------------------------------------------------------ */}
|
|
246
248
|
<Section
|
|
247
249
|
title="SntDateRangePicker"
|
|
248
|
-
description="Range selection with
|
|
250
|
+
description="Range selection with day / week / month / custom modes. Value is { viewMode, start, end } as JS Dates."
|
|
249
251
|
>
|
|
250
|
-
<Example label={`Current: ${dateRange.
|
|
251
|
-
<SntDateRangePicker
|
|
252
|
-
from={dateRange.from}
|
|
253
|
-
to={dateRange.to}
|
|
254
|
-
onChange={setDateRange}
|
|
255
|
-
/>
|
|
252
|
+
<Example label={`Current: ${dateRange.start.toDateString()} → ${dateRange.end.toDateString()} (${dateRange.viewMode})`}>
|
|
253
|
+
<SntDateRangePicker value={dateRange} onChange={setDateRange} />
|
|
256
254
|
</Example>
|
|
257
255
|
</Section>
|
|
258
256
|
|
|
@@ -487,6 +485,8 @@ export function WidgetShowcase() {
|
|
|
487
485
|
description="Leaflet map with Street/Satellite layer toggle. Optionally renders geozones (by orgId or array) and device markers."
|
|
488
486
|
>
|
|
489
487
|
<SntMap
|
|
488
|
+
mapboxKey={config.mapboxKey}
|
|
489
|
+
locationiqKey={config.locationiqKey}
|
|
490
490
|
height="320px"
|
|
491
491
|
center={[50.85, 4.35]}
|
|
492
492
|
zoom={6}
|