Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions src/website/app/api/datasets/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import ConnectMongoDB from '@/lib/mongodb';

import AISShips from '@/models/AISShips';
import Batteries from '@/models/Batteries';
import GenericSensors from '@/models/GenericSensors';
import GlobalPath from '@/models/GlobalPath';
import GPS from '@/models/GPS';
import LocalPath from '@/models/LocalPath';
import PhSensors from '@/models/PhSensors';
import SalinitySensors from '@/models/SalinitySensors';
import TempSensors from '@/models/TempSensors';
import WindSensors from '@/models/WindSensors';

type LastUpdatedMap = Record<string, string | null>;
Expand All @@ -16,7 +18,9 @@ interface WithTimestamp {
timestamp: string;
}

async function getLastUpdated<T extends WithTimestamp>(Model: Model<T>): Promise<string | null> {
async function getLastUpdated<T extends WithTimestamp>(
Model: Model<T>,
): Promise<string | null> {
const latest = await Model.findOne({})
.sort({ timestamp: -1 })
.select({ timestamp: 1, _id: 0 })
Expand All @@ -36,7 +40,9 @@ export async function GET() {
LocalPath: await getLastUpdated(LocalPath),
Batteries: await getLastUpdated(Batteries),
WindSensors: await getLastUpdated(WindSensors),
GenericSensors: await getLastUpdated(GenericSensors),
TempSensors: await getLastUpdated(TempSensors),
PhSensors: await getLastUpdated(PhSensors),
SalinitySensors: await getLastUpdated(SalinitySensors),
};

return NextResponse.json({ success: true, data });
Expand Down
22 changes: 22 additions & 0 deletions src/website/app/api/ph-sensors/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { NextResponse } from 'next/server';
import ConnectMongoDB from '@/lib/mongodb';
import PhSensors from '@/models/PhSensors';

export async function GET() {
try {
await ConnectMongoDB();

const phSensors = await PhSensors.find({}).select({
'phSensors._id': 0,
_id: 0,
__v: 0,
});

return NextResponse.json({ success: true, data: phSensors });
} catch (error) {
return NextResponse.json(
{ success: false, message: (error as Error).message },
{ status: 400 },
);
}
}
22 changes: 22 additions & 0 deletions src/website/app/api/salinity-sensors/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { NextResponse } from 'next/server';
import ConnectMongoDB from '@/lib/mongodb';
import SalinitySensors from '@/models/SalinitySensors';

export async function GET() {
try {
await ConnectMongoDB();

const salinitySensors = await SalinitySensors.find({}).select({
'salinitySensors._id': 0,
_id: 0,
__v: 0,
});

return NextResponse.json({ success: true, data: salinitySensors });
} catch (error) {
return NextResponse.json(
{ success: false, message: (error as Error).message },
{ status: 400 },
);
}
}
22 changes: 22 additions & 0 deletions src/website/app/api/temp-sensors/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { NextResponse } from 'next/server';
import ConnectMongoDB from '@/lib/mongodb';
import TempSensors from '@/models/TempSensors';

export async function GET() {
try {
await ConnectMongoDB();

const tempSensors = await TempSensors.find({}).select({
'tempSensors._id': 0,
_id: 0,
__v: 0,
});

return NextResponse.json({ success: true, data: tempSensors });
} catch (error) {
return NextResponse.json(
{ success: false, message: (error as Error).message },
{ status: 400 },
);
}
}
6 changes: 6 additions & 0 deletions src/website/lib/redux/rootReducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import LocalPathReducer from '@/stores/LocalPath/LocalPathReducers';
import BatteriesReducer from '@/stores/Batteries/BatteriesReducers';
import WindSensorsReducer from '@/stores/WindSensors/WindSensorsReducers';
import GenericSensorsReducer from '@/stores/GenericSensors/GenericSensorsReducers';
import TempSensorsReducer from '@/stores/TempSensors/TempSensorsReducers';
import PhSensorsReducer from '@/stores/PhSensors/PhSensorsReducers';
import SalinitySensorsReducer from '@/stores/SalinitySensors/SalinitySensorsReducers';
import GraphsReducer from '@/stores/Graphs/GraphsReducers';
import DataFilterReducer from '@/stores/DataFilter/DataFilterReducers';

Expand All @@ -19,6 +22,9 @@ export function rootReducer() {
batteries: new BatteriesReducer().reducer,
windSensors: new WindSensorsReducer().reducer,
genericSensors: new GenericSensorsReducer().reducer,
tempSensors: new TempSensorsReducer().reducer,
phSensors: new PhSensorsReducer().reducer,
salinitySensors: new SalinitySensorsReducer().reducer,
graphs: new GraphsReducer().reducer,
dataFilter: new DataFilterReducer().reducer,
};
Expand Down
6 changes: 6 additions & 0 deletions src/website/lib/redux/rootSaga.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import GlobalPathSagas from '@/stores/GlobalPath/GlobalPathSagas';
import BatteriesSagas from '@/stores/Batteries/BatteriesSagas';
import WindSensorsSagas from '@/stores/WindSensors/WindSensorsSagas';
import GenericSensorsSagas from '@/stores/GenericSensors/GenericSensorsSagas';
import TempSensorsSagas from '@/stores/TempSensors/TempSensorsSagas';
import PhSensorsSagas from '@/stores/PhSensors/PhSensorsSagas';
import SalinitySensorsSagas from '@/stores/SalinitySensors/SalinitySensorsSagas';
import GraphsSagas from '@/stores/Graphs/GraphsSagas';
import GraphsActions from '@/stores/Graphs/GraphsActions';
import DataFilterSagas from '@/stores/DataFilter/DataFilterSagas';
Expand All @@ -20,6 +23,9 @@ export function* rootSaga() {
batteries: new BatteriesSagas().forkSagas(),
windSensors: new WindSensorsSagas().forkSagas(),
genericSensors: new GenericSensorsSagas().forkSagas(),
tempSensors: new TempSensorsSagas().forkSagas(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR is titled move from Generic Sensors, but GenericSensors is only removed from the datasets route and the download UI — the store, saga, reducer, model, and /api/generic-sensors route all remain. Since forkSagas() starts every saga, genericSensors still polls /api/generic-sensors on every interval and dispatches into a reducer nothing reads anymore (dead polling + dead state).

Either fully remove GenericSensors (store dir, model, route, the endpoints.ts / interfaces.ts / given.ts entries, the rootReducer + rootSaga registrations, and genericsensors.feature), or if it's intentionally kept during the transition, please note that in the PR description.

phSensors: new PhSensorsSagas().forkSagas(),
salinitySensors: new SalinitySensorsSagas().forkSagas(),
graphs: new GraphsSagas().forkSaga(GraphsActions.REARRANGE_GRAPHS),
dataFilter: new DataFilterSagas().forkSaga(DataFilterActions.SET_TIMESTAMP),
};
Expand Down
30 changes: 30 additions & 0 deletions src/website/models/PhSensors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import mongoose from 'mongoose';

interface PhSensor extends mongoose.Document {
ph: number;
}

export interface PhSensors extends mongoose.Document {
phSensors: PhSensor[];
timestamp: string;
}

const PhSensorsSchema = new mongoose.Schema<PhSensors>({
phSensors: {
type: [
{
ph: Number,
},
],
required: [true, 'Missing array of objects in PhSensors interface'],
},
timestamp: {
type: String,
default: () => new Date().toISOString(),
},
});

export default (mongoose.models['PhSensors'] as
| mongoose.Model<PhSensors>
| undefined) ??
mongoose.model<PhSensors>('PhSensors', PhSensorsSchema, 'ph_sensors');
34 changes: 34 additions & 0 deletions src/website/models/SalinitySensors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import mongoose from 'mongoose';

interface SalinitySensor extends mongoose.Document {
salinity: number;
}

export interface SalinitySensors extends mongoose.Document {
salinitySensors: SalinitySensor[];
timestamp: string;
}

const SalinitySensorsSchema = new mongoose.Schema<SalinitySensors>({
salinitySensors: {
type: [
{
salinity: Number,
},
],
required: [true, 'Missing array of objects in SalinitySensors interface'],
},
timestamp: {
type: String,
default: () => new Date().toISOString(),
},
});

export default (mongoose.models['SalinitySensors'] as
| mongoose.Model<SalinitySensors>
| undefined) ??
mongoose.model<SalinitySensors>(
'SalinitySensors',
SalinitySensorsSchema,
'salinity_sensors',
);
30 changes: 30 additions & 0 deletions src/website/models/TempSensors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import mongoose from 'mongoose';

interface TempSensor extends mongoose.Document {
temperature: number;
}

export interface TempSensors extends mongoose.Document {
tempSensors: TempSensor[];
timestamp: string;
}

const TempSensorsSchema = new mongoose.Schema<TempSensors>({
tempSensors: {
type: [
{
temperature: Number,
},
],
required: [true, 'Missing array of objects in TempSensors interface'],
},
timestamp: {
type: String,
default: () => new Date().toISOString(),
},
});

export default (mongoose.models['TempSensors'] as
| mongoose.Model<TempSensors>
| undefined) ??
mongoose.model<TempSensors>('TempSensors', TempSensorsSchema, 'temp_sensors');
22 changes: 19 additions & 3 deletions src/website/stores/Graphs/GraphsLayoutHelpers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Layout, LayoutItem, GraphId } from './GraphsTypes.ts';
import { isSplitGroup } from './GraphsTypes.ts';
import { isSplitGroup, getAllGraphIds } from './GraphsTypes.ts';

/**
* Find the index of the layout item containing a given graphId.
Expand Down Expand Up @@ -73,11 +73,13 @@ export const moveGraphToIndex = (
): Layout => {
const sourceIndex = findLayoutIndex(layout, sourceId);
if (sourceIndex === -1) return layout;
if (targetIndex === sourceIndex || targetIndex === sourceIndex + 1) return layout;
if (targetIndex === sourceIndex || targetIndex === sourceIndex + 1)
return layout;

const newLayout = [...layout];
const [removed] = newLayout.splice(sourceIndex, 1);
const adjustedIndex = targetIndex > sourceIndex ? targetIndex - 1 : targetIndex;
const adjustedIndex =
targetIndex > sourceIndex ? targetIndex - 1 : targetIndex;
newLayout.splice(adjustedIndex, 0, removed);
return newLayout;
};
Expand Down Expand Up @@ -108,6 +110,20 @@ export const extractGraph = (
return newLayout;
};

/**
* Append any default graph ids missing from a layout. Guards against layouts
* persisted to sessionStorage before newer graphs existed — without this,
* those graphs would silently never render.
*/
export const mergeMissingGraphIds = (
layout: Layout,
defaults: GraphId[],
): Layout => {
const present = new Set(getAllGraphIds(layout));
const missing = defaults.filter((id) => !present.has(id));
return missing.length > 0 ? [...layout, ...missing] : layout;
};

/**
* Place sourceId next to targetId as a vertical split row. Capped at two graphs
* per row, so dropping onto a target that is already in a split group is a
Expand Down
23 changes: 16 additions & 7 deletions src/website/stores/Graphs/GraphsReducers.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
import BaseReducer from '@/utils/BaseReducer';
import GraphsActions from './GraphsActions';
import { GraphsState, Layout } from './GraphsTypes';
import { GraphId, GraphsState, Layout } from './GraphsTypes';
import { AnyAction } from 'redux';
import { initSessionStorageData } from '@/utils/SessionStorage';
import { mergeMissingGraphIds } from './GraphsLayoutHelpers';

const DEFAULT_LAYOUT: GraphId[] = [
'GPS',
'BatteriesVoltage',
'BatteriesCurrent',
'WindSensors',
'Temperature',
'PH',
'Salinity',
];

export default class GraphsReducer extends BaseReducer {
initialState: GraphsState = {
layout: initSessionStorageData('Graph Layout', [
'GPS',
'BatteriesVoltage',
'BatteriesCurrent',
'WindSensors',
]) as Layout,
layout: mergeMissingGraphIds(
initSessionStorageData('Graph Layout', DEFAULT_LAYOUT) as Layout,
DEFAULT_LAYOUT,
),
error: null,
};

Expand Down
9 changes: 8 additions & 1 deletion src/website/stores/Graphs/GraphsTypes.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
export type GraphId = 'GPS' | 'BatteriesVoltage' | 'BatteriesCurrent' | 'WindSensors';
export type GraphId =
| 'GPS'
| 'BatteriesVoltage'
| 'BatteriesCurrent'
| 'WindSensors'
| 'Temperature'
| 'PH'
| 'Salinity';

// A layout item is either a single graph or a split group of graphs
export type LayoutItem = GraphId | GraphId[];
Expand Down
Loading