@burdenoff/microfe-ecoimpacthub 2026.704.4 → 2026.709.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.
- package/dist/dev/main.d.ts +2 -0
- package/dist/dev/main.d.ts.map +1 -0
- package/dist/ecoimpacthub/EcoImpactHubRoot.d.ts +5 -0
- package/dist/ecoimpacthub/EcoImpactHubRoot.d.ts.map +1 -0
- package/dist/ecoimpacthub/EcoImpactHubRoutes.d.ts +4 -0
- package/dist/ecoimpacthub/EcoImpactHubRoutes.d.ts.map +1 -0
- package/dist/ecoimpacthub/EcoImpactHubRoutes.js +48 -40
- package/dist/ecoimpacthub/EcoImpactHubRoutes.js.map +1 -1
- package/dist/ecoimpacthub/components/DataTable.d.ts +28 -0
- package/dist/ecoimpacthub/components/DataTable.d.ts.map +1 -0
- package/dist/ecoimpacthub/components/EcoDiscussion.d.ts +18 -0
- package/dist/ecoimpacthub/components/EcoDiscussion.d.ts.map +1 -0
- package/dist/ecoimpacthub/components/EcoTags.d.ts +17 -0
- package/dist/ecoimpacthub/components/EcoTags.d.ts.map +1 -0
- package/dist/ecoimpacthub/components/EmptyState.d.ts +18 -0
- package/dist/ecoimpacthub/components/EmptyState.d.ts.map +1 -0
- package/dist/ecoimpacthub/components/EvidenceUpload.d.ts +14 -0
- package/dist/ecoimpacthub/components/EvidenceUpload.d.ts.map +1 -0
- package/dist/ecoimpacthub/components/FeatureFlagGate.d.ts +10 -0
- package/dist/ecoimpacthub/components/FeatureFlagGate.d.ts.map +1 -0
- package/dist/ecoimpacthub/components/FeatureFlagGate.js +8 -0
- package/dist/ecoimpacthub/components/FeatureFlagGate.js.map +1 -0
- package/dist/ecoimpacthub/components/FileLink.d.ts +15 -0
- package/dist/ecoimpacthub/components/FileLink.d.ts.map +1 -0
- package/dist/ecoimpacthub/components/FilterTabs.d.ts +18 -0
- package/dist/ecoimpacthub/components/FilterTabs.d.ts.map +1 -0
- package/dist/ecoimpacthub/components/MetricsCard.d.ts +23 -0
- package/dist/ecoimpacthub/components/MetricsCard.d.ts.map +1 -0
- package/dist/ecoimpacthub/components/MiniBar.d.ts +16 -0
- package/dist/ecoimpacthub/components/MiniBar.d.ts.map +1 -0
- package/dist/ecoimpacthub/components/PageLayout.d.ts +16 -0
- package/dist/ecoimpacthub/components/PageLayout.d.ts.map +1 -0
- package/dist/ecoimpacthub/components/Pagination.d.ts +22 -0
- package/dist/ecoimpacthub/components/Pagination.d.ts.map +1 -0
- package/dist/ecoimpacthub/components/StateViews.d.ts +24 -0
- package/dist/ecoimpacthub/components/StateViews.d.ts.map +1 -0
- package/dist/ecoimpacthub/components/StatusBadge.d.ts +9 -0
- package/dist/ecoimpacthub/components/StatusBadge.d.ts.map +1 -0
- package/dist/ecoimpacthub/components/Tabs.d.ts +17 -0
- package/dist/ecoimpacthub/components/Tabs.d.ts.map +1 -0
- package/dist/ecoimpacthub/components/index.d.ts +19 -0
- package/dist/ecoimpacthub/components/index.d.ts.map +1 -0
- package/dist/ecoimpacthub/context/EcoImpactHubContext.d.ts +16 -0
- package/dist/ecoimpacthub/context/EcoImpactHubContext.d.ts.map +1 -0
- package/dist/ecoimpacthub/context/index.d.ts +6 -0
- package/dist/ecoimpacthub/context/index.d.ts.map +1 -0
- package/dist/ecoimpacthub/hooks/index.d.ts +10 -0
- package/dist/ecoimpacthub/hooks/index.d.ts.map +1 -0
- package/dist/ecoimpacthub/hooks/useCursorPager.d.ts +33 -0
- package/dist/ecoimpacthub/hooks/useCursorPager.d.ts.map +1 -0
- package/dist/ecoimpacthub/hooks/useEcoComments.d.ts +36 -0
- package/dist/ecoimpacthub/hooks/useEcoComments.d.ts.map +1 -0
- package/dist/ecoimpacthub/hooks/useEcoFiles.d.ts +47 -0
- package/dist/ecoimpacthub/hooks/useEcoFiles.d.ts.map +1 -0
- package/dist/ecoimpacthub/hooks/useEcoImpactHubApi.d.ts +104 -0
- package/dist/ecoimpacthub/hooks/useEcoImpactHubApi.d.ts.map +1 -0
- package/dist/ecoimpacthub/hooks/useEcoTags.d.ts +44 -0
- package/dist/ecoimpacthub/hooks/useEcoTags.d.ts.map +1 -0
- package/dist/ecoimpacthub/index.d.ts +10 -0
- package/dist/ecoimpacthub/index.d.ts.map +1 -0
- package/dist/ecoimpacthub/index.js +2 -0
- package/dist/ecoimpacthub/pages/DashboardPage.d.ts +10 -0
- package/dist/ecoimpacthub/pages/DashboardPage.d.ts.map +1 -0
- package/dist/ecoimpacthub/pages/DashboardPage.js +345 -189
- package/dist/ecoimpacthub/pages/DashboardPage.js.map +1 -1
- package/dist/ecoimpacthub/pages/_shared/ConservationBadge.d.ts +9 -0
- package/dist/ecoimpacthub/pages/_shared/ConservationBadge.d.ts.map +1 -0
- package/dist/ecoimpacthub/pages/_shared/ConservationBadge.js +58 -0
- package/dist/ecoimpacthub/pages/_shared/ConservationBadge.js.map +1 -0
- package/dist/ecoimpacthub/pages/_shared/EvidenceThumb.d.ts +23 -0
- package/dist/ecoimpacthub/pages/_shared/EvidenceThumb.d.ts.map +1 -0
- package/dist/ecoimpacthub/pages/_shared/EvidenceThumb.js +70 -0
- package/dist/ecoimpacthub/pages/_shared/EvidenceThumb.js.map +1 -0
- package/dist/ecoimpacthub/pages/_shared/MethodBadge.d.ts +9 -0
- package/dist/ecoimpacthub/pages/_shared/MethodBadge.d.ts.map +1 -0
- package/dist/ecoimpacthub/pages/_shared/MethodBadge.js +51 -0
- package/dist/ecoimpacthub/pages/_shared/MethodBadge.js.map +1 -0
- package/dist/ecoimpacthub/pages/_shared/TaxonChip.d.ts +9 -0
- package/dist/ecoimpacthub/pages/_shared/TaxonChip.d.ts.map +1 -0
- package/dist/ecoimpacthub/pages/_shared/TaxonChip.js +29 -0
- package/dist/ecoimpacthub/pages/_shared/TaxonChip.js.map +1 -0
- package/dist/ecoimpacthub/pages/badges.d.ts +27 -0
- package/dist/ecoimpacthub/pages/badges.d.ts.map +1 -0
- package/dist/ecoimpacthub/pages/badges.js +71 -0
- package/dist/ecoimpacthub/pages/badges.js.map +1 -0
- package/dist/ecoimpacthub/pages/carbon/CarbonPage.d.ts +15 -0
- package/dist/ecoimpacthub/pages/carbon/CarbonPage.d.ts.map +1 -0
- package/dist/ecoimpacthub/pages/carbon/CarbonPage.js +337 -300
- package/dist/ecoimpacthub/pages/carbon/CarbonPage.js.map +1 -1
- package/dist/ecoimpacthub/pages/carbonVisuals.d.ts +47 -0
- package/dist/ecoimpacthub/pages/carbonVisuals.d.ts.map +1 -0
- package/dist/ecoimpacthub/pages/carbonVisuals.js +89 -0
- package/dist/ecoimpacthub/pages/carbonVisuals.js.map +1 -0
- package/dist/ecoimpacthub/pages/habitat/HabitatProjectDetailPage.d.ts +12 -0
- package/dist/ecoimpacthub/pages/habitat/HabitatProjectDetailPage.d.ts.map +1 -0
- package/dist/ecoimpacthub/pages/habitat/HabitatProjectDetailPage.js +252 -218
- package/dist/ecoimpacthub/pages/habitat/HabitatProjectDetailPage.js.map +1 -1
- package/dist/ecoimpacthub/pages/habitat/HabitatProjectsPage.d.ts +8 -0
- package/dist/ecoimpacthub/pages/habitat/HabitatProjectsPage.d.ts.map +1 -0
- package/dist/ecoimpacthub/pages/habitat/HabitatProjectsPage.js +15 -12
- package/dist/ecoimpacthub/pages/habitat/HabitatProjectsPage.js.map +1 -1
- package/dist/ecoimpacthub/pages/habitat/LifecycleProgress.d.ts +6 -0
- package/dist/ecoimpacthub/pages/habitat/LifecycleProgress.d.ts.map +1 -0
- package/dist/ecoimpacthub/pages/habitat/LifecycleProgress.js +168 -0
- package/dist/ecoimpacthub/pages/habitat/LifecycleProgress.js.map +1 -0
- package/dist/ecoimpacthub/pages/monitoring/MonitoringPage.d.ts +12 -0
- package/dist/ecoimpacthub/pages/monitoring/MonitoringPage.d.ts.map +1 -0
- package/dist/ecoimpacthub/pages/monitoring/MonitoringPage.js +30 -17
- package/dist/ecoimpacthub/pages/monitoring/MonitoringPage.js.map +1 -1
- package/dist/ecoimpacthub/pages/observations/ObservationsPage.d.ts +11 -0
- package/dist/ecoimpacthub/pages/observations/ObservationsPage.d.ts.map +1 -0
- package/dist/ecoimpacthub/pages/observations/ObservationsPage.js +236 -219
- package/dist/ecoimpacthub/pages/observations/ObservationsPage.js.map +1 -1
- package/dist/ecoimpacthub/pages/reports/ReportDetailPage.d.ts +11 -0
- package/dist/ecoimpacthub/pages/reports/ReportDetailPage.d.ts.map +1 -0
- package/dist/ecoimpacthub/pages/reports/ReportDetailPage.js +248 -212
- package/dist/ecoimpacthub/pages/reports/ReportDetailPage.js.map +1 -1
- package/dist/ecoimpacthub/pages/reports/ReportsPage.d.ts +8 -0
- package/dist/ecoimpacthub/pages/reports/ReportsPage.d.ts.map +1 -0
- package/dist/ecoimpacthub/pages/reports/ReportsPage.js +119 -118
- package/dist/ecoimpacthub/pages/reports/ReportsPage.js.map +1 -1
- package/dist/ecoimpacthub/pages/sites/SiteDetailPage.d.ts +10 -0
- package/dist/ecoimpacthub/pages/sites/SiteDetailPage.d.ts.map +1 -0
- package/dist/ecoimpacthub/pages/sites/SiteDetailPage.js +498 -370
- package/dist/ecoimpacthub/pages/sites/SiteDetailPage.js.map +1 -1
- package/dist/ecoimpacthub/pages/sites/SitesPage.d.ts +8 -0
- package/dist/ecoimpacthub/pages/sites/SitesPage.d.ts.map +1 -0
- package/dist/ecoimpacthub/pages/sites/SitesPage.js +109 -99
- package/dist/ecoimpacthub/pages/sites/SitesPage.js.map +1 -1
- package/dist/ecoimpacthub/pages/sites/siteTypeVisuals.d.ts +22 -0
- package/dist/ecoimpacthub/pages/sites/siteTypeVisuals.d.ts.map +1 -0
- package/dist/ecoimpacthub/pages/sites/siteTypeVisuals.js +64 -0
- package/dist/ecoimpacthub/pages/sites/siteTypeVisuals.js.map +1 -0
- package/dist/ecoimpacthub/pages/species/SpeciesDetailPage.d.ts +9 -0
- package/dist/ecoimpacthub/pages/species/SpeciesDetailPage.d.ts.map +1 -0
- package/dist/ecoimpacthub/pages/species/SpeciesDetailPage.js +275 -259
- package/dist/ecoimpacthub/pages/species/SpeciesDetailPage.js.map +1 -1
- package/dist/ecoimpacthub/pages/species/SpeciesPage.d.ts +8 -0
- package/dist/ecoimpacthub/pages/species/SpeciesPage.d.ts.map +1 -0
- package/dist/ecoimpacthub/pages/species/SpeciesPage.js +235 -177
- package/dist/ecoimpacthub/pages/species/SpeciesPage.js.map +1 -1
- package/dist/ecoimpacthub/services/createSandboxAssistantTransport.d.ts +33 -0
- package/dist/ecoimpacthub/services/createSandboxAssistantTransport.d.ts.map +1 -0
- package/dist/ecoimpacthub/services/createSandboxAssistantTransport.js +42 -0
- package/dist/ecoimpacthub/services/createSandboxAssistantTransport.js.map +1 -0
- package/dist/ecoimpacthub/services/index.d.ts +6 -0
- package/dist/ecoimpacthub/services/index.d.ts.map +1 -0
- package/dist/ecoimpacthub/services/index.js +1 -0
- package/dist/ecoimpacthub/types/index.d.ts +417 -0
- package/dist/ecoimpacthub/types/index.d.ts.map +1 -0
- package/dist/ecoimpacthub/utils/cn.d.ts +4 -0
- package/dist/ecoimpacthub/utils/cn.d.ts.map +1 -0
- package/dist/ecoimpacthub/utils/formatters.d.ts +26 -0
- package/dist/ecoimpacthub/utils/formatters.d.ts.map +1 -0
- package/dist/ecoimpacthub/utils/i18n.d.ts +6 -0
- package/dist/ecoimpacthub/utils/i18n.d.ts.map +1 -0
- package/dist/ecoimpacthub/utils/index.d.ts +9 -0
- package/dist/ecoimpacthub/utils/index.d.ts.map +1 -0
- package/dist/ecoimpacthub/utils/navigation.d.ts +14 -0
- package/dist/ecoimpacthub/utils/navigation.d.ts.map +1 -0
- package/dist/generated/global-operations.d.ts +2 -0
- package/dist/generated/global-operations.d.ts.map +1 -0
- package/dist/generated/global-types.d.ts +18199 -0
- package/dist/generated/global-types.d.ts.map +1 -0
- package/dist/generated/wspace-operations.d.ts +2 -0
- package/dist/generated/wspace-operations.d.ts.map +1 -0
- package/dist/generated/wspace-types.d.ts +43046 -0
- package/dist/generated/wspace-types.d.ts.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -1
- package/dist/node_modules/recharts/es6/cartesian/CartesianGrid.js +305 -0
- package/dist/node_modules/recharts/es6/cartesian/CartesianGrid.js.map +1 -0
- package/dist/node_modules/recharts/es6/context/chartLayoutContext.js +44 -33
- package/dist/node_modules/recharts/es6/context/chartLayoutContext.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/ChartUtils.js +31 -23
- package/dist/node_modules/recharts/es6/util/ChartUtils.js.map +1 -1
- package/package.json +5 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SpeciesPage.js","names":[],"sources":["../../../../src/ecoimpacthub/pages/species/SpeciesPage.tsx"],"sourcesContent":["/**\n * Species — list, filter, and register tracked taxa.\n * @module ecoimpacthub/pages/species\n *\n * Reads `ecoListSpecies`; writes `ecoCreateSpecies`.\n */\n\nimport { useMemo, useState } from 'react';\nimport { Plus, Rabbit, Star } from 'lucide-react';\nimport {\n Button,\n Input,\n Label,\n Textarea,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { DataTable, type Column } from '../../components/DataTable';\nimport { FilterTabs, type FilterOption } from '../../components/FilterTabs';\nimport { LoadingView, ErrorView } from '../../components/StateViews';\nimport { EmptyState } from '../../components/EmptyState';\nimport { Pagination } from '../../components/Pagination';\nimport { useEcoImpactHub } from '../../context';\nimport { useEcoSpecies, useEcoCreateSpecies, useCursorPager } from '../../hooks';\nimport { formatEnumLabel, formatRelativeTime } from '../../utils/formatters';\nimport type { EcoSpecies, EcoTaxonGroup, EcoConservationStatus } from '../../types';\n\nconst TAXON_GROUPS: EcoTaxonGroup[] = [\n 'MAMMAL',\n 'BIRD',\n 'REPTILE',\n 'AMPHIBIAN',\n 'FISH',\n 'INSECT',\n 'PLANT',\n 'FUNGI',\n 'OTHER',\n];\n\nconst CONSERVATION_STATUSES: EcoConservationStatus[] = [\n 'LEAST_CONCERN',\n 'NEAR_THREATENED',\n 'VULNERABLE',\n 'ENDANGERED',\n 'CRITICALLY_ENDANGERED',\n 'EXTINCT_IN_WILD',\n 'DATA_DEFICIENT',\n 'NOT_EVALUATED',\n];\n\nconst PRIORITY_FILTERS: FilterOption<'ALL' | 'PRIORITY'>[] = [\n { value: 'ALL', label: 'All species' },\n { value: 'PRIORITY', label: 'Priority only' },\n];\n\nconst PAGE_SIZE = 25;\n\ninterface CreateFormState {\n commonName: string;\n scientificName: string;\n taxonGroup: EcoTaxonGroup;\n conservationStatus: EcoConservationStatus;\n isPriority: boolean;\n description: string;\n}\n\nconst EMPTY_FORM: CreateFormState = {\n commonName: '',\n scientificName: '',\n taxonGroup: 'MAMMAL',\n conservationStatus: 'NOT_EVALUATED',\n isPriority: false,\n description: '',\n};\n\nexport function SpeciesPage() {\n const { navigateTo } = useEcoImpactHub();\n const [taxonGroup, setTaxonGroup] = useState<EcoTaxonGroup | 'ALL'>('ALL');\n const [conservationStatus, setConservationStatus] = useState<EcoConservationStatus | 'ALL'>(\n 'ALL'\n );\n const [priority, setPriority] = useState<'ALL' | 'PRIORITY'>('ALL');\n const pager = useCursorPager();\n const [dialogOpen, setDialogOpen] = useState(false);\n const [form, setForm] = useState<CreateFormState>(EMPTY_FORM);\n const [formError, setFormError] = useState<string | null>(null);\n\n const { data, isLoading, isError, refetch } = useEcoSpecies({\n taxonGroup: taxonGroup === 'ALL' ? undefined : taxonGroup,\n conservationStatus: conservationStatus === 'ALL' ? undefined : conservationStatus,\n priorityOnly: priority === 'PRIORITY' ? true : undefined,\n pagination: { limit: PAGE_SIZE, cursor: pager.cursor },\n });\n const createSpecies = useEcoCreateSpecies();\n\n const rows = useMemo(() => data?.items ?? [], [data]);\n\n const columns: Column<EcoSpecies>[] = [\n {\n key: 'name',\n header: 'Species',\n render: (s) => (\n <div>\n <p className=\"font-semibold text-text-primary\">{s.commonName}</p>\n {s.scientificName && (\n <p className=\"text-xs italic text-text-tertiary\">{s.scientificName}</p>\n )}\n </div>\n ),\n },\n {\n key: 'taxonGroup',\n header: 'Group',\n hideOnMobile: true,\n render: (s) => <span className=\"text-text-secondary\">{formatEnumLabel(s.taxonGroup)}</span>,\n },\n {\n key: 'conservationStatus',\n header: 'Conservation',\n render: (s) => <StatusBadge status={s.conservationStatus} />,\n },\n {\n key: 'priority',\n header: 'Priority',\n align: 'center',\n render: (s) =>\n s.isPriority ? (\n <span\n className=\"inline-flex justify-center text-status-warning-text\"\n title=\"Priority species\"\n >\n <Star className=\"h-4 w-4 fill-current\" />\n </span>\n ) : null,\n },\n {\n key: 'updated',\n header: 'Updated',\n align: 'right',\n hideOnMobile: true,\n render: (s) => <span className=\"text-text-tertiary\">{formatRelativeTime(s.updatedAt)}</span>,\n },\n ];\n\n const resetForm = () => {\n setForm(EMPTY_FORM);\n setFormError(null);\n };\n\n const handleCreate = async () => {\n if (!form.commonName.trim()) {\n setFormError('Common name is required.');\n return;\n }\n try {\n const created = await createSpecies.mutateAsync({\n commonName: form.commonName.trim(),\n scientificName: form.scientificName.trim() || null,\n taxonGroup: form.taxonGroup,\n conservationStatus: form.conservationStatus,\n isPriority: form.isPriority,\n description: form.description.trim() || null,\n });\n setDialogOpen(false);\n resetForm();\n navigateTo(`species/${created.id}`);\n } catch (err) {\n setFormError(err instanceof Error ? err.message : 'Failed to create species.');\n }\n };\n\n return (\n <PageLayout\n title=\"Species\"\n description=\"Tracked taxa — conservation status, priority focus & field observations.\"\n actions={\n <Button onClick={() => setDialogOpen(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> New species\n </Button>\n }\n >\n <div className=\"mb-5 flex flex-wrap items-center gap-3\">\n <FilterTabs\n options={PRIORITY_FILTERS}\n value={priority}\n onChange={(v) => {\n setPriority(v);\n pager.reset();\n }}\n />\n <Select\n value={taxonGroup}\n onValueChange={(v) => {\n setTaxonGroup(v as EcoTaxonGroup | 'ALL');\n pager.reset();\n }}\n >\n <SelectTrigger className=\"w-44\">\n <SelectValue placeholder=\"All groups\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"ALL\">All groups</SelectItem>\n {TAXON_GROUPS.map((t) => (\n <SelectItem key={t} value={t}>\n {formatEnumLabel(t)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <Select\n value={conservationStatus}\n onValueChange={(v) => {\n setConservationStatus(v as EcoConservationStatus | 'ALL');\n pager.reset();\n }}\n >\n <SelectTrigger className=\"w-52\">\n <SelectValue placeholder=\"All conservation\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"ALL\">All conservation</SelectItem>\n {CONSERVATION_STATUSES.map((c) => (\n <SelectItem key={c} value={c}>\n {formatEnumLabel(c)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n {isLoading ? (\n <LoadingView label=\"Loading species…\" />\n ) : isError ? (\n <ErrorView message=\"Couldn't load species.\" onRetry={() => refetch()} />\n ) : rows.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Rabbit className=\"h-10 w-10\" />}\n title=\"No species yet\"\n description={\n taxonGroup === 'ALL' && conservationStatus === 'ALL' && priority === 'ALL'\n ? 'Register your first species to start logging field observations.'\n : 'No species match these filters.'\n }\n action={\n <Button onClick={() => setDialogOpen(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> New species\n </Button>\n }\n />\n ) : (\n <>\n <DataTable\n columns={columns}\n rows={rows}\n rowKey={(s) => s.id}\n onRowClick={(s) => navigateTo(`species/${s.id}`)}\n />\n <Pagination\n page={pager.page}\n pageSize={PAGE_SIZE}\n itemCount={rows.length}\n hasMore={data?.pageInfo?.hasMore ?? false}\n onPageChange={(target) => pager.onPageChange(target, data?.pageInfo?.cursor)}\n />\n </>\n )}\n\n <ResponsiveDialog\n open={dialogOpen}\n onOpenChange={(open) => {\n setDialogOpen(open);\n if (!open) resetForm();\n }}\n >\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>New species</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Register a taxon to track its conservation status and field observations.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n\n <div className=\"grid gap-4 py-2\">\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"commonName\">Common name *</Label>\n <Input\n id=\"commonName\"\n value={form.commonName}\n onChange={(e) => setForm({ ...form, commonName: e.target.value })}\n placeholder=\"Indian Pangolin\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"scientificName\">Scientific name</Label>\n <Input\n id=\"scientificName\"\n value={form.scientificName}\n onChange={(e) => setForm({ ...form, scientificName: e.target.value })}\n placeholder=\"Manis crassicaudata\"\n />\n </div>\n </div>\n\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"taxonGroup\">Taxon group</Label>\n <Select\n value={form.taxonGroup}\n onValueChange={(v) => setForm({ ...form, taxonGroup: v as EcoTaxonGroup })}\n >\n <SelectTrigger id=\"taxonGroup\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {TAXON_GROUPS.map((t) => (\n <SelectItem key={t} value={t}>\n {formatEnumLabel(t)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"conservationStatus\">Conservation status</Label>\n <Select\n value={form.conservationStatus}\n onValueChange={(v) =>\n setForm({ ...form, conservationStatus: v as EcoConservationStatus })\n }\n >\n <SelectTrigger id=\"conservationStatus\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {CONSERVATION_STATUSES.map((c) => (\n <SelectItem key={c} value={c}>\n {formatEnumLabel(c)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n\n <label className=\"flex items-center gap-2 text-sm text-text-primary\">\n <input\n type=\"checkbox\"\n checked={form.isPriority}\n onChange={(e) => setForm({ ...form, isPriority: e.target.checked })}\n className=\"h-4 w-4 rounded border-border-seam accent-action-primary-bg\"\n />\n Mark as priority species\n </label>\n\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"description\">Description</Label>\n <Textarea\n id=\"description\"\n value={form.description}\n onChange={(e) => setForm({ ...form, description: e.target.value })}\n placeholder=\"Optional notes on habitat, range or identification.\"\n rows={2}\n />\n </div>\n\n {formError && <p className=\"text-sm text-status-error-text\">{formError}</p>}\n </div>\n\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => setDialogOpen(false)}>\n Cancel\n </Button>\n <Button onClick={handleCreate} disabled={createSpecies.isPending}>\n {createSpecies.isPending ? 'Creating…' : 'Create species'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SpeciesPage.js","names":[],"sources":["../../../../src/ecoimpacthub/pages/species/SpeciesPage.tsx"],"sourcesContent":["/**\n * Species — list, filter, and register tracked taxa.\n * @module ecoimpacthub/pages/species\n *\n * Reads `ecoListSpecies`; writes `ecoCreateSpecies`.\n */\n\nimport { useMemo, useState } from 'react';\nimport { Plus, Rabbit, Search, Star } from 'lucide-react';\nimport {\n Button,\n GlassCard,\n Input,\n Label,\n Textarea,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { DataTable, type Column } from '../../components/DataTable';\nimport { FilterTabs, type FilterOption } from '../../components/FilterTabs';\nimport { LoadingView, ErrorView } from '../../components/StateViews';\nimport { EmptyState } from '../../components/EmptyState';\nimport { Pagination } from '../../components/Pagination';\nimport { ConservationBadge } from '../_shared/ConservationBadge';\nimport { TaxonChip } from '../_shared/TaxonChip';\nimport { useEcoImpactHub } from '../../context';\nimport { useEcoSpecies, useEcoCreateSpecies, useCursorPager } from '../../hooks';\nimport { formatEnumLabel, formatRelativeTime } from '../../utils/formatters';\nimport type { EcoSpecies, EcoTaxonGroup, EcoConservationStatus } from '../../types';\n\nconst TAXON_GROUPS: EcoTaxonGroup[] = [\n 'MAMMAL',\n 'BIRD',\n 'REPTILE',\n 'AMPHIBIAN',\n 'FISH',\n 'INSECT',\n 'PLANT',\n 'FUNGI',\n 'OTHER',\n];\n\nconst CONSERVATION_STATUSES: EcoConservationStatus[] = [\n 'LEAST_CONCERN',\n 'NEAR_THREATENED',\n 'VULNERABLE',\n 'ENDANGERED',\n 'CRITICALLY_ENDANGERED',\n 'EXTINCT_IN_WILD',\n 'DATA_DEFICIENT',\n 'NOT_EVALUATED',\n];\n\nconst PRIORITY_FILTERS: FilterOption<'ALL' | 'PRIORITY'>[] = [\n { value: 'ALL', label: 'All species' },\n { value: 'PRIORITY', label: 'Priority only' },\n];\n\nconst PAGE_SIZE = 25;\n\ninterface CreateFormState {\n commonName: string;\n scientificName: string;\n taxonGroup: EcoTaxonGroup;\n conservationStatus: EcoConservationStatus;\n isPriority: boolean;\n description: string;\n}\n\nconst EMPTY_FORM: CreateFormState = {\n commonName: '',\n scientificName: '',\n taxonGroup: 'MAMMAL',\n conservationStatus: 'NOT_EVALUATED',\n isPriority: false,\n description: '',\n};\n\nexport function SpeciesPage() {\n const { navigateTo } = useEcoImpactHub();\n const [taxonGroup, setTaxonGroup] = useState<EcoTaxonGroup | 'ALL'>('ALL');\n const [conservationStatus, setConservationStatus] = useState<EcoConservationStatus | 'ALL'>(\n 'ALL'\n );\n const [priority, setPriority] = useState<'ALL' | 'PRIORITY'>('ALL');\n const [search, setSearch] = useState('');\n const pager = useCursorPager();\n const [dialogOpen, setDialogOpen] = useState(false);\n const [form, setForm] = useState<CreateFormState>(EMPTY_FORM);\n const [formError, setFormError] = useState<string | null>(null);\n\n const { data, isLoading, isError, refetch } = useEcoSpecies({\n taxonGroup: taxonGroup === 'ALL' ? undefined : taxonGroup,\n conservationStatus: conservationStatus === 'ALL' ? undefined : conservationStatus,\n priorityOnly: priority === 'PRIORITY' ? true : undefined,\n pagination: { limit: PAGE_SIZE, cursor: pager.cursor },\n });\n const createSpecies = useEcoCreateSpecies();\n\n const rows = useMemo(() => data?.items ?? [], [data]);\n\n const query = search.trim().toLowerCase();\n const visibleRows = useMemo(() => {\n if (!query) return rows;\n return rows.filter(\n (s) =>\n s.commonName.toLowerCase().includes(query) ||\n (s.scientificName?.toLowerCase().includes(query) ?? false)\n );\n }, [rows, query]);\n\n const columns: Column<EcoSpecies>[] = [\n {\n key: 'name',\n header: 'Species',\n render: (s) => (\n <div className=\"min-w-0\">\n <p className=\"font-semibold text-text-primary\">{s.commonName}</p>\n {s.scientificName && (\n <p className=\"truncate text-xs italic text-text-tertiary\">{s.scientificName}</p>\n )}\n </div>\n ),\n },\n {\n key: 'taxonGroup',\n header: 'Taxon',\n hideOnMobile: true,\n render: (s) => <TaxonChip group={s.taxonGroup} />,\n },\n {\n key: 'conservationStatus',\n header: 'Conservation status',\n render: (s) => <ConservationBadge status={s.conservationStatus} />,\n },\n {\n key: 'priority',\n header: 'Priority',\n align: 'center',\n render: (s) =>\n s.isPriority ? (\n <span\n className=\"inline-flex items-center justify-center gap-1 rounded-full bg-status-warning-bg-subtle px-2 py-0.5 text-status-warning-text\"\n title=\"Priority species\"\n >\n <Star className=\"h-3.5 w-3.5 fill-current\" />\n </span>\n ) : (\n <span className=\"text-text-tertiary\" title=\"Not prioritised\">\n —\n </span>\n ),\n },\n {\n key: 'updated',\n header: 'Updated',\n align: 'right',\n hideOnMobile: true,\n render: (s) => (\n <span className=\"whitespace-nowrap text-text-tertiary\">\n {formatRelativeTime(s.updatedAt)}\n </span>\n ),\n },\n ];\n\n const resetForm = () => {\n setForm(EMPTY_FORM);\n setFormError(null);\n };\n\n const handleCreate = async () => {\n if (!form.commonName.trim()) {\n setFormError('Common name is required.');\n return;\n }\n try {\n const created = await createSpecies.mutateAsync({\n commonName: form.commonName.trim(),\n scientificName: form.scientificName.trim() || null,\n taxonGroup: form.taxonGroup,\n conservationStatus: form.conservationStatus,\n isPriority: form.isPriority,\n description: form.description.trim() || null,\n });\n setDialogOpen(false);\n resetForm();\n navigateTo(`species/${created.id}`);\n } catch (err) {\n setFormError(err instanceof Error ? err.message : 'Failed to create species.');\n }\n };\n\n return (\n <PageLayout\n title=\"Species\"\n description=\"Tracked taxa — conservation status, priority focus & field observations.\"\n actions={\n <Button onClick={() => setDialogOpen(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> New species\n </Button>\n }\n >\n <GlassCard treatment=\"plain\" className=\"mb-5 p-4\">\n <div className=\"flex flex-col gap-3 lg:flex-row lg:items-end lg:justify-between\">\n <div className=\"flex flex-wrap items-end gap-3\">\n <div className=\"grid gap-1.5\">\n <span className=\"text-xs font-medium uppercase tracking-wide text-text-tertiary\">\n Taxon group\n </span>\n <Select\n value={taxonGroup}\n onValueChange={(v) => {\n setTaxonGroup(v as EcoTaxonGroup | 'ALL');\n pager.reset();\n }}\n >\n <SelectTrigger className=\"w-44\">\n <SelectValue placeholder=\"All groups\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"ALL\">All groups</SelectItem>\n {TAXON_GROUPS.map((t) => (\n <SelectItem key={t} value={t}>\n {formatEnumLabel(t)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"grid gap-1.5\">\n <span className=\"text-xs font-medium uppercase tracking-wide text-text-tertiary\">\n Conservation status\n </span>\n <Select\n value={conservationStatus}\n onValueChange={(v) => {\n setConservationStatus(v as EcoConservationStatus | 'ALL');\n pager.reset();\n }}\n >\n <SelectTrigger className=\"w-52\">\n <SelectValue placeholder=\"All conservation\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"ALL\">All conservation</SelectItem>\n {CONSERVATION_STATUSES.map((c) => (\n <SelectItem key={c} value={c}>\n {formatEnumLabel(c)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"grid gap-1.5\">\n <span className=\"text-xs font-medium uppercase tracking-wide text-text-tertiary\">\n Search this page\n </span>\n <div className=\"relative\">\n <Search className=\"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-tertiary\" />\n <Input\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n placeholder=\"Common or scientific name…\"\n className=\"w-full pl-9 sm:w-64\"\n aria-label=\"Search loaded species by name\"\n />\n </div>\n </div>\n </div>\n <FilterTabs\n options={PRIORITY_FILTERS}\n value={priority}\n onChange={(v) => {\n setPriority(v);\n pager.reset();\n }}\n />\n </div>\n </GlassCard>\n\n {isLoading ? (\n <LoadingView label=\"Loading species…\" />\n ) : isError ? (\n <ErrorView message=\"Couldn't load species.\" onRetry={() => refetch()} />\n ) : rows.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Rabbit className=\"h-10 w-10\" />}\n title=\"No species yet\"\n description={\n taxonGroup === 'ALL' && conservationStatus === 'ALL' && priority === 'ALL'\n ? 'Register your first species to start logging field observations.'\n : 'No species match these filters.'\n }\n action={\n <Button onClick={() => setDialogOpen(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> New species\n </Button>\n }\n />\n ) : visibleRows.length === 0 ? (\n <EmptyState\n icon={<Search className=\"h-10 w-10\" />}\n title=\"No matches on this page\"\n description={`No species on this page match “${search.trim()}”. Clear the search or page through the catalog.`}\n action={\n <Button variant=\"outline\" onClick={() => setSearch('')}>\n Clear search\n </Button>\n }\n />\n ) : (\n <>\n <DataTable\n columns={columns}\n rows={visibleRows}\n rowKey={(s) => s.id}\n onRowClick={(s) => navigateTo(`species/${s.id}`)}\n />\n {query ? (\n <p className=\"mt-4 text-sm text-text-secondary tabular-nums\">\n {visibleRows.length} of {rows.length} on this page match “{search.trim()}”\n </p>\n ) : (\n <Pagination\n page={pager.page}\n pageSize={PAGE_SIZE}\n itemCount={rows.length}\n hasMore={data?.pageInfo?.hasMore ?? false}\n onPageChange={(target) => pager.onPageChange(target, data?.pageInfo?.cursor)}\n />\n )}\n </>\n )}\n\n <ResponsiveDialog\n open={dialogOpen}\n onOpenChange={(open) => {\n setDialogOpen(open);\n if (!open) resetForm();\n }}\n >\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>New species</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Register a taxon to track its conservation status and field observations.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n\n <div className=\"grid gap-4 py-2\">\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"commonName\">Common name *</Label>\n <Input\n id=\"commonName\"\n value={form.commonName}\n onChange={(e) => setForm({ ...form, commonName: e.target.value })}\n placeholder=\"Indian Pangolin\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"scientificName\">Scientific name</Label>\n <Input\n id=\"scientificName\"\n value={form.scientificName}\n onChange={(e) => setForm({ ...form, scientificName: e.target.value })}\n placeholder=\"Manis crassicaudata\"\n />\n </div>\n </div>\n\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"taxonGroup\">Taxon group</Label>\n <Select\n value={form.taxonGroup}\n onValueChange={(v) => setForm({ ...form, taxonGroup: v as EcoTaxonGroup })}\n >\n <SelectTrigger id=\"taxonGroup\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {TAXON_GROUPS.map((t) => (\n <SelectItem key={t} value={t}>\n {formatEnumLabel(t)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"conservationStatus\">Conservation status</Label>\n <Select\n value={form.conservationStatus}\n onValueChange={(v) =>\n setForm({ ...form, conservationStatus: v as EcoConservationStatus })\n }\n >\n <SelectTrigger id=\"conservationStatus\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {CONSERVATION_STATUSES.map((c) => (\n <SelectItem key={c} value={c}>\n {formatEnumLabel(c)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n\n <label className=\"flex items-center gap-2 text-sm text-text-primary\">\n <input\n type=\"checkbox\"\n checked={form.isPriority}\n onChange={(e) => setForm({ ...form, isPriority: e.target.checked })}\n className=\"h-4 w-4 rounded border-border-seam accent-action-primary-bg\"\n />\n Mark as priority species\n </label>\n\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"description\">Description</Label>\n <Textarea\n id=\"description\"\n value={form.description}\n onChange={(e) => setForm({ ...form, description: e.target.value })}\n placeholder=\"Optional notes on habitat, range or identification.\"\n rows={2}\n />\n </div>\n\n {formError && <p className=\"text-sm text-status-error-text\">{formError}</p>}\n </div>\n\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => setDialogOpen(false)}>\n Cancel\n </Button>\n <Button onClick={handleCreate} disabled={createSpecies.isPending}>\n {createSpecies.isPending ? 'Creating…' : 'Create species'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EcoImpactHub transport adapter for the shared fe-libs AssistantWidget.
|
|
3
|
+
*
|
|
4
|
+
* The floating widget (fe-libs, Layer 1) is backend-agnostic — it calls an
|
|
5
|
+
* injected `AssistantTransport`. This hook builds a transport that returns
|
|
6
|
+
* contextual, screen-aware guidance for the EcoImpactHub domain. It is a
|
|
7
|
+
* lightweight first-mile implementation: it does not require a warm sandbox or
|
|
8
|
+
* agent runtime, so it works out of the box while the product backend is being
|
|
9
|
+
* extended with an AI assistant capability.
|
|
10
|
+
*
|
|
11
|
+
* Future iterations can swap the local `respond` function for a call to the
|
|
12
|
+
* workspace AI orchestrator (e.g. `microfe-sandbox` assistant APIs or a
|
|
13
|
+
* dedicated `ecoimpacthub.assistant` GraphQL mutation) without changing the
|
|
14
|
+
* host AppShell contract.
|
|
15
|
+
*/
|
|
16
|
+
interface AssistantSendArgs {
|
|
17
|
+
prompt: string;
|
|
18
|
+
onProgress: (partialText: string) => void;
|
|
19
|
+
signal: AbortSignal;
|
|
20
|
+
}
|
|
21
|
+
export interface AssistantTransport {
|
|
22
|
+
sendPrompt: (args: AssistantSendArgs) => Promise<{
|
|
23
|
+
text: string;
|
|
24
|
+
}>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Returns a memoized `AssistantTransport` wired to a lightweight, page-aware
|
|
28
|
+
* EcoImpactHub responder. The transport fulfills the fe-libs AssistantWidget
|
|
29
|
+
* contract and degrades gracefully when no AI backend is configured.
|
|
30
|
+
*/
|
|
31
|
+
export declare function useSandboxAssistantTransport(): AssistantTransport;
|
|
32
|
+
export {};
|
|
33
|
+
//# sourceMappingURL=createSandboxAssistantTransport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createSandboxAssistantTransport.d.ts","sourceRoot":"","sources":["../../../src/ecoimpacthub/services/createSandboxAssistantTransport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH,UAAU,iBAAiB;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,MAAM,EAAE,WAAW,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,CAAC,IAAI,EAAE,iBAAiB,KAAK,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpE;AAuDD;;;;GAIG;AACH,wBAAgB,4BAA4B,IAAI,kBAAkB,CA0BjE"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { useCallback as e, useMemo as t } from "react";
|
|
2
|
+
import { useLocation as n } from "react-router-dom";
|
|
3
|
+
//#region src/ecoimpacthub/services/createSandboxAssistantTransport.ts
|
|
4
|
+
function r(e) {
|
|
5
|
+
let t = e.split("/").filter(Boolean), n = t.findIndex((e) => e === "ecoimpacthub"), [r, i] = n >= 0 ? t.slice(n + 1) : t;
|
|
6
|
+
return {
|
|
7
|
+
path: e,
|
|
8
|
+
page: r ?? "dashboard",
|
|
9
|
+
entityId: i
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
function i(e, t) {
|
|
13
|
+
let { page: n, entityId: r } = t, i = e.toLowerCase(), a = {
|
|
14
|
+
dashboard: "Dashboard",
|
|
15
|
+
sites: "Environmental Sites",
|
|
16
|
+
monitoring: "Monitoring",
|
|
17
|
+
species: "Species",
|
|
18
|
+
observations: "Observations",
|
|
19
|
+
habitat: "Habitat Projects",
|
|
20
|
+
carbon: "Carbon Ledger",
|
|
21
|
+
reports: "ESG Reports"
|
|
22
|
+
}[n] ?? "EcoImpactHub";
|
|
23
|
+
return i.includes("help") || i.includes("what") || i.includes("how") ? `You're on the **${a}** page in EcoImpactHub.\n\nYou can ask me to:\n- Explain the current screen\n- Suggest next steps for sustainability or conservation workflows\n- Summarize what actions are available here\n\n${r ? `Context: viewing a specific record (${r}).` : "Context: list/overview view."}` : i.includes("create") || i.includes("add") || i.includes("new") ? `To create a new record in **${a}**, use the primary action button on the page. If you don't see one, you may need additional permissions in this workspace.` : i.includes("delete") || i.includes("remove") ? `Deletion in **${a}** is typically available from the row-level actions or the detail page. Items are soft-deleted so they can be restored by a workspace admin if needed.` : i.includes("report") || i.includes("export") ? "EcoImpactHub can generate ESG and sustainability reports from the **Reports** page. You can also export list views using the export action where available." : `Thanks for your message. I'm the EcoImpactHub assistant, currently viewing **${a}**.\n\nI can help explain this screen, suggest workflows, or point you to the right module. For live data operations, use the controls on the page directly.`;
|
|
24
|
+
}
|
|
25
|
+
function a(e) {
|
|
26
|
+
return new Promise((t) => setTimeout(t, e));
|
|
27
|
+
}
|
|
28
|
+
function o() {
|
|
29
|
+
let { pathname: o } = n(), s = t(() => r(o), [o]), c = e(async ({ prompt: e, onProgress: t, signal: n }) => {
|
|
30
|
+
let r = i(e, s), o = r.split(" "), c = "";
|
|
31
|
+
for (let e = 0; e < o.length; e++) {
|
|
32
|
+
if (n.aborted) throw Error("Cancelled");
|
|
33
|
+
c += (e === 0 ? "" : " ") + o[e], t(c), await a(12);
|
|
34
|
+
}
|
|
35
|
+
return { text: r };
|
|
36
|
+
}, [s]);
|
|
37
|
+
return t(() => ({ sendPrompt: c }), [c]);
|
|
38
|
+
}
|
|
39
|
+
//#endregion
|
|
40
|
+
export { o as useSandboxAssistantTransport };
|
|
41
|
+
|
|
42
|
+
//# sourceMappingURL=createSandboxAssistantTransport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createSandboxAssistantTransport.js","names":[],"sources":["../../../src/ecoimpacthub/services/createSandboxAssistantTransport.ts"],"sourcesContent":["/**\n * EcoImpactHub transport adapter for the shared fe-libs AssistantWidget.\n *\n * The floating widget (fe-libs, Layer 1) is backend-agnostic — it calls an\n * injected `AssistantTransport`. This hook builds a transport that returns\n * contextual, screen-aware guidance for the EcoImpactHub domain. It is a\n * lightweight first-mile implementation: it does not require a warm sandbox or\n * agent runtime, so it works out of the box while the product backend is being\n * extended with an AI assistant capability.\n *\n * Future iterations can swap the local `respond` function for a call to the\n * workspace AI orchestrator (e.g. `microfe-sandbox` assistant APIs or a\n * dedicated `ecoimpacthub.assistant` GraphQL mutation) without changing the\n * host AppShell contract.\n */\n\nimport { useCallback, useMemo } from 'react';\nimport { useLocation } from 'react-router-dom';\n\ninterface AssistantSendArgs {\n prompt: string;\n onProgress: (partialText: string) => void;\n signal: AbortSignal;\n}\n\nexport interface AssistantTransport {\n sendPrompt: (args: AssistantSendArgs) => Promise<{ text: string }>;\n}\n\ninterface PageContext {\n path: string;\n page: string;\n entityId?: string;\n}\n\nfunction resolvePageContext(pathname: string): PageContext {\n const segments = pathname.split('/').filter(Boolean);\n const productIndex = segments.findIndex((s) => s === 'ecoimpacthub');\n const productSegments = productIndex >= 0 ? segments.slice(productIndex + 1) : segments;\n const [page, entityId] = productSegments;\n return { path: pathname, page: page ?? 'dashboard', entityId };\n}\n\nfunction buildContextualResponse(prompt: string, context: PageContext): string {\n const { page, entityId } = context;\n const lower = prompt.toLowerCase();\n\n const pageName =\n {\n dashboard: 'Dashboard',\n sites: 'Environmental Sites',\n monitoring: 'Monitoring',\n species: 'Species',\n observations: 'Observations',\n habitat: 'Habitat Projects',\n carbon: 'Carbon Ledger',\n reports: 'ESG Reports',\n }[page] ?? 'EcoImpactHub';\n\n if (lower.includes('help') || lower.includes('what') || lower.includes('how')) {\n return `You're on the **${pageName}** page in EcoImpactHub.\\n\\nYou can ask me to:\\n- Explain the current screen\\n- Suggest next steps for sustainability or conservation workflows\\n- Summarize what actions are available here\\n\\n${entityId ? `Context: viewing a specific record (${entityId}).` : 'Context: list/overview view.'}`;\n }\n\n if (lower.includes('create') || lower.includes('add') || lower.includes('new')) {\n return `To create a new record in **${pageName}**, use the primary action button on the page. If you don't see one, you may need additional permissions in this workspace.`;\n }\n\n if (lower.includes('delete') || lower.includes('remove')) {\n return `Deletion in **${pageName}** is typically available from the row-level actions or the detail page. Items are soft-deleted so they can be restored by a workspace admin if needed.`;\n }\n\n if (lower.includes('report') || lower.includes('export')) {\n return `EcoImpactHub can generate ESG and sustainability reports from the **Reports** page. You can also export list views using the export action where available.`;\n }\n\n return `Thanks for your message. I'm the EcoImpactHub assistant, currently viewing **${pageName}**.\\n\\nI can help explain this screen, suggest workflows, or point you to the right module. For live data operations, use the controls on the page directly.`;\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Returns a memoized `AssistantTransport` wired to a lightweight, page-aware\n * EcoImpactHub responder. The transport fulfills the fe-libs AssistantWidget\n * contract and degrades gracefully when no AI backend is configured.\n */\nexport function useSandboxAssistantTransport(): AssistantTransport {\n const { pathname } = useLocation();\n const context = useMemo(() => resolvePageContext(pathname), [pathname]);\n\n const sendPrompt = useCallback(\n async ({ prompt, onProgress, signal }: AssistantSendArgs): Promise<{ text: string }> => {\n const response = buildContextualResponse(prompt, context);\n\n // Simulate a short streaming response so the widget UI shows progress.\n const words = response.split(' ');\n let partial = '';\n for (let i = 0; i < words.length; i++) {\n if (signal.aborted) {\n throw new Error('Cancelled');\n }\n partial += (i === 0 ? '' : ' ') + words[i];\n onProgress(partial);\n await delay(12);\n }\n\n return { text: response };\n },\n [context]\n );\n\n return useMemo<AssistantTransport>(() => ({ sendPrompt }), [sendPrompt]);\n}\n"],"mappings":";;;AAmCA,SAAS,EAAmB,GAA+B;CACzD,IAAM,IAAW,EAAS,MAAM,IAAI,CAAC,OAAO,QAAQ,EAC9C,IAAe,EAAS,WAAW,MAAM,MAAM,eAAe,EAE9D,CAAC,GAAM,KADW,KAAgB,IAAI,EAAS,MAAM,IAAe,EAAE,GAAG;AAE/E,QAAO;EAAE,MAAM;EAAU,MAAM,KAAQ;EAAa;EAAU;;AAGhE,SAAS,EAAwB,GAAgB,GAA8B;CAC7E,IAAM,EAAE,SAAM,gBAAa,GACrB,IAAQ,EAAO,aAAa,EAE5B,IACJ;EACE,WAAW;EACX,OAAO;EACP,YAAY;EACZ,SAAS;EACT,cAAc;EACd,SAAS;EACT,QAAQ;EACR,SAAS;EACV,CAAC,MAAS;AAkBb,QAhBI,EAAM,SAAS,OAAO,IAAI,EAAM,SAAS,OAAO,IAAI,EAAM,SAAS,MAAM,GACpE,mBAAmB,EAAS,kMAAkM,IAAW,uCAAuC,EAAS,MAAM,mCAGpS,EAAM,SAAS,SAAS,IAAI,EAAM,SAAS,MAAM,IAAI,EAAM,SAAS,MAAM,GACrE,+BAA+B,EAAS,+HAG7C,EAAM,SAAS,SAAS,IAAI,EAAM,SAAS,SAAS,GAC/C,iBAAiB,EAAS,2JAG/B,EAAM,SAAS,SAAS,IAAI,EAAM,SAAS,SAAS,GAC/C,gKAGF,gFAAgF,EAAS;;AAGlG,SAAS,EAAM,GAA2B;AACxC,QAAO,IAAI,SAAS,MAAY,WAAW,GAAS,EAAG,CAAC;;AAQ1D,SAAgB,IAAmD;CACjE,IAAM,EAAE,gBAAa,GAAa,EAC5B,IAAU,QAAc,EAAmB,EAAS,EAAE,CAAC,EAAS,CAAC,EAEjE,IAAa,EACjB,OAAO,EAAE,WAAQ,eAAY,gBAA2D;EACtF,IAAM,IAAW,EAAwB,GAAQ,EAAQ,EAGnD,IAAQ,EAAS,MAAM,IAAI,EAC7B,IAAU;AACd,OAAK,IAAI,IAAI,GAAG,IAAI,EAAM,QAAQ,KAAK;AACrC,OAAI,EAAO,QACT,OAAU,MAAM,YAAY;AAI9B,GAFA,MAAY,MAAM,IAAI,KAAK,OAAO,EAAM,IACxC,EAAW,EAAQ,EACnB,MAAM,EAAM,GAAG;;AAGjB,SAAO,EAAE,MAAM,GAAU;IAE3B,CAAC,EAAQ,CACV;AAED,QAAO,SAAmC,EAAE,eAAY,GAAG,CAAC,EAAW,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ecoimpacthub/services/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,4BAA4B,EAC5B,KAAK,kBAAkB,GACxB,MAAM,mCAAmC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "./createSandboxAssistantTransport.js";
|
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
export interface NavItem {
|
|
4
|
+
id: string;
|
|
5
|
+
label: string;
|
|
6
|
+
path: string;
|
|
7
|
+
icon?: ReactNode;
|
|
8
|
+
badge?: number;
|
|
9
|
+
order?: number;
|
|
10
|
+
group?: string;
|
|
11
|
+
visible?: boolean;
|
|
12
|
+
external?: boolean;
|
|
13
|
+
children?: NavItem[];
|
|
14
|
+
}
|
|
15
|
+
export interface FooterItem {
|
|
16
|
+
id: string;
|
|
17
|
+
label: string;
|
|
18
|
+
icon?: string;
|
|
19
|
+
onClick?: () => void;
|
|
20
|
+
type?: 'status' | 'action' | 'info';
|
|
21
|
+
order?: number;
|
|
22
|
+
badge?: string;
|
|
23
|
+
section?: 'left' | 'center' | 'right';
|
|
24
|
+
visible?: boolean;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Props for the EcoImpactHubRoot component. Host-contract preserving: the app
|
|
28
|
+
* shell spreads `workspaceBaseProps` (basePath, currentUser, workspaceId,
|
|
29
|
+
* tenantId, apiGatewayUrl, authToken, navigate, registerNavItems,
|
|
30
|
+
* registerFooterItems) onto this component.
|
|
31
|
+
*/
|
|
32
|
+
export interface EcoImpactHubRootProps {
|
|
33
|
+
basePath?: string;
|
|
34
|
+
workspaceId?: string;
|
|
35
|
+
tenantId?: string;
|
|
36
|
+
apiGatewayUrl?: string;
|
|
37
|
+
authToken?: string;
|
|
38
|
+
navigate?: (path: string) => void;
|
|
39
|
+
currentUser?: {
|
|
40
|
+
id: string;
|
|
41
|
+
email: string;
|
|
42
|
+
firstName?: string;
|
|
43
|
+
lastName?: string;
|
|
44
|
+
avatar?: string;
|
|
45
|
+
username?: string;
|
|
46
|
+
name?: string;
|
|
47
|
+
role?: string;
|
|
48
|
+
} | null;
|
|
49
|
+
registerNavItems?: (items: NavItem | NavItem[]) => () => void;
|
|
50
|
+
registerFooterItems?: (items: FooterItem | FooterItem[]) => () => void;
|
|
51
|
+
}
|
|
52
|
+
export type TrendDirection = 'up' | 'down' | 'neutral';
|
|
53
|
+
/**
|
|
54
|
+
* The svc `PaginationInput` accepts { limit, offset, cursor } but the resolver
|
|
55
|
+
* uses cursor+limit only (offset is a no-op). We drive pages by cursor:
|
|
56
|
+
* pass `pagination.cursor = previous pageInfo.cursor` for the next page.
|
|
57
|
+
*/
|
|
58
|
+
export interface PaginationInput {
|
|
59
|
+
limit?: number;
|
|
60
|
+
offset?: number;
|
|
61
|
+
cursor?: string | null;
|
|
62
|
+
}
|
|
63
|
+
/** All Eco*PageInfo variants are structurally { cursor, hasMore }. */
|
|
64
|
+
export interface EcoPageInfo {
|
|
65
|
+
cursor?: string | null;
|
|
66
|
+
hasMore: boolean;
|
|
67
|
+
}
|
|
68
|
+
export interface EcoConnection<T> {
|
|
69
|
+
items: T[];
|
|
70
|
+
pageInfo: EcoPageInfo;
|
|
71
|
+
}
|
|
72
|
+
export interface EcoFileRef {
|
|
73
|
+
id: string;
|
|
74
|
+
name?: string | null;
|
|
75
|
+
url?: string | null;
|
|
76
|
+
mimeType?: string | null;
|
|
77
|
+
sizeBytes?: number | null;
|
|
78
|
+
}
|
|
79
|
+
export type EcoSiteType = 'FACILITY' | 'WATERSHED' | 'FOREST' | 'WETLAND' | 'FARM' | 'PROTECTED_AREA' | 'AIRSHED' | 'COASTAL' | 'OTHER';
|
|
80
|
+
export type EcoSiteStatus = 'ACTIVE' | 'MONITORING_PAUSED' | 'ARCHIVED';
|
|
81
|
+
export type EcoSensorKind = 'AIR_QUALITY' | 'WATER_QUALITY' | 'WEATHER' | 'SOIL' | 'ENERGY_METER' | 'FLOW' | 'ACOUSTIC' | 'CAMERA_TRAP' | 'MANUAL';
|
|
82
|
+
export type EcoSensorStatus = 'ONLINE' | 'OFFLINE' | 'DEGRADED' | 'MAINTENANCE' | 'RETIRED';
|
|
83
|
+
export type EcoMeasurementSource = 'SENSOR' | 'MANUAL' | 'SATELLITE' | 'IMPORT' | 'CALCULATED';
|
|
84
|
+
export type EcoThresholdDirection = 'ABOVE' | 'BELOW' | 'OUTSIDE_RANGE';
|
|
85
|
+
export type EcoThresholdSeverity = 'INFO' | 'WARNING' | 'CRITICAL';
|
|
86
|
+
export type EcoConservationStatus = 'LEAST_CONCERN' | 'NEAR_THREATENED' | 'VULNERABLE' | 'ENDANGERED' | 'CRITICALLY_ENDANGERED' | 'EXTINCT_IN_WILD' | 'DATA_DEFICIENT' | 'NOT_EVALUATED';
|
|
87
|
+
export type EcoTaxonGroup = 'MAMMAL' | 'BIRD' | 'REPTILE' | 'AMPHIBIAN' | 'FISH' | 'INSECT' | 'PLANT' | 'FUNGI' | 'OTHER';
|
|
88
|
+
export type EcoObservationMethod = 'DIRECT_SIGHTING' | 'CAMERA_TRAP' | 'ACOUSTIC' | 'TRACKS_SIGNS' | 'EDNA' | 'TELEMETRY' | 'COMMUNITY_REPORT';
|
|
89
|
+
export type EcoHabitatProjectStatus = 'PLANNED' | 'IN_PROGRESS' | 'MONITORING' | 'COMPLETED' | 'ON_HOLD' | 'CANCELLED';
|
|
90
|
+
export type EcoRestorationActivityType = 'PLANTING' | 'INVASIVE_REMOVAL' | 'REWILDING' | 'WATER_MANAGEMENT' | 'SOIL_REMEDIATION' | 'COMMUNITY_ENGAGEMENT' | 'SURVEY';
|
|
91
|
+
export type EcoEmissionScope = 'SCOPE_1' | 'SCOPE_2' | 'SCOPE_3';
|
|
92
|
+
export type EcoCarbonEntryStatus = 'DRAFT' | 'RECORDED' | 'VERIFIED' | 'ADJUSTED';
|
|
93
|
+
export type EcoReportStatus = 'DRAFT' | 'IN_REVIEW' | 'PUBLISHED' | 'ARCHIVED';
|
|
94
|
+
export type EcoReportFramework = 'GHG_PROTOCOL' | 'GRI' | 'TCFD' | 'CDP' | 'SASB' | 'CUSTOM';
|
|
95
|
+
export type EcoReductionTargetStatus = 'PROPOSED' | 'ACTIVE' | 'ACHIEVED' | 'MISSED' | 'RETIRED';
|
|
96
|
+
export interface EcoSite {
|
|
97
|
+
id: string;
|
|
98
|
+
workspaceId: string;
|
|
99
|
+
name: string;
|
|
100
|
+
code?: string | null;
|
|
101
|
+
type: EcoSiteType;
|
|
102
|
+
status: EcoSiteStatus;
|
|
103
|
+
description?: string | null;
|
|
104
|
+
latitude?: number | null;
|
|
105
|
+
longitude?: number | null;
|
|
106
|
+
areaHectares?: number | null;
|
|
107
|
+
country?: string | null;
|
|
108
|
+
region?: string | null;
|
|
109
|
+
sensors?: EcoSensor[];
|
|
110
|
+
thresholds?: EcoAlertThreshold[];
|
|
111
|
+
createdAt: string;
|
|
112
|
+
updatedAt: string;
|
|
113
|
+
}
|
|
114
|
+
export interface EcoSensor {
|
|
115
|
+
id: string;
|
|
116
|
+
workspaceId: string;
|
|
117
|
+
siteId: string;
|
|
118
|
+
name: string;
|
|
119
|
+
kind: EcoSensorKind;
|
|
120
|
+
status: EcoSensorStatus;
|
|
121
|
+
hardwareId?: string | null;
|
|
122
|
+
unit?: string | null;
|
|
123
|
+
lastReadingAt?: string | null;
|
|
124
|
+
installedAt?: string | null;
|
|
125
|
+
site?: EcoSite | null;
|
|
126
|
+
createdAt: string;
|
|
127
|
+
updatedAt: string;
|
|
128
|
+
}
|
|
129
|
+
export interface EcoMeasurement {
|
|
130
|
+
id: string;
|
|
131
|
+
workspaceId: string;
|
|
132
|
+
siteId: string;
|
|
133
|
+
sensorId?: string | null;
|
|
134
|
+
parameter: string;
|
|
135
|
+
value: number;
|
|
136
|
+
unit: string;
|
|
137
|
+
source: EcoMeasurementSource;
|
|
138
|
+
recordedAt: string;
|
|
139
|
+
isBreach: boolean;
|
|
140
|
+
notes?: string | null;
|
|
141
|
+
createdAt: string;
|
|
142
|
+
updatedAt: string;
|
|
143
|
+
}
|
|
144
|
+
export interface EcoAlertThreshold {
|
|
145
|
+
id: string;
|
|
146
|
+
workspaceId: string;
|
|
147
|
+
siteId: string;
|
|
148
|
+
parameter: string;
|
|
149
|
+
direction: EcoThresholdDirection;
|
|
150
|
+
severity: EcoThresholdSeverity;
|
|
151
|
+
limitValue?: number | null;
|
|
152
|
+
minValue?: number | null;
|
|
153
|
+
maxValue?: number | null;
|
|
154
|
+
unit: string;
|
|
155
|
+
isActive: boolean;
|
|
156
|
+
createdAt: string;
|
|
157
|
+
updatedAt: string;
|
|
158
|
+
}
|
|
159
|
+
export interface EcoSpecies {
|
|
160
|
+
id: string;
|
|
161
|
+
workspaceId: string;
|
|
162
|
+
commonName: string;
|
|
163
|
+
scientificName?: string | null;
|
|
164
|
+
taxonGroup: EcoTaxonGroup;
|
|
165
|
+
conservationStatus: EcoConservationStatus;
|
|
166
|
+
isPriority: boolean;
|
|
167
|
+
description?: string | null;
|
|
168
|
+
observations?: EcoObservation[];
|
|
169
|
+
createdAt: string;
|
|
170
|
+
updatedAt: string;
|
|
171
|
+
}
|
|
172
|
+
export interface EcoObservation {
|
|
173
|
+
id: string;
|
|
174
|
+
workspaceId: string;
|
|
175
|
+
speciesId: string;
|
|
176
|
+
siteId?: string | null;
|
|
177
|
+
method: EcoObservationMethod;
|
|
178
|
+
count: number;
|
|
179
|
+
observedAt: string;
|
|
180
|
+
latitude?: number | null;
|
|
181
|
+
longitude?: number | null;
|
|
182
|
+
observerId?: string | null;
|
|
183
|
+
notes?: string | null;
|
|
184
|
+
evidence?: EcoFileRef | null;
|
|
185
|
+
species?: EcoSpecies | null;
|
|
186
|
+
createdAt: string;
|
|
187
|
+
updatedAt: string;
|
|
188
|
+
}
|
|
189
|
+
export interface EcoHabitatProject {
|
|
190
|
+
id: string;
|
|
191
|
+
workspaceId: string;
|
|
192
|
+
name: string;
|
|
193
|
+
status: EcoHabitatProjectStatus;
|
|
194
|
+
description?: string | null;
|
|
195
|
+
siteId?: string | null;
|
|
196
|
+
targetHectares?: number | null;
|
|
197
|
+
budgetAmount: number;
|
|
198
|
+
currency: string;
|
|
199
|
+
managerId?: string | null;
|
|
200
|
+
startDate?: string | null;
|
|
201
|
+
endDate?: string | null;
|
|
202
|
+
completedAt?: string | null;
|
|
203
|
+
activities?: EcoRestorationActivity[];
|
|
204
|
+
createdAt: string;
|
|
205
|
+
updatedAt: string;
|
|
206
|
+
}
|
|
207
|
+
export interface EcoRestorationActivity {
|
|
208
|
+
id: string;
|
|
209
|
+
workspaceId: string;
|
|
210
|
+
projectId: string;
|
|
211
|
+
type: EcoRestorationActivityType;
|
|
212
|
+
summary: string;
|
|
213
|
+
details?: string | null;
|
|
214
|
+
quantity?: number | null;
|
|
215
|
+
unit?: string | null;
|
|
216
|
+
performedAt: string;
|
|
217
|
+
createdAt: string;
|
|
218
|
+
updatedAt: string;
|
|
219
|
+
}
|
|
220
|
+
export interface EcoEmissionFactor {
|
|
221
|
+
id: string;
|
|
222
|
+
workspaceId: string;
|
|
223
|
+
name: string;
|
|
224
|
+
scope: EcoEmissionScope;
|
|
225
|
+
activityUnit: string;
|
|
226
|
+
factorKgco2e: number;
|
|
227
|
+
source?: string | null;
|
|
228
|
+
validYear?: number | null;
|
|
229
|
+
isActive: boolean;
|
|
230
|
+
createdAt: string;
|
|
231
|
+
updatedAt: string;
|
|
232
|
+
}
|
|
233
|
+
export interface EcoCarbonEntry {
|
|
234
|
+
id: string;
|
|
235
|
+
workspaceId: string;
|
|
236
|
+
siteId?: string | null;
|
|
237
|
+
factorId?: string | null;
|
|
238
|
+
scope: EcoEmissionScope;
|
|
239
|
+
status: EcoCarbonEntryStatus;
|
|
240
|
+
category: string;
|
|
241
|
+
activityValue: number;
|
|
242
|
+
activityUnit: string;
|
|
243
|
+
co2eKg: number;
|
|
244
|
+
periodStart: string;
|
|
245
|
+
notes?: string | null;
|
|
246
|
+
factor?: EcoEmissionFactor | null;
|
|
247
|
+
createdAt: string;
|
|
248
|
+
updatedAt: string;
|
|
249
|
+
}
|
|
250
|
+
export interface EcoReductionTarget {
|
|
251
|
+
id: string;
|
|
252
|
+
workspaceId: string;
|
|
253
|
+
name: string;
|
|
254
|
+
status: EcoReductionTargetStatus;
|
|
255
|
+
metric: string;
|
|
256
|
+
baselineYear: number;
|
|
257
|
+
baselineValue: number;
|
|
258
|
+
targetYear: number;
|
|
259
|
+
targetValue: number;
|
|
260
|
+
unit: string;
|
|
261
|
+
description?: string | null;
|
|
262
|
+
createdAt: string;
|
|
263
|
+
updatedAt: string;
|
|
264
|
+
}
|
|
265
|
+
export interface EcoReport {
|
|
266
|
+
id: string;
|
|
267
|
+
workspaceId: string;
|
|
268
|
+
title: string;
|
|
269
|
+
framework: EcoReportFramework;
|
|
270
|
+
status: EcoReportStatus;
|
|
271
|
+
periodStart: string;
|
|
272
|
+
periodEnd: string;
|
|
273
|
+
summary?: string | null;
|
|
274
|
+
file?: EcoFileRef | null;
|
|
275
|
+
publishedAt?: string | null;
|
|
276
|
+
lineItems?: EcoReportLineItem[];
|
|
277
|
+
createdAt: string;
|
|
278
|
+
updatedAt: string;
|
|
279
|
+
}
|
|
280
|
+
export interface EcoReportLineItem {
|
|
281
|
+
id: string;
|
|
282
|
+
workspaceId: string;
|
|
283
|
+
reportId: string;
|
|
284
|
+
carbonEntryId?: string | null;
|
|
285
|
+
label: string;
|
|
286
|
+
value: number;
|
|
287
|
+
unit: string;
|
|
288
|
+
category?: string | null;
|
|
289
|
+
createdAt: string;
|
|
290
|
+
updatedAt: string;
|
|
291
|
+
}
|
|
292
|
+
export interface EcoCreateSiteInput {
|
|
293
|
+
name: string;
|
|
294
|
+
code?: string | null;
|
|
295
|
+
type?: EcoSiteType;
|
|
296
|
+
status?: EcoSiteStatus;
|
|
297
|
+
description?: string | null;
|
|
298
|
+
latitude?: number | null;
|
|
299
|
+
longitude?: number | null;
|
|
300
|
+
areaHectares?: number | null;
|
|
301
|
+
country?: string | null;
|
|
302
|
+
region?: string | null;
|
|
303
|
+
}
|
|
304
|
+
export type EcoUpdateSiteInput = Partial<EcoCreateSiteInput>;
|
|
305
|
+
export interface EcoCreateSensorInput {
|
|
306
|
+
name: string;
|
|
307
|
+
siteId: string;
|
|
308
|
+
kind?: EcoSensorKind;
|
|
309
|
+
status?: EcoSensorStatus;
|
|
310
|
+
hardwareId?: string | null;
|
|
311
|
+
unit?: string | null;
|
|
312
|
+
installedAt?: string | null;
|
|
313
|
+
}
|
|
314
|
+
export interface EcoRecordMeasurementInput {
|
|
315
|
+
siteId: string;
|
|
316
|
+
parameter: string;
|
|
317
|
+
value: number;
|
|
318
|
+
unit: string;
|
|
319
|
+
recordedAt: string;
|
|
320
|
+
sensorId?: string | null;
|
|
321
|
+
source?: EcoMeasurementSource;
|
|
322
|
+
notes?: string | null;
|
|
323
|
+
}
|
|
324
|
+
export interface EcoCreateThresholdInput {
|
|
325
|
+
siteId: string;
|
|
326
|
+
parameter: string;
|
|
327
|
+
unit: string;
|
|
328
|
+
direction?: EcoThresholdDirection;
|
|
329
|
+
severity?: EcoThresholdSeverity;
|
|
330
|
+
limitValue?: number | null;
|
|
331
|
+
minValue?: number | null;
|
|
332
|
+
maxValue?: number | null;
|
|
333
|
+
}
|
|
334
|
+
export interface EcoCreateSpeciesInput {
|
|
335
|
+
commonName: string;
|
|
336
|
+
scientificName?: string | null;
|
|
337
|
+
taxonGroup?: EcoTaxonGroup;
|
|
338
|
+
conservationStatus?: EcoConservationStatus;
|
|
339
|
+
isPriority?: boolean;
|
|
340
|
+
description?: string | null;
|
|
341
|
+
}
|
|
342
|
+
export type EcoUpdateSpeciesInput = Partial<EcoCreateSpeciesInput>;
|
|
343
|
+
export interface EcoRecordObservationInput {
|
|
344
|
+
speciesId: string;
|
|
345
|
+
observedAt: string;
|
|
346
|
+
count?: number;
|
|
347
|
+
method?: EcoObservationMethod;
|
|
348
|
+
siteId?: string | null;
|
|
349
|
+
latitude?: number | null;
|
|
350
|
+
longitude?: number | null;
|
|
351
|
+
notes?: string | null;
|
|
352
|
+
evidenceFileId?: string | null;
|
|
353
|
+
}
|
|
354
|
+
export interface EcoCreateHabitatProjectInput {
|
|
355
|
+
name: string;
|
|
356
|
+
description?: string | null;
|
|
357
|
+
siteId?: string | null;
|
|
358
|
+
targetHectares?: number | null;
|
|
359
|
+
budgetAmount?: number | null;
|
|
360
|
+
currency?: string | null;
|
|
361
|
+
managerId?: string | null;
|
|
362
|
+
startDate?: string | null;
|
|
363
|
+
endDate?: string | null;
|
|
364
|
+
}
|
|
365
|
+
export interface EcoLogRestorationActivityInput {
|
|
366
|
+
projectId: string;
|
|
367
|
+
summary: string;
|
|
368
|
+
performedAt: string;
|
|
369
|
+
type?: EcoRestorationActivityType;
|
|
370
|
+
details?: string | null;
|
|
371
|
+
quantity?: number | null;
|
|
372
|
+
unit?: string | null;
|
|
373
|
+
}
|
|
374
|
+
export interface EcoCreateEmissionFactorInput {
|
|
375
|
+
name: string;
|
|
376
|
+
activityUnit: string;
|
|
377
|
+
factorKgco2e: number;
|
|
378
|
+
scope?: EcoEmissionScope;
|
|
379
|
+
source?: string | null;
|
|
380
|
+
validYear?: number | null;
|
|
381
|
+
}
|
|
382
|
+
export interface EcoRecordCarbonEntryInput {
|
|
383
|
+
category: string;
|
|
384
|
+
activityValue: number;
|
|
385
|
+
activityUnit: string;
|
|
386
|
+
periodStart: string;
|
|
387
|
+
scope?: EcoEmissionScope;
|
|
388
|
+
factorId?: string | null;
|
|
389
|
+
siteId?: string | null;
|
|
390
|
+
notes?: string | null;
|
|
391
|
+
}
|
|
392
|
+
export interface EcoCreateReductionTargetInput {
|
|
393
|
+
name: string;
|
|
394
|
+
metric: string;
|
|
395
|
+
baselineValue: number;
|
|
396
|
+
baselineYear: number;
|
|
397
|
+
targetValue: number;
|
|
398
|
+
targetYear: number;
|
|
399
|
+
unit: string;
|
|
400
|
+
description?: string | null;
|
|
401
|
+
}
|
|
402
|
+
export interface EcoCreateReportInput {
|
|
403
|
+
title: string;
|
|
404
|
+
periodStart: string;
|
|
405
|
+
periodEnd: string;
|
|
406
|
+
framework?: EcoReportFramework;
|
|
407
|
+
summary?: string | null;
|
|
408
|
+
}
|
|
409
|
+
export interface EcoAddReportLineItemInput {
|
|
410
|
+
reportId: string;
|
|
411
|
+
label: string;
|
|
412
|
+
value: number;
|
|
413
|
+
unit: string;
|
|
414
|
+
category?: string | null;
|
|
415
|
+
carbonEntryId?: string | null;
|
|
416
|
+
}
|
|
417
|
+
//# sourceMappingURL=index.d.ts.map
|