add ability to customize whitch paremeters to show
Some checks failed
Deploy MyApp on Same Server / build-and-deploy (push) Failing after 1s
Some checks failed
Deploy MyApp on Same Server / build-and-deploy (push) Failing after 1s
This commit is contained in:
@@ -28,6 +28,7 @@ function DailyReportContent() {
|
|||||||
const [activeTab, setActiveTab] = useState<TabType>('summary')
|
const [activeTab, setActiveTab] = useState<TabType>('summary')
|
||||||
const [forecastWeather, setForecastWeather] = useState<WeatherData | null>(null)
|
const [forecastWeather, setForecastWeather] = useState<WeatherData | null>(null)
|
||||||
const [forecastWeatherLoading, setForecastWeatherLoading] = useState(false)
|
const [forecastWeatherLoading, setForecastWeatherLoading] = useState(false)
|
||||||
|
const [visibleParams, setVisibleParams] = useState<string[] | null>(null)
|
||||||
|
|
||||||
// Map summary param to chart key
|
// Map summary param to chart key
|
||||||
const paramToChartKey = useCallback((param: string): string => {
|
const paramToChartKey = useCallback((param: string): string => {
|
||||||
@@ -113,6 +114,16 @@ function DailyReportContent() {
|
|||||||
|
|
||||||
const result = await api.listTelemetry({ deviceId, startUtc, endUtc, pageSize: 100000 })
|
const result = await api.listTelemetry({ deviceId, startUtc, endUtc, pageSize: 100000 })
|
||||||
setTelemetry(result.items)
|
setTelemetry(result.items)
|
||||||
|
|
||||||
|
console.log(result.items)
|
||||||
|
// Load visible params from server (controls which parameters are shown)
|
||||||
|
try {
|
||||||
|
const params = await api.getDisplayParameters(deviceId)
|
||||||
|
setVisibleParams(params ?? null)
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error loading display parameters:', err)
|
||||||
|
setVisibleParams(['gas', 'temperature', 'humidity', 'lux'])
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error loading telemetry:', error)
|
console.error('Error loading telemetry:', error)
|
||||||
} finally {
|
} finally {
|
||||||
@@ -243,10 +254,10 @@ function DailyReportContent() {
|
|||||||
className="md:mx-0 mx-[-1rem] md:rounded-xl rounded-none"
|
className="md:mx-0 mx-[-1rem] md:rounded-xl rounded-none"
|
||||||
>
|
>
|
||||||
{{
|
{{
|
||||||
summary: <SummaryTab temperature={temp} humidity={hum} soil={soil} gas={gas} lux={lux} forecastWeather={forecastWeather} forecastWeatherLoading={forecastWeatherLoading} onCardClick={handleCardClick} />,
|
summary: <SummaryTab temperature={temp} humidity={hum} soil={soil} gas={gas} lux={lux} forecastWeather={forecastWeather} forecastWeatherLoading={forecastWeatherLoading} onCardClick={handleCardClick} visibleParams={visibleParams} />,
|
||||||
charts: (
|
charts: (
|
||||||
<Suspense fallback={<Loading message="در حال بارگذاری نمودارها..." />}>
|
<Suspense fallback={<Loading message="در حال بارگذاری نمودارها..." />}>
|
||||||
<ChartsTab sortedTelemetry={sortedTelemetry} dataGaps={dataGaps} />
|
<ChartsTab sortedTelemetry={sortedTelemetry} dataGaps={dataGaps} visibleParams={visibleParams} />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
),
|
),
|
||||||
weather: selectedDate ? (
|
weather: selectedDate ? (
|
||||||
|
|||||||
@@ -10,11 +10,22 @@ import { useTelemetryCharts } from '@/features/daily-report/hooks/useTelemetryCh
|
|||||||
type ChartsTabProps = {
|
type ChartsTabProps = {
|
||||||
sortedTelemetry: TelemetryDto[]
|
sortedTelemetry: TelemetryDto[]
|
||||||
dataGaps?: DataGap[]
|
dataGaps?: DataGap[]
|
||||||
|
visibleParams?: string[] | null
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map server param keys to chart keys
|
||||||
|
const paramToChartKey: Record<string, string> = {
|
||||||
|
temperature: 'temp',
|
||||||
|
humidity: 'hum',
|
||||||
|
gas: 'gas',
|
||||||
|
soil: 'soil',
|
||||||
|
lux: 'lux',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ChartsTab = memo(function ChartsTab({
|
export const ChartsTab = memo(function ChartsTab({
|
||||||
sortedTelemetry,
|
sortedTelemetry,
|
||||||
dataGaps = [],
|
dataGaps = [],
|
||||||
|
visibleParams,
|
||||||
}: ChartsTabProps) {
|
}: ChartsTabProps) {
|
||||||
const [chartStartMinute, setChartStartMinute] = useState(0)
|
const [chartStartMinute, setChartStartMinute] = useState(0)
|
||||||
const [chartEndMinute, setChartEndMinute] = useState(1439)
|
const [chartEndMinute, setChartEndMinute] = useState(1439)
|
||||||
@@ -57,6 +68,12 @@ export const ChartsTab = memo(function ChartsTab({
|
|||||||
filteredDataGaps,
|
filteredDataGaps,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// If server returned a visibility list, compute allowed chart keys
|
||||||
|
const allowedChartKeys = useMemo(() => {
|
||||||
|
if (!visibleParams || visibleParams.length === 0) return null
|
||||||
|
return new Set(visibleParams.map(p => paramToChartKey[p] ?? p))
|
||||||
|
}, [visibleParams])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<TimeRangeSelector
|
<TimeRangeSelector
|
||||||
@@ -76,7 +93,9 @@ export const ChartsTab = memo(function ChartsTab({
|
|||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div className="grid gap-6 md:grid-cols-2">
|
<div className="grid gap-6 md:grid-cols-2">
|
||||||
{charts.map(chart => (
|
{charts
|
||||||
|
.filter(chart => !allowedChartKeys || allowedChartKeys.has(chart.key))
|
||||||
|
.map(chart => (
|
||||||
<Panel key={chart.key} title={chart.title} id={`chart-${chart.key}`}>
|
<Panel key={chart.key} title={chart.title} id={`chart-${chart.key}`}>
|
||||||
<LineChart
|
<LineChart
|
||||||
labels={chartLabels}
|
labels={chartLabels}
|
||||||
|
|||||||
@@ -15,9 +15,10 @@ type SummaryTabProps = {
|
|||||||
forecastWeather?: WeatherData | null
|
forecastWeather?: WeatherData | null
|
||||||
forecastWeatherLoading?: boolean
|
forecastWeatherLoading?: boolean
|
||||||
onCardClick?: (param: string) => void
|
onCardClick?: (param: string) => void
|
||||||
|
visibleParams?: string[] | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SummaryTab({ temperature, humidity, soil, gas, lux, forecastWeather, forecastWeatherLoading = false, onCardClick }: SummaryTabProps) {
|
export function SummaryTab({ temperature, humidity, soil, gas, lux, forecastWeather, forecastWeatherLoading = false, onCardClick, visibleParams }: SummaryTabProps) {
|
||||||
const [isAlertsDialogOpen, setIsAlertsDialogOpen] = useState(false)
|
const [isAlertsDialogOpen, setIsAlertsDialogOpen] = useState(false)
|
||||||
|
|
||||||
const alertsCount = useMemo(() => {
|
const alertsCount = useMemo(() => {
|
||||||
@@ -99,6 +100,7 @@ export function SummaryTab({ temperature, humidity, soil, gas, lux, forecastWeat
|
|||||||
|
|
||||||
{/* Summary Cards Grid */}
|
{/* Summary Cards Grid */}
|
||||||
<div className="grid gap-6 grid-cols-1 md:grid-cols-2 lg:grid-cols-3">
|
<div className="grid gap-6 grid-cols-1 md:grid-cols-2 lg:grid-cols-3">
|
||||||
|
{(!visibleParams || visibleParams.length === 0 || visibleParams.includes('temperature')) && (
|
||||||
<SummaryCard
|
<SummaryCard
|
||||||
param="temperature"
|
param="temperature"
|
||||||
currentValue={temperatureSummary.current}
|
currentValue={temperatureSummary.current}
|
||||||
@@ -107,6 +109,9 @@ export function SummaryTab({ temperature, humidity, soil, gas, lux, forecastWeat
|
|||||||
data={temperature}
|
data={temperature}
|
||||||
onClick={() => onCardClick?.('temperature')}
|
onClick={() => onCardClick?.('temperature')}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{(!visibleParams || visibleParams.length === 0 || visibleParams.includes('humidity')) && (
|
||||||
<SummaryCard
|
<SummaryCard
|
||||||
param="humidity"
|
param="humidity"
|
||||||
currentValue={humiditySummary.current}
|
currentValue={humiditySummary.current}
|
||||||
@@ -115,6 +120,9 @@ export function SummaryTab({ temperature, humidity, soil, gas, lux, forecastWeat
|
|||||||
data={humidity}
|
data={humidity}
|
||||||
onClick={() => onCardClick?.('humidity')}
|
onClick={() => onCardClick?.('humidity')}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{(!visibleParams || visibleParams.length === 0 || visibleParams.includes('gas')) && (
|
||||||
<SummaryCard
|
<SummaryCard
|
||||||
param="gas"
|
param="gas"
|
||||||
currentValue={gasSummary.current}
|
currentValue={gasSummary.current}
|
||||||
@@ -123,6 +131,9 @@ export function SummaryTab({ temperature, humidity, soil, gas, lux, forecastWeat
|
|||||||
data={gas}
|
data={gas}
|
||||||
onClick={() => onCardClick?.('gas')}
|
onClick={() => onCardClick?.('gas')}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{(!visibleParams || visibleParams.length === 0 || visibleParams.includes('soil')) && (
|
||||||
<SummaryCard
|
<SummaryCard
|
||||||
param="soil"
|
param="soil"
|
||||||
currentValue={soilSummary.current}
|
currentValue={soilSummary.current}
|
||||||
@@ -131,6 +142,9 @@ export function SummaryTab({ temperature, humidity, soil, gas, lux, forecastWeat
|
|||||||
data={soil}
|
data={soil}
|
||||||
onClick={() => onCardClick?.('soil')}
|
onClick={() => onCardClick?.('soil')}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{(!visibleParams || visibleParams.length === 0 || visibleParams.includes('lux')) && (
|
||||||
<SummaryCard
|
<SummaryCard
|
||||||
param="lux"
|
param="lux"
|
||||||
currentValue={luxSummary.current}
|
currentValue={luxSummary.current}
|
||||||
@@ -139,6 +153,7 @@ export function SummaryTab({ temperature, humidity, soil, gas, lux, forecastWeat
|
|||||||
data={lux}
|
data={lux}
|
||||||
onClick={() => onCardClick?.('lux')}
|
onClick={() => onCardClick?.('lux')}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Alerts Dialog */}
|
{/* Alerts Dialog */}
|
||||||
|
|||||||
@@ -83,6 +83,10 @@ export const api = {
|
|||||||
getDailyReport: (deviceId: number, persianDate: string) =>
|
getDailyReport: (deviceId: number, persianDate: string) =>
|
||||||
http<DailyReportDto>(`${API_BASE}/api/DailyReport?deviceId=${deviceId}&persianDate=${encodeURIComponent(persianDate)}`),
|
http<DailyReportDto>(`${API_BASE}/api/DailyReport?deviceId=${deviceId}&persianDate=${encodeURIComponent(persianDate)}`),
|
||||||
|
|
||||||
|
// NEW: get displayable parameters from server
|
||||||
|
getDisplayParameters: (deviceId: number) =>
|
||||||
|
http<string[]>(`${API_BASE}/api/display-parameters?deviceId=${deviceId}`),
|
||||||
|
|
||||||
// Alert Conditions
|
// Alert Conditions
|
||||||
getAlertConditions: (deviceId: number) => {
|
getAlertConditions: (deviceId: number) => {
|
||||||
return http<AlertConditionDto[]>(`${API_BASE}/api/alertconditions/device/${deviceId}`)
|
return http<AlertConditionDto[]>(`${API_BASE}/api/alertconditions/device/${deviceId}`)
|
||||||
|
|||||||
@@ -24,6 +24,11 @@ export type TelemetryDto = {
|
|||||||
persianMonth: number
|
persianMonth: number
|
||||||
persianDate: string
|
persianDate: string
|
||||||
deviceName?: string
|
deviceName?: string
|
||||||
|
power?: number
|
||||||
|
oldPower?: number
|
||||||
|
batteryVoltage?: number
|
||||||
|
batteryPercent?: number
|
||||||
|
voltage?: number
|
||||||
serverTimestampUtc?: string
|
serverTimestampUtc?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user