development
|
|
@ -13,5 +13,6 @@ data/config.ts
|
||||||
|
|
||||||
public/images-custom/*
|
public/images-custom/*
|
||||||
|
|
||||||
|
temp/wmf/
|
||||||
temp/config.*
|
temp/config.*
|
||||||
temp/wmf/
|
temp/*.csv
|
||||||
|
|
|
||||||
1
app.js
|
|
@ -57,6 +57,7 @@ app.use(urlPrefix, express.static(path.join("public")));
|
||||||
app.use(urlPrefix + "/lib/fa", express.static(path.join("node_modules", "@fortawesome", "fontawesome-free")));
|
app.use(urlPrefix + "/lib/fa", express.static(path.join("node_modules", "@fortawesome", "fontawesome-free")));
|
||||||
app.use(urlPrefix + "/lib/cityssm-bulma-webapp-js", express.static(path.join("node_modules", "@cityssm", "bulma-webapp-js")));
|
app.use(urlPrefix + "/lib/cityssm-bulma-webapp-js", express.static(path.join("node_modules", "@cityssm", "bulma-webapp-js")));
|
||||||
app.use(urlPrefix + "/lib/cityssm-bulma-js", express.static(path.join("node_modules", "@cityssm", "bulma-js", "dist")));
|
app.use(urlPrefix + "/lib/cityssm-bulma-js", express.static(path.join("node_modules", "@cityssm", "bulma-js", "dist")));
|
||||||
|
app.use(urlPrefix + "/lib/leaflet", express.static(path.join("node_modules", "leaflet", "dist")));
|
||||||
const sessionCookieName = configFunctions.getProperty("session.cookieName");
|
const sessionCookieName = configFunctions.getProperty("session.cookieName");
|
||||||
const FileStoreSession = FileStore(session);
|
const FileStoreSession = FileStore(session);
|
||||||
app.use(session({
|
app.use(session({
|
||||||
|
|
|
||||||
3
app.ts
|
|
@ -109,6 +109,9 @@ app.use(urlPrefix + "/lib/cityssm-bulma-webapp-js",
|
||||||
app.use(urlPrefix + "/lib/cityssm-bulma-js",
|
app.use(urlPrefix + "/lib/cityssm-bulma-js",
|
||||||
express.static(path.join("node_modules", "@cityssm", "bulma-js", "dist")));
|
express.static(path.join("node_modules", "@cityssm", "bulma-js", "dist")));
|
||||||
|
|
||||||
|
app.use(urlPrefix + "/lib/leaflet",
|
||||||
|
express.static(path.join("node_modules", "leaflet", "dist")));
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SESSION MANAGEMENT
|
* SESSION MANAGEMENT
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
import type { RequestHandler } from "express";
|
||||||
|
export declare const handler: RequestHandler;
|
||||||
|
export default handler;
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
import * as configFunctions from "../../helpers/functions.config.js";
|
||||||
|
import { getMaps } from "../../helpers/lotOccupancyDB/getMaps.js";
|
||||||
|
export const handler = (_request, response) => {
|
||||||
|
const maps = getMaps();
|
||||||
|
response.render("map-search", {
|
||||||
|
headTitle: configFunctions.getProperty("aliases.map") + " Search",
|
||||||
|
maps
|
||||||
|
});
|
||||||
|
};
|
||||||
|
export default handler;
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
import type {
|
||||||
|
RequestHandler
|
||||||
|
} from "express";
|
||||||
|
|
||||||
|
import * as configFunctions from "../../helpers/functions.config.js";
|
||||||
|
|
||||||
|
import {
|
||||||
|
getMaps
|
||||||
|
} from "../../helpers/lotOccupancyDB/getMaps.js";
|
||||||
|
|
||||||
|
|
||||||
|
export const handler: RequestHandler = (_request, response) => {
|
||||||
|
|
||||||
|
const maps = getMaps();
|
||||||
|
|
||||||
|
response.render("map-search", {
|
||||||
|
headTitle: configFunctions.getProperty("aliases.map") + " Search",
|
||||||
|
maps
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export default handler;
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
import type { RequestHandler } from "express";
|
||||||
|
export declare const handler: RequestHandler;
|
||||||
|
export default handler;
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
import * as configFunctions from "../../helpers/functions.config.js";
|
||||||
|
import { getMap } from "../../helpers/lotOccupancyDB/getMap.js";
|
||||||
|
export const handler = (request, response) => {
|
||||||
|
const map = getMap(request.params.mapId);
|
||||||
|
if (!map) {
|
||||||
|
return response.redirect(configFunctions.getProperty("reverseProxy.urlPrefix") + "/maps/?error=mapIdNotFound");
|
||||||
|
}
|
||||||
|
response.render("map-view", {
|
||||||
|
headTitle: map.mapName,
|
||||||
|
map
|
||||||
|
});
|
||||||
|
};
|
||||||
|
export default handler;
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
import type { RequestHandler } from "express";
|
||||||
|
|
||||||
|
import * as configFunctions from "../../helpers/functions.config.js";
|
||||||
|
|
||||||
|
import { getMap } from "../../helpers/lotOccupancyDB/getMap.js";
|
||||||
|
|
||||||
|
|
||||||
|
export const handler: RequestHandler = (request, response) => {
|
||||||
|
|
||||||
|
const map = getMap(request.params.mapId);
|
||||||
|
|
||||||
|
if (!map) {
|
||||||
|
return response.redirect(configFunctions.getProperty("reverseProxy.urlPrefix") + "/maps/?error=mapIdNotFound");
|
||||||
|
}
|
||||||
|
|
||||||
|
response.render("map-view", {
|
||||||
|
headTitle: map.mapName,
|
||||||
|
map
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export default handler;
|
||||||
|
|
@ -68,6 +68,7 @@ export const initLotOccupancyDB = () => {
|
||||||
" lotTypeId integer not null," +
|
" lotTypeId integer not null," +
|
||||||
" lotName varchar(100)," +
|
" lotName varchar(100)," +
|
||||||
" mapId integer," +
|
" mapId integer," +
|
||||||
|
" mapKey varchar(100)," +
|
||||||
" lotLatitude decimal(10, 8) check (lotLatitude between -90 and 90)," +
|
" lotLatitude decimal(10, 8) check (lotLatitude between -90 and 90)," +
|
||||||
" lotLongitude decimal(11, 8) check (lotLongitude between -180 and 180)," +
|
" lotLongitude decimal(11, 8) check (lotLongitude between -180 and 180)," +
|
||||||
" lotTypeStatusId integer," +
|
" lotTypeStatusId integer," +
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,7 @@ export const initLotOccupancyDB = (): boolean => {
|
||||||
" lotTypeId integer not null," +
|
" lotTypeId integer not null," +
|
||||||
" lotName varchar(100)," +
|
" lotName varchar(100)," +
|
||||||
" mapId integer," +
|
" mapId integer," +
|
||||||
|
" mapKey varchar(100)," +
|
||||||
|
|
||||||
" lotLatitude decimal(10, 8) check (lotLatitude between -90 and 90)," +
|
" lotLatitude decimal(10, 8) check (lotLatitude between -90 and 90)," +
|
||||||
" lotLongitude decimal(11, 8) check (lotLongitude between -180 and 180)," +
|
" lotLongitude decimal(11, 8) check (lotLongitude between -180 and 180)," +
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
import type * as recordTypes from "../../types/recordTypes";
|
||||||
|
interface AddLotForm {
|
||||||
|
lotName: string;
|
||||||
|
lotTypeId: string | number;
|
||||||
|
lotTypeStatusId: string | number;
|
||||||
|
mapId: string | number;
|
||||||
|
mapKey: string;
|
||||||
|
lotLatitude: string;
|
||||||
|
lotLongitude: string;
|
||||||
|
}
|
||||||
|
export declare const addLot: (lotForm: AddLotForm, requestSession: recordTypes.PartialSession) => number;
|
||||||
|
export default addLot;
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
import sqlite from "better-sqlite3";
|
||||||
|
import { lotOccupancyDB as databasePath } from "../../data/databasePaths.js";
|
||||||
|
export const addLot = (lotForm, requestSession) => {
|
||||||
|
const database = sqlite(databasePath);
|
||||||
|
const rightNowMillis = Date.now();
|
||||||
|
const result = database
|
||||||
|
.prepare("insert into Lots (" +
|
||||||
|
"lotName, lotTypeId, lotTypeStatusId," +
|
||||||
|
" mapId, mapKey," +
|
||||||
|
" lotLatitude, lotLongitude," +
|
||||||
|
" recordCreate_userName, recordCreate_timeMillis," +
|
||||||
|
" recordUpdate_userName, recordUpdate_timeMillis)" +
|
||||||
|
" values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
|
||||||
|
.run(lotForm.lotName, lotForm.lotTypeId, (lotForm.lotTypeStatusId === "" ? undefined : lotForm.lotTypeStatusId), (lotForm.mapId === "" ? undefined : lotForm.mapId), lotForm.mapKey, (lotForm.lotLatitude === "" ? undefined : lotForm.lotLatitude), (lotForm.lotLongitude === "" ? undefined : lotForm.lotLongitude), requestSession.user.userName, rightNowMillis, requestSession.user.userName, rightNowMillis);
|
||||||
|
database.close();
|
||||||
|
return result.lastInsertRowid;
|
||||||
|
};
|
||||||
|
export default addLot;
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
import sqlite from "better-sqlite3";
|
||||||
|
import { lotOccupancyDB as databasePath } from "../../data/databasePaths.js";
|
||||||
|
|
||||||
|
import type * as recordTypes from "../../types/recordTypes";
|
||||||
|
|
||||||
|
|
||||||
|
interface AddLotForm {
|
||||||
|
lotName: string;
|
||||||
|
lotTypeId: string | number;
|
||||||
|
lotTypeStatusId: string | number;
|
||||||
|
|
||||||
|
mapId: string | number;
|
||||||
|
mapKey: string;
|
||||||
|
|
||||||
|
lotLatitude: string;
|
||||||
|
lotLongitude: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const addLot =
|
||||||
|
(lotForm: AddLotForm, requestSession: recordTypes.PartialSession): number => {
|
||||||
|
|
||||||
|
const database = sqlite(databasePath);
|
||||||
|
|
||||||
|
const rightNowMillis = Date.now();
|
||||||
|
|
||||||
|
const result = database
|
||||||
|
.prepare("insert into Lots (" +
|
||||||
|
"lotName, lotTypeId, lotTypeStatusId," +
|
||||||
|
" mapId, mapKey," +
|
||||||
|
" lotLatitude, lotLongitude," +
|
||||||
|
" recordCreate_userName, recordCreate_timeMillis," +
|
||||||
|
" recordUpdate_userName, recordUpdate_timeMillis)" +
|
||||||
|
" values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
|
||||||
|
.run(lotForm.lotName,
|
||||||
|
lotForm.lotTypeId,
|
||||||
|
(lotForm.lotTypeStatusId === "" ? undefined : lotForm.lotTypeStatusId),
|
||||||
|
(lotForm.mapId === "" ? undefined : lotForm.mapId),
|
||||||
|
lotForm.mapKey,
|
||||||
|
(lotForm.lotLatitude === "" ? undefined : lotForm.lotLatitude),
|
||||||
|
(lotForm.lotLongitude === "" ? undefined : lotForm.lotLongitude),
|
||||||
|
requestSession.user.userName,
|
||||||
|
rightNowMillis,
|
||||||
|
requestSession.user.userName,
|
||||||
|
rightNowMillis);
|
||||||
|
|
||||||
|
database.close();
|
||||||
|
|
||||||
|
return result.lastInsertRowid as number;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export default addLot;
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
import type * as recordTypes from "../../types/recordTypes";
|
||||||
|
interface AddMapForm {
|
||||||
|
mapName: string;
|
||||||
|
mapDescription: string;
|
||||||
|
mapSVG: string;
|
||||||
|
mapLatitude: string;
|
||||||
|
mapLongitude: string;
|
||||||
|
mapAddress1: string;
|
||||||
|
mapAddress2: string;
|
||||||
|
mapCity: string;
|
||||||
|
mapProvince: string;
|
||||||
|
mapPostalCode: string;
|
||||||
|
mapPhoneNumber: string;
|
||||||
|
}
|
||||||
|
export declare const addMap: (mapForm: AddMapForm, requestSession: recordTypes.PartialSession) => number;
|
||||||
|
export default addMap;
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
import sqlite from "better-sqlite3";
|
||||||
|
import { lotOccupancyDB as databasePath } from "../../data/databasePaths.js";
|
||||||
|
export const addMap = (mapForm, requestSession) => {
|
||||||
|
const database = sqlite(databasePath);
|
||||||
|
const rightNowMillis = Date.now();
|
||||||
|
const result = database
|
||||||
|
.prepare("insert into Maps (" +
|
||||||
|
"mapName, mapDescription," +
|
||||||
|
" mapSVG, mapLatitude, mapLongitude," +
|
||||||
|
" mapAddress1, mapAddress2, mapCity, mapProvince, mapPostalCode, mapPhoneNumber," +
|
||||||
|
" recordCreate_userName, recordCreate_timeMillis," +
|
||||||
|
" recordUpdate_userName, recordUpdate_timeMillis)" +
|
||||||
|
" values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
|
||||||
|
.run(mapForm.mapName, mapForm.mapDescription, mapForm.mapSVG, (mapForm.mapLatitude === "" ? undefined : mapForm.mapLatitude), (mapForm.mapLongitude === "" ? undefined : mapForm.mapLongitude), mapForm.mapAddress1, mapForm.mapAddress2, mapForm.mapCity, mapForm.mapProvince, mapForm.mapPostalCode, mapForm.mapPhoneNumber, requestSession.user.userName, rightNowMillis, requestSession.user.userName, rightNowMillis);
|
||||||
|
database.close();
|
||||||
|
return result.lastInsertRowid;
|
||||||
|
};
|
||||||
|
export default addMap;
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
import sqlite from "better-sqlite3";
|
||||||
|
import { lotOccupancyDB as databasePath } from "../../data/databasePaths.js";
|
||||||
|
|
||||||
|
import type * as recordTypes from "../../types/recordTypes";
|
||||||
|
|
||||||
|
|
||||||
|
interface AddMapForm {
|
||||||
|
mapName: string;
|
||||||
|
mapDescription: string;
|
||||||
|
mapSVG: string;
|
||||||
|
mapLatitude: string;
|
||||||
|
mapLongitude: string;
|
||||||
|
mapAddress1: string;
|
||||||
|
mapAddress2: string;
|
||||||
|
mapCity: string;
|
||||||
|
mapProvince: string;
|
||||||
|
mapPostalCode: string;
|
||||||
|
mapPhoneNumber: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const addMap =
|
||||||
|
(mapForm: AddMapForm, requestSession: recordTypes.PartialSession): number => {
|
||||||
|
|
||||||
|
const database = sqlite(databasePath);
|
||||||
|
|
||||||
|
const rightNowMillis = Date.now();
|
||||||
|
|
||||||
|
const result = database
|
||||||
|
.prepare("insert into Maps (" +
|
||||||
|
"mapName, mapDescription," +
|
||||||
|
" mapSVG, mapLatitude, mapLongitude," +
|
||||||
|
" mapAddress1, mapAddress2, mapCity, mapProvince, mapPostalCode, mapPhoneNumber," +
|
||||||
|
" recordCreate_userName, recordCreate_timeMillis," +
|
||||||
|
" recordUpdate_userName, recordUpdate_timeMillis)" +
|
||||||
|
" values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
|
||||||
|
.run(mapForm.mapName,
|
||||||
|
mapForm.mapDescription,
|
||||||
|
mapForm.mapSVG,
|
||||||
|
(mapForm.mapLatitude === "" ? undefined : mapForm.mapLatitude),
|
||||||
|
(mapForm.mapLongitude === "" ? undefined : mapForm.mapLongitude),
|
||||||
|
mapForm.mapAddress1,
|
||||||
|
mapForm.mapAddress2,
|
||||||
|
mapForm.mapCity,
|
||||||
|
mapForm.mapProvince,
|
||||||
|
mapForm.mapPostalCode,
|
||||||
|
mapForm.mapPhoneNumber,
|
||||||
|
requestSession.user.userName,
|
||||||
|
rightNowMillis,
|
||||||
|
requestSession.user.userName,
|
||||||
|
rightNowMillis);
|
||||||
|
|
||||||
|
database.close();
|
||||||
|
|
||||||
|
return result.lastInsertRowid as number;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export default addMap;
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
import sqlite from "better-sqlite3";
|
||||||
|
import type * as recordTypes from "../../types/recordTypes";
|
||||||
|
interface AddOccupantForm {
|
||||||
|
occupantName: string;
|
||||||
|
occupantAddress1: string;
|
||||||
|
occupantAddress2: string;
|
||||||
|
occupantCity: string;
|
||||||
|
occupantProvince: string;
|
||||||
|
occupantPostalCode: string;
|
||||||
|
occupantPhoneNumber: string;
|
||||||
|
}
|
||||||
|
export declare const addOccupant: (occupantForm: AddOccupantForm, requestSession: recordTypes.PartialSession, connectedDatabase?: sqlite.Database) => number;
|
||||||
|
export default addOccupant;
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
import sqlite from "better-sqlite3";
|
||||||
|
import { lotOccupancyDB as databasePath } from "../../data/databasePaths.js";
|
||||||
|
export const addOccupant = (occupantForm, requestSession, connectedDatabase) => {
|
||||||
|
const database = connectedDatabase || sqlite(databasePath);
|
||||||
|
const rightNowMillis = Date.now();
|
||||||
|
const result = database
|
||||||
|
.prepare("insert into Occupants (" +
|
||||||
|
"occupantName," +
|
||||||
|
" occupantAddress1, occupantAddress2, occupantCity, occupantProvince, occupantPostalCode, occupantPhoneNumber," +
|
||||||
|
" recordCreate_userName, recordCreate_timeMillis," +
|
||||||
|
" recordUpdate_userName, recordUpdate_timeMillis)" +
|
||||||
|
" values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
|
||||||
|
.run(occupantForm.occupantName, occupantForm.occupantAddress1, occupantForm.occupantAddress2, occupantForm.occupantCity, occupantForm.occupantProvince, occupantForm.occupantPostalCode, occupantForm.occupantPhoneNumber, requestSession.user.userName, rightNowMillis, requestSession.user.userName, rightNowMillis);
|
||||||
|
if (!connectedDatabase) {
|
||||||
|
database.close();
|
||||||
|
}
|
||||||
|
return result.lastInsertRowid;
|
||||||
|
};
|
||||||
|
export default addOccupant;
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
import sqlite from "better-sqlite3";
|
||||||
|
import {
|
||||||
|
lotOccupancyDB as databasePath
|
||||||
|
} from "../../data/databasePaths.js";
|
||||||
|
|
||||||
|
import type * as recordTypes from "../../types/recordTypes";
|
||||||
|
|
||||||
|
|
||||||
|
interface AddOccupantForm {
|
||||||
|
occupantName: string;
|
||||||
|
occupantAddress1: string;
|
||||||
|
occupantAddress2: string;
|
||||||
|
occupantCity: string;
|
||||||
|
occupantProvince: string;
|
||||||
|
occupantPostalCode: string;
|
||||||
|
occupantPhoneNumber: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const addOccupant =
|
||||||
|
(occupantForm: AddOccupantForm, requestSession: recordTypes.PartialSession, connectedDatabase ? : sqlite.Database): number => {
|
||||||
|
|
||||||
|
const database = connectedDatabase || sqlite(databasePath);
|
||||||
|
|
||||||
|
const rightNowMillis = Date.now();
|
||||||
|
|
||||||
|
const result = database
|
||||||
|
.prepare("insert into Occupants (" +
|
||||||
|
"occupantName," +
|
||||||
|
" occupantAddress1, occupantAddress2, occupantCity, occupantProvince, occupantPostalCode, occupantPhoneNumber," +
|
||||||
|
" recordCreate_userName, recordCreate_timeMillis," +
|
||||||
|
" recordUpdate_userName, recordUpdate_timeMillis)" +
|
||||||
|
" values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
|
||||||
|
.run(occupantForm.occupantName,
|
||||||
|
occupantForm.occupantAddress1,
|
||||||
|
occupantForm.occupantAddress2,
|
||||||
|
occupantForm.occupantCity,
|
||||||
|
occupantForm.occupantProvince,
|
||||||
|
occupantForm.occupantPostalCode,
|
||||||
|
occupantForm.occupantPhoneNumber,
|
||||||
|
requestSession.user.userName,
|
||||||
|
rightNowMillis,
|
||||||
|
requestSession.user.userName,
|
||||||
|
rightNowMillis);
|
||||||
|
|
||||||
|
if (!connectedDatabase) {
|
||||||
|
database.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.lastInsertRowid as number;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export default addOccupant;
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
import type * as recordTypes from "../../types/recordTypes";
|
||||||
|
export declare const getLotTypes: () => recordTypes.LotType[];
|
||||||
|
export default getLotTypes;
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
import sqlite from "better-sqlite3";
|
||||||
|
import { lotOccupancyDB as databasePath } from "../../data/databasePaths.js";
|
||||||
|
export const getLotTypes = () => {
|
||||||
|
const database = sqlite(databasePath, {
|
||||||
|
readonly: true
|
||||||
|
});
|
||||||
|
const lotTypes = database
|
||||||
|
.prepare("select * from LotTypes" +
|
||||||
|
" where recordDelete_timeMillis is null" +
|
||||||
|
" order by orderNumber, lotType")
|
||||||
|
.all();
|
||||||
|
database.close();
|
||||||
|
return lotTypes;
|
||||||
|
};
|
||||||
|
export default getLotTypes;
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
import sqlite from "better-sqlite3";
|
||||||
|
import { lotOccupancyDB as databasePath } from "../../data/databasePaths.js";
|
||||||
|
|
||||||
|
import type * as recordTypes from "../../types/recordTypes";
|
||||||
|
|
||||||
|
|
||||||
|
export const getLotTypes = (): recordTypes.LotType[] => {
|
||||||
|
|
||||||
|
const database = sqlite(databasePath, {
|
||||||
|
readonly: true
|
||||||
|
});
|
||||||
|
|
||||||
|
const lotTypes: recordTypes.LotType[] = database
|
||||||
|
.prepare("select * from LotTypes" +
|
||||||
|
" where recordDelete_timeMillis is null" +
|
||||||
|
" order by orderNumber, lotType")
|
||||||
|
.all();
|
||||||
|
|
||||||
|
database.close();
|
||||||
|
|
||||||
|
return lotTypes;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export default getLotTypes;
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
import type * as recordTypes from "../../types/recordTypes";
|
||||||
|
export declare const getMap: (mapId: number | string) => recordTypes.Map;
|
||||||
|
export default getMap;
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
import sqlite from "better-sqlite3";
|
||||||
|
import { lotOccupancyDB as databasePath } from "../../data/databasePaths.js";
|
||||||
|
export const getMap = (mapId) => {
|
||||||
|
const database = sqlite(databasePath, {
|
||||||
|
readonly: true
|
||||||
|
});
|
||||||
|
const map = database
|
||||||
|
.prepare("select m.mapId, m.mapName, m.mapDescription," +
|
||||||
|
" m.mapLatitude, m.mapLongitude, m.mapSVG," +
|
||||||
|
" m.mapAddress1, m.mapAddress2, m.mapCity, m.mapProvince, m.mapPostalCode, m.mapPhoneNumber," +
|
||||||
|
" m.recordCreate_userName, m.recordCreate_timeMillis," +
|
||||||
|
" m.recordUpdate_userName, m.recordUpdate_timeMillis," +
|
||||||
|
" m.recordDelete_userName, m.recordDelete_timeMillis," +
|
||||||
|
" count(l.lotId) as lotCount" +
|
||||||
|
" from Maps m" +
|
||||||
|
" left join Lots l on m.mapId = l.mapId and l.recordDelete_timeMillis is null" +
|
||||||
|
" where m.mapId = ?" +
|
||||||
|
" group by m.mapId, m.mapName, m.mapDescription," +
|
||||||
|
" m.mapLatitude, m.mapLongitude, m.mapSVG," +
|
||||||
|
" m.mapAddress1, m.mapAddress2, m.mapCity, m.mapProvince, m.mapPostalCode, m.mapPhoneNumber," +
|
||||||
|
" m.recordCreate_userName, m.recordCreate_timeMillis," +
|
||||||
|
" m.recordUpdate_userName, m.recordUpdate_timeMillis," +
|
||||||
|
" m.recordDelete_userName, m.recordDelete_timeMillis")
|
||||||
|
.get(mapId);
|
||||||
|
database.close();
|
||||||
|
return map;
|
||||||
|
};
|
||||||
|
export default getMap;
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
import sqlite from "better-sqlite3";
|
||||||
|
import { lotOccupancyDB as databasePath } from "../../data/databasePaths.js";
|
||||||
|
|
||||||
|
import type * as recordTypes from "../../types/recordTypes";
|
||||||
|
|
||||||
|
|
||||||
|
export const getMap = (mapId: number | string): recordTypes.Map => {
|
||||||
|
|
||||||
|
const database = sqlite(databasePath, {
|
||||||
|
readonly: true
|
||||||
|
});
|
||||||
|
|
||||||
|
const map: recordTypes.Map = database
|
||||||
|
.prepare("select m.mapId, m.mapName, m.mapDescription," +
|
||||||
|
" m.mapLatitude, m.mapLongitude, m.mapSVG," +
|
||||||
|
" m.mapAddress1, m.mapAddress2, m.mapCity, m.mapProvince, m.mapPostalCode, m.mapPhoneNumber," +
|
||||||
|
" m.recordCreate_userName, m.recordCreate_timeMillis," +
|
||||||
|
" m.recordUpdate_userName, m.recordUpdate_timeMillis," +
|
||||||
|
" m.recordDelete_userName, m.recordDelete_timeMillis," +
|
||||||
|
" count(l.lotId) as lotCount" +
|
||||||
|
" from Maps m" +
|
||||||
|
" left join Lots l on m.mapId = l.mapId and l.recordDelete_timeMillis is null" +
|
||||||
|
" where m.mapId = ?" +
|
||||||
|
" group by m.mapId, m.mapName, m.mapDescription," +
|
||||||
|
" m.mapLatitude, m.mapLongitude, m.mapSVG," +
|
||||||
|
" m.mapAddress1, m.mapAddress2, m.mapCity, m.mapProvince, m.mapPostalCode, m.mapPhoneNumber," +
|
||||||
|
" m.recordCreate_userName, m.recordCreate_timeMillis," +
|
||||||
|
" m.recordUpdate_userName, m.recordUpdate_timeMillis," +
|
||||||
|
" m.recordDelete_userName, m.recordDelete_timeMillis")
|
||||||
|
.get(mapId);
|
||||||
|
|
||||||
|
database.close();
|
||||||
|
|
||||||
|
return map;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export default getMap;
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
import type * as recordTypes from "../../types/recordTypes";
|
||||||
|
interface GetMapsFilters {
|
||||||
|
}
|
||||||
|
export declare const getMaps: (filters?: GetMapsFilters) => recordTypes.Map[];
|
||||||
|
export default getMaps;
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
import sqlite from "better-sqlite3";
|
||||||
|
import { lotOccupancyDB as databasePath } from "../../data/databasePaths.js";
|
||||||
|
export const getMaps = (filters) => {
|
||||||
|
const database = sqlite(databasePath, {
|
||||||
|
readonly: true
|
||||||
|
});
|
||||||
|
const maps = database
|
||||||
|
.prepare("select m.mapId, m.mapName, m.mapDescription," +
|
||||||
|
" m.mapLatitude, m.mapLongitude, m.mapSVG," +
|
||||||
|
" m.mapAddress1, m.mapAddress2, m.mapCity, m.mapProvince, m.mapPostalCode, m.mapPhoneNumber," +
|
||||||
|
" l.lotCount" +
|
||||||
|
" from Maps m" +
|
||||||
|
(" left join (" +
|
||||||
|
"select mapId, count(lotId) as lotCount" +
|
||||||
|
" from Lots" +
|
||||||
|
" where recordDelete_timeMillis is null" +
|
||||||
|
" group by mapId) l on m.mapId = l.mapId") +
|
||||||
|
" where m.recordDelete_timeMillis is null" +
|
||||||
|
" order by m.mapName, m.mapId")
|
||||||
|
.all();
|
||||||
|
database.close();
|
||||||
|
return maps;
|
||||||
|
};
|
||||||
|
export default getMaps;
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
import sqlite from "better-sqlite3";
|
||||||
|
import {
|
||||||
|
lotOccupancyDB as databasePath
|
||||||
|
} from "../../data/databasePaths.js";
|
||||||
|
|
||||||
|
import type * as recordTypes from "../../types/recordTypes";
|
||||||
|
|
||||||
|
|
||||||
|
interface GetMapsFilters {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const getMaps = (filters ? : GetMapsFilters): recordTypes.Map[] => {
|
||||||
|
|
||||||
|
const database = sqlite(databasePath, {
|
||||||
|
readonly: true
|
||||||
|
});
|
||||||
|
|
||||||
|
const maps: recordTypes.Map[] = database
|
||||||
|
.prepare("select m.mapId, m.mapName, m.mapDescription," +
|
||||||
|
" m.mapLatitude, m.mapLongitude, m.mapSVG," +
|
||||||
|
" m.mapAddress1, m.mapAddress2, m.mapCity, m.mapProvince, m.mapPostalCode, m.mapPhoneNumber," +
|
||||||
|
" l.lotCount" +
|
||||||
|
" from Maps m" +
|
||||||
|
(" left join (" +
|
||||||
|
"select mapId, count(lotId) as lotCount" +
|
||||||
|
" from Lots" +
|
||||||
|
" where recordDelete_timeMillis is null" +
|
||||||
|
" group by mapId) l on m.mapId = l.mapId") +
|
||||||
|
" where m.recordDelete_timeMillis is null" +
|
||||||
|
" order by m.mapName, m.mapId")
|
||||||
|
.all();
|
||||||
|
|
||||||
|
database.close();
|
||||||
|
|
||||||
|
return maps;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export default getMaps;
|
||||||
|
|
@ -27,6 +27,7 @@
|
||||||
"express-rate-limit": "^6.4.0",
|
"express-rate-limit": "^6.4.0",
|
||||||
"express-session": "^1.17.3",
|
"express-session": "^1.17.3",
|
||||||
"http-errors": "^2.0.0",
|
"http-errors": "^2.0.0",
|
||||||
|
"leaflet": "^1.8.0",
|
||||||
"session-file-store": "^1.5.0"
|
"session-file-store": "^1.5.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
@ -46,9 +47,11 @@
|
||||||
"@types/gulp-minify": "^3.1.1",
|
"@types/gulp-minify": "^3.1.1",
|
||||||
"@types/gulp-sass": "^5.0.0",
|
"@types/gulp-sass": "^5.0.0",
|
||||||
"@types/http-errors": "^1.8.2",
|
"@types/http-errors": "^1.8.2",
|
||||||
|
"@types/leaflet": "^1.7.11",
|
||||||
"@types/mocha": "^9.1.1",
|
"@types/mocha": "^9.1.1",
|
||||||
"@types/mssql": "^8.0.3",
|
"@types/mssql": "^8.0.3",
|
||||||
"@types/node-windows": "^0.1.2",
|
"@types/node-windows": "^0.1.2",
|
||||||
|
"@types/papaparse": "^5.3.2",
|
||||||
"@types/session-file-store": "^1.2.2",
|
"@types/session-file-store": "^1.2.2",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.30.6",
|
"@typescript-eslint/eslint-plugin": "^5.30.6",
|
||||||
"@typescript-eslint/parser": "^5.30.6",
|
"@typescript-eslint/parser": "^5.30.6",
|
||||||
|
|
@ -62,6 +65,7 @@
|
||||||
"gulp-minify": "^3.1.0",
|
"gulp-minify": "^3.1.0",
|
||||||
"gulp-sass": "^5.1.0",
|
"gulp-sass": "^5.1.0",
|
||||||
"nodemon": "^2.0.19",
|
"nodemon": "^2.0.19",
|
||||||
|
"papaparse": "^5.3.2",
|
||||||
"sass": "^1.53.0"
|
"sass": "^1.53.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|
@ -843,6 +847,12 @@
|
||||||
"@types/express": "*"
|
"@types/express": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/geojson": {
|
||||||
|
"version": "7946.0.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.10.tgz",
|
||||||
|
"integrity": "sha512-Nmh0K3iWQJzniTuPRcJn5hxXkfB1T1pgB89SBig5PlJQU5yocazeu4jATJlaA0GYFKWMqDdvYemoSnF2pXgLVA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@types/glob": {
|
"node_modules/@types/glob": {
|
||||||
"version": "7.2.0",
|
"version": "7.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz",
|
||||||
|
|
@ -930,6 +940,15 @@
|
||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/leaflet": {
|
||||||
|
"version": "1.7.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.7.11.tgz",
|
||||||
|
"integrity": "sha512-VwAYom2pfIAf/pLj1VR5aLltd4tOtHyvfaJlNYCoejzP2nu52PrMi1ehsLRMUS+bgafmIIKBV1cMfKeS+uJ0Vg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/geojson": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/mime": {
|
"node_modules/@types/mime": {
|
||||||
"version": "1.3.2",
|
"version": "1.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz",
|
||||||
|
|
@ -1019,6 +1038,15 @@
|
||||||
"integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==",
|
"integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/papaparse": {
|
||||||
|
"version": "5.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/papaparse/-/papaparse-5.3.2.tgz",
|
||||||
|
"integrity": "sha512-BNbCHJkTE4RwmAFkCxEalET4mDvGr/1ld7ZtQ4i/laWI/iiVt+GL07stdvufle4KfywyvloqqpIiJscXNCrKxA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/qs": {
|
"node_modules/@types/qs": {
|
||||||
"version": "6.9.7",
|
"version": "6.9.7",
|
||||||
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
|
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
|
||||||
|
|
@ -6329,6 +6357,11 @@
|
||||||
"node": ">= 0.10"
|
"node": ">= 0.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/leaflet": {
|
||||||
|
"version": "1.8.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.8.0.tgz",
|
||||||
|
"integrity": "sha512-gwhMjFCQiYs3x/Sf+d49f10ERXaEFCPr+nVTryhAW8DWbMGqJqt9G4XuIaHmFW08zYvhgdzqXGr8AlW8v8dQkA=="
|
||||||
|
},
|
||||||
"node_modules/levn": {
|
"node_modules/levn": {
|
||||||
"version": "0.4.1",
|
"version": "0.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
|
||||||
|
|
@ -7506,6 +7539,12 @@
|
||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/papaparse": {
|
||||||
|
"version": "5.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.3.2.tgz",
|
||||||
|
"integrity": "sha512-6dNZu0Ki+gyV0eBsFKJhYr+MdQYAzFUGlBMNj3GNrmHxmz1lfRa24CjFObPXtjcetlOv5Ad299MhIK0znp3afw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/parent-module": {
|
"node_modules/parent-module": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
||||||
|
|
@ -11187,6 +11226,12 @@
|
||||||
"@types/express": "*"
|
"@types/express": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/geojson": {
|
||||||
|
"version": "7946.0.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.10.tgz",
|
||||||
|
"integrity": "sha512-Nmh0K3iWQJzniTuPRcJn5hxXkfB1T1pgB89SBig5PlJQU5yocazeu4jATJlaA0GYFKWMqDdvYemoSnF2pXgLVA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"@types/glob": {
|
"@types/glob": {
|
||||||
"version": "7.2.0",
|
"version": "7.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz",
|
||||||
|
|
@ -11274,6 +11319,15 @@
|
||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/leaflet": {
|
||||||
|
"version": "1.7.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.7.11.tgz",
|
||||||
|
"integrity": "sha512-VwAYom2pfIAf/pLj1VR5aLltd4tOtHyvfaJlNYCoejzP2nu52PrMi1ehsLRMUS+bgafmIIKBV1cMfKeS+uJ0Vg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/geojson": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/mime": {
|
"@types/mime": {
|
||||||
"version": "1.3.2",
|
"version": "1.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz",
|
||||||
|
|
@ -11362,6 +11416,15 @@
|
||||||
"integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==",
|
"integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@types/papaparse": {
|
||||||
|
"version": "5.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/papaparse/-/papaparse-5.3.2.tgz",
|
||||||
|
"integrity": "sha512-BNbCHJkTE4RwmAFkCxEalET4mDvGr/1ld7ZtQ4i/laWI/iiVt+GL07stdvufle4KfywyvloqqpIiJscXNCrKxA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/qs": {
|
"@types/qs": {
|
||||||
"version": "6.9.7",
|
"version": "6.9.7",
|
||||||
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
|
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
|
||||||
|
|
@ -15459,6 +15522,11 @@
|
||||||
"flush-write-stream": "^1.0.2"
|
"flush-write-stream": "^1.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"leaflet": {
|
||||||
|
"version": "1.8.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.8.0.tgz",
|
||||||
|
"integrity": "sha512-gwhMjFCQiYs3x/Sf+d49f10ERXaEFCPr+nVTryhAW8DWbMGqJqt9G4XuIaHmFW08zYvhgdzqXGr8AlW8v8dQkA=="
|
||||||
|
},
|
||||||
"levn": {
|
"levn": {
|
||||||
"version": "0.4.1",
|
"version": "0.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
|
||||||
|
|
@ -16381,6 +16449,12 @@
|
||||||
"integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==",
|
"integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"papaparse": {
|
||||||
|
"version": "5.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.3.2.tgz",
|
||||||
|
"integrity": "sha512-6dNZu0Ki+gyV0eBsFKJhYr+MdQYAzFUGlBMNj3GNrmHxmz1lfRa24CjFObPXtjcetlOv5Ad299MhIK0znp3afw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"parent-module": {
|
"parent-module": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
||||||
|
|
|
||||||
11
package.json
|
|
@ -9,15 +9,12 @@
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build:version": "npx genversion --es6 --semi version.js",
|
"build:version": "npx genversion --es6 --semi version.js",
|
||||||
|
|
||||||
"start": "cross-env NODE_ENV=production node ./bin/www",
|
"start": "cross-env NODE_ENV=production node ./bin/www",
|
||||||
|
|
||||||
"dev:test": "cross-env NODE_ENV=dev DEBUG=lot-occupancy-system:* TEST_DATABASES=true nodemon ./bin/www",
|
"dev:test": "cross-env NODE_ENV=dev DEBUG=lot-occupancy-system:* TEST_DATABASES=true nodemon ./bin/www",
|
||||||
"dev:live": "cross-env NODE_ENV=dev DEBUG=lot-occupancy-system:* nodemon ./bin/www",
|
"dev:live": "cross-env NODE_ENV=dev DEBUG=lot-occupancy-system:* nodemon ./bin/www",
|
||||||
|
|
||||||
"test": "echo \"Error: no test specified\" && exit 1",
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
|
"temp:legacy:importFromCSV": "cross-env NODE_ENV=dev DEBUG=lot-occupancy-system:* TEST_DATABASES=true node ./temp/legacy.importFromCSV.js",
|
||||||
"temp:so:importMaps": "node ./temp/so.importMaps.js"
|
"temp:so:exportMaps": "node ./temp/so.exportMaps.js"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|
@ -49,6 +46,7 @@
|
||||||
"express-rate-limit": "^6.4.0",
|
"express-rate-limit": "^6.4.0",
|
||||||
"express-session": "^1.17.3",
|
"express-session": "^1.17.3",
|
||||||
"http-errors": "^2.0.0",
|
"http-errors": "^2.0.0",
|
||||||
|
"leaflet": "^1.8.0",
|
||||||
"session-file-store": "^1.5.0"
|
"session-file-store": "^1.5.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
@ -68,9 +66,11 @@
|
||||||
"@types/gulp-minify": "^3.1.1",
|
"@types/gulp-minify": "^3.1.1",
|
||||||
"@types/gulp-sass": "^5.0.0",
|
"@types/gulp-sass": "^5.0.0",
|
||||||
"@types/http-errors": "^1.8.2",
|
"@types/http-errors": "^1.8.2",
|
||||||
|
"@types/leaflet": "^1.7.11",
|
||||||
"@types/mocha": "^9.1.1",
|
"@types/mocha": "^9.1.1",
|
||||||
"@types/mssql": "^8.0.3",
|
"@types/mssql": "^8.0.3",
|
||||||
"@types/node-windows": "^0.1.2",
|
"@types/node-windows": "^0.1.2",
|
||||||
|
"@types/papaparse": "^5.3.2",
|
||||||
"@types/session-file-store": "^1.2.2",
|
"@types/session-file-store": "^1.2.2",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.30.6",
|
"@typescript-eslint/eslint-plugin": "^5.30.6",
|
||||||
"@typescript-eslint/parser": "^5.30.6",
|
"@typescript-eslint/parser": "^5.30.6",
|
||||||
|
|
@ -84,6 +84,7 @@
|
||||||
"gulp-minify": "^3.1.0",
|
"gulp-minify": "^3.1.0",
|
||||||
"gulp-sass": "^5.1.0",
|
"gulp-sass": "^5.1.0",
|
||||||
"nodemon": "^2.0.19",
|
"nodemon": "^2.0.19",
|
||||||
|
"papaparse": "^5.3.2",
|
||||||
"sass": "^1.53.0"
|
"sass": "^1.53.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,93 +0,0 @@
|
||||||
"use strict";
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
(() => {
|
|
||||||
const urlPrefix = document.querySelector("main").dataset.urlPrefix;
|
|
||||||
const formElement = document.querySelector("#form--filters");
|
|
||||||
const limitElement = document.querySelector("#filter--limit");
|
|
||||||
const offsetElement = document.querySelector("#filter--offset");
|
|
||||||
const searchResultsElement = document.querySelector("#container--searchResults");
|
|
||||||
const doLicenceSearchFunction = () => {
|
|
||||||
const currentLimit = Number.parseInt(limitElement.value, 10);
|
|
||||||
const currentOffset = Number.parseInt(offsetElement.value, 10);
|
|
||||||
searchResultsElement.innerHTML = "<p class=\"has-text-centered has-text-grey-lighter\">" +
|
|
||||||
"<i class=\"fas fa-3x fa-circle-notch fa-spin\" aria-hidden=\"true\"></i><br />" +
|
|
||||||
"<em>Loading licences...</em>" +
|
|
||||||
"</p>";
|
|
||||||
cityssm.postJSON(urlPrefix + "/licences/doSearch", formElement, (licenceResults) => {
|
|
||||||
const licenceList = licenceResults.licences;
|
|
||||||
if (licenceList.length === 0) {
|
|
||||||
searchResultsElement.innerHTML = "<div class=\"message is-info\">" +
|
|
||||||
"<div class=\"message-body\">" +
|
|
||||||
"<strong>Your search returned no results.</strong><br />" +
|
|
||||||
"Please try expanding your search criteria." +
|
|
||||||
"</div>" +
|
|
||||||
"</div>";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
searchResultsElement.innerHTML = "<table class=\"table is-fullwidth is-striped is-hoverable has-sticky-header\">" +
|
|
||||||
"<thead><tr>" +
|
|
||||||
"</tr></thead>" +
|
|
||||||
"<tbody></tbody>" +
|
|
||||||
"</table>";
|
|
||||||
const tbodyElement = searchResultsElement.querySelector("tbody");
|
|
||||||
for (const licenceObject of licenceList) {
|
|
||||||
const trElement = document.createElement("tr");
|
|
||||||
trElement.innerHTML = "";
|
|
||||||
tbodyElement.append(trElement);
|
|
||||||
}
|
|
||||||
searchResultsElement.insertAdjacentHTML("beforeend", "<div class=\"level is-block-print\">" +
|
|
||||||
"<div class=\"level-left has-text-weight-bold\">" +
|
|
||||||
"Displaying licences " +
|
|
||||||
(currentOffset + 1).toString() +
|
|
||||||
" to " +
|
|
||||||
Math.min(currentLimit + currentOffset, licenceResults.count).toString() +
|
|
||||||
" of " +
|
|
||||||
licenceResults.count.toString() +
|
|
||||||
"</div>" +
|
|
||||||
"</div>");
|
|
||||||
if (currentLimit < licenceResults.count) {
|
|
||||||
const paginationElement = document.createElement("nav");
|
|
||||||
paginationElement.className = "level-right is-hidden-print";
|
|
||||||
paginationElement.setAttribute("role", "pagination");
|
|
||||||
paginationElement.setAttribute("aria-label", "pagination");
|
|
||||||
if (currentOffset > 0) {
|
|
||||||
const previousElement = document.createElement("a");
|
|
||||||
previousElement.className = "button";
|
|
||||||
previousElement.textContent = "Previous";
|
|
||||||
previousElement.addEventListener("click", (clickEvent) => {
|
|
||||||
clickEvent.preventDefault();
|
|
||||||
offsetElement.value = Math.max(0, currentOffset - currentLimit).toString();
|
|
||||||
doLicenceSearchFunction();
|
|
||||||
});
|
|
||||||
paginationElement.append(previousElement);
|
|
||||||
}
|
|
||||||
if (currentLimit + currentOffset < licenceResults.count) {
|
|
||||||
const nextElement = document.createElement("a");
|
|
||||||
nextElement.className = "button ml-3";
|
|
||||||
nextElement.innerHTML =
|
|
||||||
"<span>Next Licences</span>" +
|
|
||||||
"<span class=\"icon\"><i class=\"fas fa-chevron-right\" aria-hidden=\"true\"></i></span>";
|
|
||||||
nextElement.addEventListener("click", (clickEvent) => {
|
|
||||||
clickEvent.preventDefault();
|
|
||||||
offsetElement.value = (currentOffset + currentLimit).toString();
|
|
||||||
doLicenceSearchFunction();
|
|
||||||
});
|
|
||||||
paginationElement.append(nextElement);
|
|
||||||
}
|
|
||||||
searchResultsElement.querySelector(".level").append(paginationElement);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
const resetOffsetAndDoLicenceSearchFunction = () => {
|
|
||||||
offsetElement.value = "0";
|
|
||||||
doLicenceSearchFunction();
|
|
||||||
};
|
|
||||||
formElement.addEventListener("submit", (formEvent) => {
|
|
||||||
formEvent.preventDefault();
|
|
||||||
});
|
|
||||||
const inputElements = formElement.querySelectorAll(".input, .select select");
|
|
||||||
for (const inputElement of inputElements) {
|
|
||||||
inputElement.addEventListener("change", resetOffsetAndDoLicenceSearchFunction);
|
|
||||||
}
|
|
||||||
resetOffsetAndDoLicenceSearchFunction();
|
|
||||||
})();
|
|
||||||
|
|
@ -1,142 +0,0 @@
|
||||||
/* eslint-disable unicorn/filename-case */
|
|
||||||
|
|
||||||
import type { cityssmGlobal } from "@cityssm/bulma-webapp-js/src/types";
|
|
||||||
import type * as recordTypes from "../types/recordTypes";
|
|
||||||
|
|
||||||
declare const cityssm: cityssmGlobal;
|
|
||||||
|
|
||||||
|
|
||||||
(() => {
|
|
||||||
|
|
||||||
const urlPrefix = document.querySelector("main").dataset.urlPrefix;
|
|
||||||
|
|
||||||
const formElement = document.querySelector("#form--filters") as HTMLFormElement;
|
|
||||||
|
|
||||||
const limitElement = document.querySelector("#filter--limit") as HTMLInputElement;
|
|
||||||
const offsetElement = document.querySelector("#filter--offset") as HTMLInputElement;
|
|
||||||
|
|
||||||
const searchResultsElement = document.querySelector("#container--searchResults") as HTMLElement;
|
|
||||||
|
|
||||||
const doLicenceSearchFunction = () => {
|
|
||||||
|
|
||||||
const currentLimit = Number.parseInt(limitElement.value, 10);
|
|
||||||
const currentOffset = Number.parseInt(offsetElement.value, 10);
|
|
||||||
|
|
||||||
searchResultsElement.innerHTML = "<p class=\"has-text-centered has-text-grey-lighter\">" +
|
|
||||||
"<i class=\"fas fa-3x fa-circle-notch fa-spin\" aria-hidden=\"true\"></i><br />" +
|
|
||||||
"<em>Loading licences...</em>" +
|
|
||||||
"</p>";
|
|
||||||
|
|
||||||
cityssm.postJSON(urlPrefix + "/licences/doSearch",
|
|
||||||
formElement,
|
|
||||||
(licenceResults: { count: number; licences: recordTypes.Licence[] }) => {
|
|
||||||
|
|
||||||
const licenceList = licenceResults.licences;
|
|
||||||
|
|
||||||
if (licenceList.length === 0) {
|
|
||||||
|
|
||||||
searchResultsElement.innerHTML = "<div class=\"message is-info\">" +
|
|
||||||
"<div class=\"message-body\">" +
|
|
||||||
"<strong>Your search returned no results.</strong><br />" +
|
|
||||||
"Please try expanding your search criteria." +
|
|
||||||
"</div>" +
|
|
||||||
"</div>";
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
searchResultsElement.innerHTML = "<table class=\"table is-fullwidth is-striped is-hoverable has-sticky-header\">" +
|
|
||||||
"<thead><tr>" +
|
|
||||||
|
|
||||||
"</tr></thead>" +
|
|
||||||
"<tbody></tbody>" +
|
|
||||||
"</table>";
|
|
||||||
|
|
||||||
const tbodyElement = searchResultsElement.querySelector("tbody");
|
|
||||||
|
|
||||||
for (const licenceObject of licenceList) {
|
|
||||||
|
|
||||||
const trElement = document.createElement("tr");
|
|
||||||
|
|
||||||
trElement.innerHTML = "";
|
|
||||||
|
|
||||||
tbodyElement.append(trElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
searchResultsElement.insertAdjacentHTML("beforeend", "<div class=\"level is-block-print\">" +
|
|
||||||
"<div class=\"level-left has-text-weight-bold\">" +
|
|
||||||
"Displaying licences " +
|
|
||||||
(currentOffset + 1).toString() +
|
|
||||||
" to " +
|
|
||||||
Math.min(currentLimit + currentOffset, licenceResults.count).toString() +
|
|
||||||
" of " +
|
|
||||||
licenceResults.count.toString() +
|
|
||||||
"</div>" +
|
|
||||||
"</div>");
|
|
||||||
|
|
||||||
if (currentLimit < licenceResults.count) {
|
|
||||||
|
|
||||||
const paginationElement = document.createElement("nav");
|
|
||||||
paginationElement.className = "level-right is-hidden-print";
|
|
||||||
paginationElement.setAttribute("role", "pagination");
|
|
||||||
paginationElement.setAttribute("aria-label", "pagination");
|
|
||||||
|
|
||||||
if (currentOffset > 0) {
|
|
||||||
|
|
||||||
const previousElement = document.createElement("a");
|
|
||||||
previousElement.className = "button";
|
|
||||||
previousElement.textContent = "Previous";
|
|
||||||
previousElement.addEventListener("click", (clickEvent) => {
|
|
||||||
|
|
||||||
clickEvent.preventDefault();
|
|
||||||
offsetElement.value = Math.max(0, currentOffset - currentLimit).toString();
|
|
||||||
doLicenceSearchFunction();
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
paginationElement.append(previousElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentLimit + currentOffset < licenceResults.count) {
|
|
||||||
|
|
||||||
const nextElement = document.createElement("a");
|
|
||||||
nextElement.className = "button ml-3";
|
|
||||||
|
|
||||||
nextElement.innerHTML =
|
|
||||||
"<span>Next Licences</span>" +
|
|
||||||
"<span class=\"icon\"><i class=\"fas fa-chevron-right\" aria-hidden=\"true\"></i></span>";
|
|
||||||
|
|
||||||
nextElement.addEventListener("click", (clickEvent) => {
|
|
||||||
|
|
||||||
clickEvent.preventDefault();
|
|
||||||
offsetElement.value = (currentOffset + currentLimit).toString();
|
|
||||||
doLicenceSearchFunction();
|
|
||||||
});
|
|
||||||
|
|
||||||
paginationElement.append(nextElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
searchResultsElement.querySelector(".level").append(paginationElement);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
const resetOffsetAndDoLicenceSearchFunction = () => {
|
|
||||||
offsetElement.value = "0";
|
|
||||||
doLicenceSearchFunction();
|
|
||||||
};
|
|
||||||
|
|
||||||
formElement.addEventListener("submit", (formEvent) => {
|
|
||||||
formEvent.preventDefault();
|
|
||||||
});
|
|
||||||
|
|
||||||
const inputElements = formElement.querySelectorAll(".input, .select select");
|
|
||||||
|
|
||||||
for (const inputElement of inputElements) {
|
|
||||||
inputElement.addEventListener("change", resetOffsetAndDoLicenceSearchFunction);
|
|
||||||
}
|
|
||||||
|
|
||||||
resetOffsetAndDoLicenceSearchFunction();
|
|
||||||
})();
|
|
||||||
|
|
@ -0,0 +1,77 @@
|
||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
(() => {
|
||||||
|
const urlPrefix = document.querySelector("main").dataset.urlPrefix;
|
||||||
|
const maps = exports.maps;
|
||||||
|
const searchFilterElement = document.querySelector("#searchFilter--map");
|
||||||
|
const searchResultsContainerElement = document.querySelector("#container--searchResults");
|
||||||
|
const renderResults = () => {
|
||||||
|
searchResultsContainerElement.innerHTML = "<div class=\"has-text-grey has-text-centered\">" +
|
||||||
|
"<i class=\"fas fa-5x fa-circle-notch fa-spin\" aria-hidden=\"true\"></i><br />" +
|
||||||
|
"Loading " + exports.aliases.maps + "..." +
|
||||||
|
"</div>";
|
||||||
|
let searchResultCount = 0;
|
||||||
|
const searchResultsTbodyElement = document.createElement("tbody");
|
||||||
|
const filterStringSplit = searchFilterElement.value.trim().toLowerCase().split(" ");
|
||||||
|
for (const map of maps) {
|
||||||
|
const mapSearchString = (map.mapName + " " +
|
||||||
|
map.mapDescription + " " +
|
||||||
|
map.mapAddress1 + " " +
|
||||||
|
map.mapAddress2).toLowerCase();
|
||||||
|
let showMap = true;
|
||||||
|
for (const filterStringPiece of filterStringSplit) {
|
||||||
|
if (!mapSearchString.includes(filterStringPiece)) {
|
||||||
|
showMap = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!showMap) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
searchResultCount += 1;
|
||||||
|
const mapName = map.mapName === ""
|
||||||
|
? "(No Name)"
|
||||||
|
: map.mapName;
|
||||||
|
searchResultsTbodyElement.insertAdjacentHTML("beforeend", "<tr>" +
|
||||||
|
("<td>" +
|
||||||
|
"<a class=\"has-text-weight-bold\" href=\"" + urlPrefix + "/maps/" + map.mapId + "\">" +
|
||||||
|
cityssm.escapeHTML(mapName) +
|
||||||
|
"</a><br />" +
|
||||||
|
cityssm.escapeHTML(map.mapAddress1) +
|
||||||
|
"</td>") +
|
||||||
|
"<td class=\"has-text-centered\">" +
|
||||||
|
(map.mapLatitude && map.mapLongitude
|
||||||
|
? "<i class=\"fas fa-map-marker-alt\" title=\"Has Geographic Coordinates\"></i>"
|
||||||
|
: "") +
|
||||||
|
"</td>" +
|
||||||
|
"<td class=\"has-text-centered\">" +
|
||||||
|
(map.mapSVG
|
||||||
|
? "<i class=\"fas fa-image\" title=\"Has Image\"></i>"
|
||||||
|
: "") +
|
||||||
|
"</td>" +
|
||||||
|
"<td class=\"has-text-right\">" + map.lotCount + "</td>" +
|
||||||
|
"</tr>");
|
||||||
|
}
|
||||||
|
searchResultsContainerElement.innerHTML = "";
|
||||||
|
if (searchResultCount === 0) {
|
||||||
|
searchResultsContainerElement.innerHTML = "<div class=\"message is-info\">" +
|
||||||
|
"<p class=\"message-body\">There are no " + exports.aliases.maps.toLowerCase() + " that meet the search criteria.</p>" +
|
||||||
|
"</div>";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const searchResultsTableElement = document.createElement("table");
|
||||||
|
searchResultsTableElement.className = "table is-fullwidth is-striped is-hoverable";
|
||||||
|
searchResultsTableElement.innerHTML = "<thead><tr>" +
|
||||||
|
"<th>" + exports.aliases.map + "</th>" +
|
||||||
|
"<th class=\"has-text-centered\">Coordinates</th>" +
|
||||||
|
"<th class=\"has-text-centered\">Image</th>" +
|
||||||
|
"<th class=\"has-text-right\">" + exports.aliases.lot + " Count</th>" +
|
||||||
|
"</tr></thead>";
|
||||||
|
searchResultsTableElement.append(searchResultsTbodyElement);
|
||||||
|
searchResultsContainerElement.append(searchResultsTableElement);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
searchFilterElement.addEventListener("keyup", renderResults);
|
||||||
|
document.querySelector("#form--searchFilters").addEventListener("submit", renderResults);
|
||||||
|
renderResults();
|
||||||
|
})();
|
||||||
|
|
@ -0,0 +1,107 @@
|
||||||
|
/* eslint-disable unicorn/prefer-module */
|
||||||
|
|
||||||
|
import type * as recordTypes from "../types/recordTypes";
|
||||||
|
|
||||||
|
import type { cityssmGlobal } from "@cityssm/bulma-webapp-js/src/types";
|
||||||
|
import type { BulmaJS } from "@cityssm/bulma-js/types";
|
||||||
|
|
||||||
|
declare const cityssm: cityssmGlobal;
|
||||||
|
declare const bulmaJS: BulmaJS;
|
||||||
|
|
||||||
|
(() => {
|
||||||
|
const urlPrefix = document.querySelector("main").dataset.urlPrefix;
|
||||||
|
|
||||||
|
const maps: recordTypes.Map[] = exports.maps;
|
||||||
|
|
||||||
|
const searchFilterElement = document.querySelector("#searchFilter--map") as HTMLInputElement;
|
||||||
|
const searchResultsContainerElement = document.querySelector("#container--searchResults") as HTMLElement;
|
||||||
|
|
||||||
|
const renderResults = () => {
|
||||||
|
|
||||||
|
searchResultsContainerElement.innerHTML = "<div class=\"has-text-grey has-text-centered\">" +
|
||||||
|
"<i class=\"fas fa-5x fa-circle-notch fa-spin\" aria-hidden=\"true\"></i><br />" +
|
||||||
|
"Loading " + exports.aliases.maps + "..." +
|
||||||
|
"</div>";
|
||||||
|
|
||||||
|
let searchResultCount = 0;
|
||||||
|
const searchResultsTbodyElement = document.createElement("tbody");
|
||||||
|
|
||||||
|
const filterStringSplit = searchFilterElement.value.trim().toLowerCase().split(" ");
|
||||||
|
|
||||||
|
for (const map of maps) {
|
||||||
|
|
||||||
|
const mapSearchString = (map.mapName + " " +
|
||||||
|
map.mapDescription + " " +
|
||||||
|
map.mapAddress1 + " " +
|
||||||
|
map.mapAddress2).toLowerCase();
|
||||||
|
|
||||||
|
let showMap = true;
|
||||||
|
|
||||||
|
for (const filterStringPiece of filterStringSplit) {
|
||||||
|
if (!mapSearchString.includes(filterStringPiece)) {
|
||||||
|
showMap = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!showMap) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
searchResultCount += 1;
|
||||||
|
|
||||||
|
const mapName = map.mapName === ""
|
||||||
|
? "(No Name)"
|
||||||
|
: map.mapName;
|
||||||
|
|
||||||
|
searchResultsTbodyElement.insertAdjacentHTML("beforeend", "<tr>" +
|
||||||
|
("<td>" +
|
||||||
|
"<a class=\"has-text-weight-bold\" href=\"" + urlPrefix + "/maps/" + map.mapId + "\">" +
|
||||||
|
cityssm.escapeHTML(mapName) +
|
||||||
|
"</a><br />" +
|
||||||
|
cityssm.escapeHTML(map.mapAddress1) +
|
||||||
|
"</td>") +
|
||||||
|
"<td class=\"has-text-centered\">" +
|
||||||
|
(map.mapLatitude && map.mapLongitude
|
||||||
|
? "<i class=\"fas fa-map-marker-alt\" title=\"Has Geographic Coordinates\"></i>"
|
||||||
|
: "") +
|
||||||
|
"</td>" +
|
||||||
|
"<td class=\"has-text-centered\">" +
|
||||||
|
(map.mapSVG
|
||||||
|
? "<i class=\"fas fa-image\" title=\"Has Image\"></i>"
|
||||||
|
: "") +
|
||||||
|
"</td>" +
|
||||||
|
"<td class=\"has-text-right\">" + map.lotCount + "</td>" +
|
||||||
|
"</tr>");
|
||||||
|
}
|
||||||
|
|
||||||
|
searchResultsContainerElement.innerHTML = "";
|
||||||
|
|
||||||
|
if (searchResultCount === 0) {
|
||||||
|
|
||||||
|
searchResultsContainerElement.innerHTML = "<div class=\"message is-info\">" +
|
||||||
|
"<p class=\"message-body\">There are no " + exports.aliases.maps.toLowerCase() + " that meet the search criteria.</p>" +
|
||||||
|
"</div>";
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
const searchResultsTableElement = document.createElement("table");
|
||||||
|
searchResultsTableElement.className = "table is-fullwidth is-striped is-hoverable";
|
||||||
|
searchResultsTableElement.innerHTML = "<thead><tr>" +
|
||||||
|
"<th>" + exports.aliases.map + "</th>" +
|
||||||
|
"<th class=\"has-text-centered\">Coordinates</th>" +
|
||||||
|
"<th class=\"has-text-centered\">Image</th>" +
|
||||||
|
"<th class=\"has-text-right\">" + exports.aliases.lot + " Count</th>" +
|
||||||
|
"</tr></thead>";
|
||||||
|
|
||||||
|
searchResultsTableElement.append(searchResultsTbodyElement);
|
||||||
|
|
||||||
|
searchResultsContainerElement.append(searchResultsTableElement);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
searchFilterElement.addEventListener("keyup", renderResults);
|
||||||
|
document.querySelector("#form--searchFilters").addEventListener("submit", renderResults);
|
||||||
|
|
||||||
|
renderResults();
|
||||||
|
})();
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
export {};
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
(() => {
|
||||||
|
const mapContainerElement = document.querySelector("#map--leaflet");
|
||||||
|
if (mapContainerElement) {
|
||||||
|
const mapLatitude = Number.parseFloat(mapContainerElement.dataset.mapLatitude);
|
||||||
|
const mapLongitude = Number.parseFloat(mapContainerElement.dataset.mapLongitude);
|
||||||
|
const mapCoordinates = [mapLatitude, mapLongitude];
|
||||||
|
const map = L.map(mapContainerElement);
|
||||||
|
map.setView(mapCoordinates, 15);
|
||||||
|
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||||
|
maxZoom: 19,
|
||||||
|
attribution: '© OpenStreetMap'
|
||||||
|
}).addTo(map);
|
||||||
|
L.marker(mapCoordinates).addTo(map);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
import type { cityssmGlobal } from "@cityssm/bulma-webapp-js/src/types";
|
||||||
|
import type { BulmaJS } from "@cityssm/bulma-js/types";
|
||||||
|
import type * as Leaflet from "leaflet";
|
||||||
|
|
||||||
|
declare const cityssm: cityssmGlobal;
|
||||||
|
declare const bulmaJS: BulmaJS;
|
||||||
|
declare const L;
|
||||||
|
|
||||||
|
(() => {
|
||||||
|
|
||||||
|
const mapContainerElement = document.querySelector("#map--leaflet") as HTMLElement;
|
||||||
|
|
||||||
|
if (mapContainerElement) {
|
||||||
|
|
||||||
|
const mapLatitude = Number.parseFloat(mapContainerElement.dataset.mapLatitude);
|
||||||
|
const mapLongitude = Number.parseFloat(mapContainerElement.dataset.mapLongitude);
|
||||||
|
|
||||||
|
const mapCoordinates: Leaflet.LatLngTuple = [mapLatitude, mapLongitude];
|
||||||
|
|
||||||
|
const map: Leaflet.Map = L.map(mapContainerElement);
|
||||||
|
map.setView(mapCoordinates, 15);
|
||||||
|
|
||||||
|
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||||
|
maxZoom: 19,
|
||||||
|
attribution: '© OpenStreetMap'
|
||||||
|
}).addTo(map);
|
||||||
|
|
||||||
|
L.marker(mapCoordinates).addTo(map);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
Before Width: | Height: | Size: 1.9 MiB After Width: | Height: | Size: 1.9 MiB |
|
Before Width: | Height: | Size: 1.9 MiB After Width: | Height: | Size: 1.9 MiB |
|
Before Width: | Height: | Size: 2.5 MiB After Width: | Height: | Size: 2.5 MiB |
|
Before Width: | Height: | Size: 274 KiB After Width: | Height: | Size: 274 KiB |
|
Before Width: | Height: | Size: 273 KiB After Width: | Height: | Size: 273 KiB |
|
Before Width: | Height: | Size: 276 KiB After Width: | Height: | Size: 276 KiB |
|
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 1.4 MiB |
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 2.0 MiB After Width: | Height: | Size: 2.0 MiB |
|
Before Width: | Height: | Size: 1.3 MiB After Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 695 KiB After Width: | Height: | Size: 695 KiB |
|
Before Width: | Height: | Size: 676 KiB After Width: | Height: | Size: 676 KiB |
|
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 1.4 MiB |
|
Before Width: | Height: | Size: 786 KiB After Width: | Height: | Size: 786 KiB |
|
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 1.4 MiB |
|
Before Width: | Height: | Size: 1022 KiB After Width: | Height: | Size: 1022 KiB |
|
Before Width: | Height: | Size: 1.7 MiB After Width: | Height: | Size: 1.7 MiB |
|
Before Width: | Height: | Size: 618 KiB After Width: | Height: | Size: 618 KiB |
|
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 1.4 MiB |
|
Before Width: | Height: | Size: 451 KiB After Width: | Height: | Size: 451 KiB |
|
Before Width: | Height: | Size: 567 KiB After Width: | Height: | Size: 567 KiB |
|
Before Width: | Height: | Size: 921 KiB After Width: | Height: | Size: 921 KiB |
|
Before Width: | Height: | Size: 502 KiB After Width: | Height: | Size: 502 KiB |
|
Before Width: | Height: | Size: 360 KiB After Width: | Height: | Size: 360 KiB |
|
Before Width: | Height: | Size: 284 KiB After Width: | Height: | Size: 284 KiB |
|
Before Width: | Height: | Size: 286 KiB After Width: | Height: | Size: 286 KiB |
|
Before Width: | Height: | Size: 303 KiB After Width: | Height: | Size: 303 KiB |
|
Before Width: | Height: | Size: 312 KiB After Width: | Height: | Size: 312 KiB |
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 247 KiB After Width: | Height: | Size: 247 KiB |
|
Before Width: | Height: | Size: 246 KiB After Width: | Height: | Size: 246 KiB |
|
Before Width: | Height: | Size: 242 KiB After Width: | Height: | Size: 242 KiB |
|
Before Width: | Height: | Size: 238 KiB After Width: | Height: | Size: 238 KiB |
|
Before Width: | Height: | Size: 162 KiB After Width: | Height: | Size: 162 KiB |
|
Before Width: | Height: | Size: 242 KiB After Width: | Height: | Size: 242 KiB |
|
Before Width: | Height: | Size: 236 KiB After Width: | Height: | Size: 236 KiB |
|
Before Width: | Height: | Size: 237 KiB After Width: | Height: | Size: 237 KiB |
|
Before Width: | Height: | Size: 351 KiB After Width: | Height: | Size: 351 KiB |
|
Before Width: | Height: | Size: 351 KiB After Width: | Height: | Size: 351 KiB |
|
Before Width: | Height: | Size: 768 KiB After Width: | Height: | Size: 768 KiB |
|
Before Width: | Height: | Size: 384 KiB After Width: | Height: | Size: 384 KiB |
|
Before Width: | Height: | Size: 109 KiB After Width: | Height: | Size: 109 KiB |
|
Before Width: | Height: | Size: 204 KiB After Width: | Height: | Size: 204 KiB |
|
Before Width: | Height: | Size: 200 KiB After Width: | Height: | Size: 200 KiB |
|
Before Width: | Height: | Size: 195 KiB After Width: | Height: | Size: 195 KiB |
|
Before Width: | Height: | Size: 193 KiB After Width: | Height: | Size: 193 KiB |
|
Before Width: | Height: | Size: 193 KiB After Width: | Height: | Size: 193 KiB |
|
Before Width: | Height: | Size: 194 KiB After Width: | Height: | Size: 194 KiB |
|
Before Width: | Height: | Size: 193 KiB After Width: | Height: | Size: 193 KiB |
|
Before Width: | Height: | Size: 192 KiB After Width: | Height: | Size: 192 KiB |
|
Before Width: | Height: | Size: 194 KiB After Width: | Height: | Size: 194 KiB |
|
Before Width: | Height: | Size: 193 KiB After Width: | Height: | Size: 193 KiB |
|
Before Width: | Height: | Size: 266 KiB After Width: | Height: | Size: 266 KiB |
|
Before Width: | Height: | Size: 261 KiB After Width: | Height: | Size: 261 KiB |
|
Before Width: | Height: | Size: 256 KiB After Width: | Height: | Size: 256 KiB |
|
Before Width: | Height: | Size: 880 KiB After Width: | Height: | Size: 880 KiB |
|
Before Width: | Height: | Size: 333 KiB After Width: | Height: | Size: 333 KiB |
|
Before Width: | Height: | Size: 333 KiB After Width: | Height: | Size: 333 KiB |
|
Before Width: | Height: | Size: 289 KiB After Width: | Height: | Size: 289 KiB |
|
Before Width: | Height: | Size: 239 KiB After Width: | Height: | Size: 239 KiB |
|
Before Width: | Height: | Size: 2.0 MiB After Width: | Height: | Size: 2.0 MiB |