fix(fires): el mapa de /fires ya no se queda en gris
Causa raíz, encontrada reproduciéndolo con el bundle de producción en local
—con el servidor de desarrollo NO se ve, y por eso llevaba semanas dándose por
un artefacto del navegador sin pantalla:
if ((centerStored !== [0, 0] || geolocation.get()) && geoInit) {
center.set(centerStored || geolocation.get());
geoInit = false;
}
`centerStored !== [0, 0]` compara contra un array recién creado: es SIEMPRE
cierto. En un navegador nuevo —sin centro en localStorage y con la
geolocalización todavía sin resolver— eso hacía `center.set(undefined)` y dejaba
`geoInit` en false, o sea para siempre. Un `<MapContainer>` sin `center` no
recibe `setView`, y un mapa de Leaflet sin vista no carga capa base ni teselas
ni dispara `whenReady`, con lo que tampoco se creaba la suscripción por
viewport. En desarrollo no pasaba porque la geolocalización llegaba a tiempo.
Y de paso el "Actualizando…" que no se quitaba nunca: las suscripciones se
creaban dentro de un `Tracker.autorun` ANIDADO en el withTracker. La computación
de fuera no dependía de `mapSize`, así que `loading` se calculaba con
`subscription` a undefined y no volvía a recalcularse; además cada pasada del
withTracker dejaba otro autorun sin parar. Ahora las suscripciones se crean en
la propia computación reactiva, que es donde Meteor sabe pararlas al invalidarse.
MapReady, además, vigila el contenedor con un ResizeObserver: su comprobación de
tamaño solo podía reintentar con el evento `resize` de Leaflet, que no se emite
si nadie llama a invalidateSize(). No era la causa de esto, pero hacía que la
comprobación no sirviera de nada.
La suite e2e deja de usar selectores por id: TestUtils.testId() los devuelve solo
en desarrollo, así que contra el bundle de producción —lo que levanta el job
nocturno— no existían y la suite entera habría fallado esta noche.
Verificado contra bundle de producción: /fires pasa de 0 teselas y 0 capas a 12
teselas, capa base y las dos suscripciones por viewport, sin "Actualizando…".
90 tests de servidor, 16 e2e y smoke REST byte-idéntico.
This commit is contained in:
parent
b0ca838788
commit
bba2ad5523
6 changed files with 154 additions and 109 deletions
|
|
@ -1,6 +1,23 @@
|
|||
// Shared helpers. Everything here drives the UI the way a person would: the
|
||||
// point of this suite is the wiring between browser, DDP and Mongo, so reaching
|
||||
// into Meteor.call() from the page would defeat it.
|
||||
//
|
||||
// ⚠️ NADA de selectores por id. `imports/ui/components/Utils/TestUtils.js`
|
||||
// devuelve el id SOLO en desarrollo, así que contra un bundle de producción
|
||||
// —que es justo lo que levanta el job nocturno de CI— esos elementos no lo
|
||||
// llevan. Aquí se va por href, rol y nombre de campo, que existen en los dos.
|
||||
|
||||
export const NAV = {
|
||||
zonas: 'nav a[href="/zones"]',
|
||||
fuegos: 'nav a[href="/fires"]',
|
||||
perfil: 'nav a[href="/profile"]',
|
||||
entrar: 'nav a[href="/login"]',
|
||||
salir: 'nav a[href="/logout"]',
|
||||
misZonas: 'nav a[href="/subscriptions"]'
|
||||
};
|
||||
|
||||
export const botonRegistro = page => page.getByRole('button', { name: 'Registrarse', exact: true });
|
||||
export const botonEntrar = page => page.getByRole('button', { name: 'Iniciar sesión', exact: true });
|
||||
|
||||
// A fresh address per test: the seed removes every e2e+* user, and reusing one
|
||||
// across specs makes failures depend on the order they ran in.
|
||||
|
|
@ -12,8 +29,8 @@ export const signUp = async (page, email = newEmail()) => {
|
|||
await page.fill('input[name=lastName]', 'Tester');
|
||||
await page.fill('input[name=emailAddress]', email);
|
||||
await page.fill('input[name=password]', 'password');
|
||||
await page.check('#tos');
|
||||
await page.click('#signUpSubmit');
|
||||
await page.check('input[name=tos]');
|
||||
await botonRegistro(page).click();
|
||||
// Signing up lands on the zones page.
|
||||
await page.waitForURL('**/subscriptions', { timeout: 30000 });
|
||||
return email;
|
||||
|
|
@ -23,7 +40,7 @@ export const logIn = async (page, email, password = 'password') => {
|
|||
await page.goto('/login');
|
||||
await page.fill('input[name=emailAddress]', email);
|
||||
await page.fill('input[name=password]', password);
|
||||
await page.click('#loginSubmit');
|
||||
await botonEntrar(page).click();
|
||||
};
|
||||
|
||||
// The map only settles once leaflet has laid out its panes and the tiles for the
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { test, expect } from '@playwright/test';
|
||||
import { signUp, logIn, newEmail } from '../support/app.js';
|
||||
import { signUp, logIn, newEmail, NAV, botonRegistro, botonEntrar } from '../support/app.js';
|
||||
|
||||
test.describe('registro y acceso', () => {
|
||||
test('a new account can sign up, log out and log back in', async ({ page }) => {
|
||||
|
|
@ -7,14 +7,14 @@ test.describe('registro y acceso', () => {
|
|||
await signUp(page, email);
|
||||
|
||||
// Signed in: the navbar swaps the login links for the profile and logout ones.
|
||||
await expect(page.locator('#logout')).toBeVisible();
|
||||
await expect(page.locator('#profile')).toContainText('E2E Tester');
|
||||
await expect(page.locator(NAV.salir)).toBeVisible();
|
||||
await expect(page.locator(NAV.perfil)).toContainText('E2E Tester');
|
||||
|
||||
await page.click('#logout');
|
||||
await expect(page.locator('#login')).toBeVisible();
|
||||
await page.locator(NAV.salir).click();
|
||||
await expect(page.locator(NAV.entrar)).toBeVisible();
|
||||
|
||||
await logIn(page, email);
|
||||
await expect(page.locator('#logout')).toBeVisible();
|
||||
await expect(page.locator(NAV.salir)).toBeVisible();
|
||||
});
|
||||
|
||||
test('signing up is refused without accepting the terms', async ({ page }) => {
|
||||
|
|
@ -24,21 +24,21 @@ test.describe('registro y acceso', () => {
|
|||
await page.fill('input[name=emailAddress]', newEmail());
|
||||
await page.fill('input[name=password]', 'password');
|
||||
|
||||
await expect(page.locator('#signUpSubmit')).toBeDisabled();
|
||||
await expect(botonRegistro(page)).toBeDisabled();
|
||||
});
|
||||
|
||||
test('a wrong password does not sign anybody in', async ({ page }) => {
|
||||
const email = newEmail();
|
||||
await signUp(page, email);
|
||||
await page.click('#logout');
|
||||
await page.locator(NAV.salir).click();
|
||||
|
||||
await logIn(page, email, 'not-the-password');
|
||||
await expect(page.locator('#loginSubmit')).toBeVisible();
|
||||
await expect(page.locator('#logout')).toHaveCount(0);
|
||||
await expect(botonEntrar(page)).toBeVisible();
|
||||
await expect(page.locator(NAV.salir)).toHaveCount(0);
|
||||
});
|
||||
|
||||
test('the private zones page sends anonymous visitors to the login', async ({ page }) => {
|
||||
await page.goto('/subscriptions');
|
||||
await expect(page.locator('#loginSubmit')).toBeVisible();
|
||||
await expect(botonEntrar(page)).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,45 +1,30 @@
|
|||
import { test, expect } from '@playwright/test';
|
||||
import { waitForMap } from '../support/app.js';
|
||||
|
||||
// ⛔ BUG ABIERTO: el mapa de /fires se queda EN GRIS cuando hay clave de Google
|
||||
// Maps configurada — ni teselas, ni fuegos, ni suscripción por viewport, con el
|
||||
// "Actualizando…" eterno. Es lo que se ve en staging.
|
||||
// El "mapa gris" de /fires: en staging la página no pintaba ninguna tesela, no
|
||||
// creaba la suscripción por viewport y se quedaba en "Actualizando…" para
|
||||
// siempre. Causa, encontrada reproduciéndolo con el bundle de producción en
|
||||
// local (con el servidor de desarrollo NO se ve):
|
||||
//
|
||||
// Lo que SÍ está establecido (2026-08-01):
|
||||
// Tracker.autorun(() => {
|
||||
// if ((centerStored !== [0, 0] || geolocation.get()) && geoInit) {
|
||||
// center.set(centerStored || geolocation.get());
|
||||
// geoInit = false;
|
||||
// }
|
||||
//
|
||||
// 1. NO es el navegador sin pantalla. El mismo Playwright headless pinta la
|
||||
// portada y /zones de staging, y pinta /fires perfectamente contra un
|
||||
// servidor local sin clave. La nota del plan que lo achacaba a eso es falsa.
|
||||
// 2. Depende de la clave de Google. Basta con poner una clave (aunque sea
|
||||
// falsa) en settings-ci.json para reproducirlo en local: 15 teselas sin
|
||||
// clave, 0 con ella. Por eso settings-ci.json lleva una: para que esto se
|
||||
// vea aquí y no solo en staging.
|
||||
// 3. El control de capas se monta con dos capas base y, al resolverse la clave,
|
||||
// se le añaden tres de Google. En esa segunda pasada react-leaflet se deja
|
||||
// por el camino la capa base marcada.
|
||||
// 4. Montar el control UNA sola vez, esperando a la clave, arregla el caso
|
||||
// local pero ROMPE staging todavía más: allí la portada y /zones —que
|
||||
// funcionaban— se quedan también sin teselas, porque entonces el control
|
||||
// aparece después de que el mapa ya esté montado. Probado en staging,
|
||||
// revertido: no basta con mover el momento del montaje.
|
||||
// 5. Y el culpable NO es DefMapLayers: /zones (SubscriptionsMap) y /fires
|
||||
// (FiresMap) usan el MISMO componente con las MISMAS props
|
||||
// (`<DefMapLayers gray />`), y en staging /zones pinta 18 teselas con su
|
||||
// capa en el pane mientras /fires se queda con CERO capas. En los dos casos
|
||||
// el mapa está inicializado y con vista (el `.leaflet-proxy` está ahí y el
|
||||
// pane tiene su transform): lo que falta en /fires es que se le añada la
|
||||
// capa base.
|
||||
// `centerStored !== [0, 0]` compara contra un array recién creado, así que es
|
||||
// SIEMPRE cierto. En un navegador nuevo —sin centro en localStorage y con la
|
||||
// geolocalización aún sin resolver— eso hacía `center.set(undefined)` y dejaba
|
||||
// `geoInit` en false, o sea para siempre. Un `<MapContainer>` sin `center` no
|
||||
// recibe `setView`, y un mapa de Leaflet sin vista no carga capa base ni
|
||||
// teselas ni dispara `whenReady`, con lo que tampoco se crea la suscripción por
|
||||
// viewport. En desarrollo no se veía porque la geolocalización ya estaba
|
||||
// resuelta cuando el mapa se montaba.
|
||||
//
|
||||
// O sea que hay que mirar cómo FiresMap monta y re-renderiza los hijos del
|
||||
// MapContainer (tiene shouldComponentUpdate y un manejo de viewport con
|
||||
// debounce), no DefMapLayers. La página de detalle de fuego es un caso aparte y
|
||||
// además pide `satellite`, que es una capa de Google y por tanto ni siquiera
|
||||
// existe hasta que la clave se resuelve.
|
||||
//
|
||||
// Quedan como test.fixme para que salgan como pendientes en cada ejecución en
|
||||
// vez de desaparecer en una nota. Quitar el .fixme al arreglarlo.
|
||||
// ⚠️ Estos tests solo muerden contra un bundle de PRODUCCIÓN, que es lo que
|
||||
// levanta el job nocturno de CI. Contra el servidor de desarrollo pasan igual.
|
||||
test.describe('mapa de fuegos activos', () => {
|
||||
test.fixme('paints its tiles', async ({ page }) => {
|
||||
test('paints its tiles', async ({ page }) => {
|
||||
await page.goto('/fires');
|
||||
await waitForMap(page);
|
||||
|
||||
|
|
@ -47,20 +32,17 @@ test.describe('mapa de fuegos activos', () => {
|
|||
expect(await page.locator('.leaflet-tile').count()).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
test.fixme('offers every base layer and keeps the checked one', async ({ page }) => {
|
||||
test('keeps exactly one base layer, and it is on the map', async ({ page }) => {
|
||||
await page.goto('/fires');
|
||||
await waitForMap(page);
|
||||
|
||||
const layers = page.locator('.leaflet-control-layers-base input');
|
||||
expect(await layers.count()).toBeGreaterThanOrEqual(2);
|
||||
// Exactamente una marcada, y el mapa con teselas: si la marcada se hubiera
|
||||
// perdido, seguiría marcada en el control pero no habría teselas.
|
||||
const checked = await page.locator('.leaflet-control-layers-base input:checked').count();
|
||||
expect(checked).toEqual(1);
|
||||
expect(await page.locator('.leaflet-tile').count()).toBeGreaterThan(0);
|
||||
expect(await page.locator('.leaflet-control-layers-base input').count()).toBeGreaterThanOrEqual(2);
|
||||
expect(await page.locator('.leaflet-control-layers-base input:checked').count()).toEqual(1);
|
||||
// Marcada en el control pero ausente del mapa es justo el síntoma del bug.
|
||||
expect(await page.locator('.leaflet-tile-pane .leaflet-layer').count()).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
test.fixme('subscribes to the fires of the current viewport', async ({ page }) => {
|
||||
test('subscribes to the fires of the current viewport', async ({ page }) => {
|
||||
await page.goto('/fires');
|
||||
await waitForMap(page);
|
||||
|
||||
|
|
@ -69,7 +51,7 @@ test.describe('mapa de fuegos activos', () => {
|
|||
expect(names).toContain('activefiresunionmyloc');
|
||||
});
|
||||
|
||||
test.fixme('does not get stuck on "Actualizando…"', async ({ page }) => {
|
||||
test('does not get stuck on "Actualizando…"', async ({ page }) => {
|
||||
await page.goto('/fires');
|
||||
await waitForMap(page);
|
||||
await page.waitForTimeout(5000);
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import { test, expect } from '@playwright/test';
|
||||
import { signUp } from '../support/app.js';
|
||||
import { signUp, NAV } from '../support/app.js';
|
||||
|
||||
// Through the navbar, not page.goto('/profile'): a cold load of that URL bounces
|
||||
// to /subscriptions (the Authenticated wrapper decides before Meteor has resumed
|
||||
// the login token). Worth its own fix, but it is not what this spec is about.
|
||||
const openProfile = async (page) => {
|
||||
await page.click('#profile');
|
||||
await page.locator(NAV.perfil).click();
|
||||
await page.waitForURL('**/profile', { timeout: 30000 });
|
||||
};
|
||||
|
||||
|
|
@ -19,22 +19,22 @@ const chooseLanguage = async (page, name) => {
|
|||
test.describe('cambio de idioma', () => {
|
||||
test('the interface follows the language chosen in the profile', async ({ page }) => {
|
||||
await signUp(page);
|
||||
await expect(page.locator('#moniZones')).toHaveText('Zonas vigiladas');
|
||||
await expect(page.locator(NAV.zonas)).toHaveText('Zonas vigiladas');
|
||||
|
||||
await openProfile(page);
|
||||
await chooseLanguage(page, 'English');
|
||||
|
||||
await expect(page.locator('#moniZones')).toHaveText('Monitored areas', { timeout: 30000 });
|
||||
await expect(page.locator(NAV.zonas)).toHaveText('Monitored areas', { timeout: 30000 });
|
||||
});
|
||||
|
||||
test('going back to Spanish works too', async ({ page }) => {
|
||||
await signUp(page);
|
||||
await openProfile(page);
|
||||
await chooseLanguage(page, 'English');
|
||||
await expect(page.locator('#moniZones')).toHaveText('Monitored areas', { timeout: 30000 });
|
||||
await expect(page.locator(NAV.zonas)).toHaveText('Monitored areas', { timeout: 30000 });
|
||||
|
||||
await chooseLanguage(page, 'Español');
|
||||
await expect(page.locator('#moniZones')).toHaveText('Zonas vigiladas', { timeout: 30000 });
|
||||
await expect(page.locator(NAV.zonas)).toHaveText('Zonas vigiladas', { timeout: 30000 });
|
||||
});
|
||||
|
||||
// KNOWN BUG, kept as a failing-by-design test instead of being quietly dropped:
|
||||
|
|
@ -46,9 +46,9 @@ test.describe('cambio de idioma', () => {
|
|||
await signUp(page);
|
||||
await openProfile(page);
|
||||
await chooseLanguage(page, 'English');
|
||||
await expect(page.locator('#moniZones')).toHaveText('Monitored areas', { timeout: 30000 });
|
||||
await expect(page.locator(NAV.zonas)).toHaveText('Monitored areas', { timeout: 30000 });
|
||||
|
||||
await page.reload();
|
||||
await expect(page.locator('#moniZones')).toHaveText('Monitored areas', { timeout: 30000 });
|
||||
await expect(page.locator(NAV.zonas)).toHaveText('Monitored areas', { timeout: 30000 });
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -16,19 +16,54 @@ export const MapReady = ({ onReady }) => {
|
|||
// sin bounds: en /fires eso dejaba la suscripcion por viewport sin crear y el
|
||||
// mapa vacio (0 capas) pese a haber 7470 fuegos. Esperamos a que el mapa este
|
||||
// listo Y tenga tamaño real; entregamos una sola vez.
|
||||
let observer = null;
|
||||
let poll = null;
|
||||
|
||||
const stopWatching = () => {
|
||||
if (observer) { observer.disconnect(); observer = null; }
|
||||
if (poll) { clearInterval(poll); poll = null; }
|
||||
};
|
||||
|
||||
const deliver = () => {
|
||||
if (cancelled || delivered) return;
|
||||
map.invalidateSize();
|
||||
const size = map.getSize();
|
||||
if (!size || size.x === 0 || size.y === 0) return;
|
||||
delivered = true;
|
||||
stopWatching();
|
||||
onReady(map);
|
||||
};
|
||||
|
||||
map.whenReady(deliver);
|
||||
map.on('resize', deliver);
|
||||
|
||||
// Y aquí está lo que faltaba. El contenedor puede coger su tamaño DESPUÉS
|
||||
// del montaje —en producción la hoja de estilos se aplica más tarde que el
|
||||
// primer render de React, cosa que en desarrollo no pasa porque el CSS lo
|
||||
// inyecta el propio JS— y Leaflet no vigila su contenedor: solo emite
|
||||
// `resize` cuando ALGUIEN llama a invalidateSize(). Como nadie lo hacía, el
|
||||
// mapa se quedaba con tamaño 0 para siempre: sin capa base, sin teselas y
|
||||
// sin la suscripción por viewport que crea el padre. Es el "mapa gris" de
|
||||
// /fires en staging, que en local no se veía justamente porque en
|
||||
// desarrollo el CSS llega a tiempo.
|
||||
const container = map.getContainer();
|
||||
if (container && typeof ResizeObserver !== 'undefined') {
|
||||
observer = new ResizeObserver(deliver);
|
||||
observer.observe(container);
|
||||
}
|
||||
// Red de seguridad para navegadores sin ResizeObserver y para cambios de
|
||||
// tamaño que no lo disparen; se apaga sola al entregar o a los 10 s.
|
||||
let attempts = 0;
|
||||
poll = setInterval(() => {
|
||||
attempts += 1;
|
||||
deliver();
|
||||
if (delivered || attempts > 20) stopWatching();
|
||||
}, 500);
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
map.off('resize', deliver);
|
||||
stopWatching();
|
||||
};
|
||||
}, [map]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import { ButtonGroup, Row, Col, Form } from 'react-bootstrap';
|
|||
import { Meteor } from 'meteor/meteor';
|
||||
import { ReactiveVar } from 'meteor/reactive-var';
|
||||
import { withTracker } from 'meteor/react-meteor-data';
|
||||
import { Tracker } from 'meteor/tracker';
|
||||
import { Helmet } from 'react-helmet-async';
|
||||
import { Trans, withTranslation } from 'react-i18next';
|
||||
import { MapContainer } from 'react-leaflet';
|
||||
|
|
@ -441,47 +440,59 @@ export default withTranslation()(withTracker(() => {
|
|||
}
|
||||
// Disable, because this increase the number of fires by one
|
||||
// Meteor.subscribe('lastFireDetected');
|
||||
Tracker.autorun(() => {
|
||||
if ((centerStored !== [0, 0] || geolocation.get()) && geoInit) {
|
||||
center.set(centerStored || geolocation.get());
|
||||
// console.log(`Geolocation ${geolocation.get()}`);
|
||||
geoInit = false;
|
||||
}
|
||||
if (mapSize.get() && mapSize.get()[0].lng && mapSize.get()[1].lat) {
|
||||
subscription = Meteor.subscribe(
|
||||
'activefiresmyloc',
|
||||
mapSize.get()[0].lng,
|
||||
mapSize.get()[0].lat,
|
||||
mapSize.get()[1].lng,
|
||||
mapSize.get()[1].lat,
|
||||
marks.get() && zoom.get() >= MAXZOOM
|
||||
);
|
||||
subscriptionUnion = Meteor.subscribe(
|
||||
'activefiresunionmyloc',
|
||||
mapSize.get()[0].lng,
|
||||
mapSize.get()[0].lat,
|
||||
mapSize.get()[1].lng,
|
||||
mapSize.get()[1].lat,
|
||||
false
|
||||
);
|
||||
alertSubscription = Meteor.subscribe(
|
||||
'fireAlerts',
|
||||
mapSize.get()[0].lng,
|
||||
mapSize.get()[0].lat,
|
||||
mapSize.get()[1].lng,
|
||||
mapSize.get()[1].lat
|
||||
);
|
||||
/* if (withIndustries) {
|
||||
Meteor.subscribe(
|
||||
'industriesMyloc',
|
||||
mapSize.get()[0].lng,
|
||||
mapSize.get()[0].lat,
|
||||
mapSize.get()[1].lng,
|
||||
mapSize.get()[1].lat
|
||||
);
|
||||
} */
|
||||
}
|
||||
});
|
||||
// ⚠️ Antes esto vivía dentro de un `Tracker.autorun` ANIDADO en el propio
|
||||
// withTracker, y eso tenía dos problemas. Uno: la computación de fuera no
|
||||
// dependía de `mapSize`, así que cuando el mapa por fin publicaba su viewport
|
||||
// y se creaban las suscripciones, `loading` se había calculado ya con
|
||||
// `subscription` a undefined — y no volvía a recalcularse, con lo que la
|
||||
// página se quedaba con el "Actualizando…" puesto para siempre. Dos: cada
|
||||
// pasada del withTracker creaba OTRO autorun que nadie paraba.
|
||||
//
|
||||
// Aquí ya estamos dentro de una computación reactiva: leyendo `mapSize.get()`
|
||||
// la dependencia queda registrada, y las suscripciones creadas dentro se
|
||||
// paran solas cuando la computación se invalida, que es justo lo que se
|
||||
// quiere al cambiar el viewport.
|
||||
//
|
||||
// La condición del centro era `(centerStored !== [0, 0] || geolocation.get()) && geoInit`,
|
||||
// y `centerStored !== [0, 0]` compara contra un array recién creado: SIEMPRE
|
||||
// cierto. En un navegador nuevo —sin centro guardado y sin geolocalización
|
||||
// todavía— hacía `center.set(undefined)` y dejaba `geoInit` en false, o sea
|
||||
// para siempre. Un `<MapContainer>` sin `center` no recibe `setView`, y un
|
||||
// mapa de Leaflet sin vista no carga capa base ni teselas ni dispara
|
||||
// `whenReady`. Ese era el "mapa gris" de /fires, que solo se veía en
|
||||
// producción porque en desarrollo la geolocalización llegaba a tiempo.
|
||||
const nextCenter = centerStored || geolocation.get();
|
||||
if (geoInit && nextCenter) {
|
||||
center.set(nextCenter);
|
||||
geoInit = false;
|
||||
}
|
||||
|
||||
const bounds = mapSize.get();
|
||||
if (bounds && bounds[0].lng && bounds[1].lat) {
|
||||
subscription = Meteor.subscribe(
|
||||
'activefiresmyloc',
|
||||
bounds[0].lng,
|
||||
bounds[0].lat,
|
||||
bounds[1].lng,
|
||||
bounds[1].lat,
|
||||
marks.get() && zoom.get() >= MAXZOOM
|
||||
);
|
||||
subscriptionUnion = Meteor.subscribe(
|
||||
'activefiresunionmyloc',
|
||||
bounds[0].lng,
|
||||
bounds[0].lat,
|
||||
bounds[1].lng,
|
||||
bounds[1].lat,
|
||||
false
|
||||
);
|
||||
alertSubscription = Meteor.subscribe(
|
||||
'fireAlerts',
|
||||
bounds[0].lng,
|
||||
bounds[0].lat,
|
||||
bounds[1].lng,
|
||||
bounds[1].lat
|
||||
);
|
||||
}
|
||||
|
||||
Meteor.subscribe('activefirestotal');
|
||||
Meteor.subscribe('activefiresuniontotal');
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue