Desplegado en staging, el "montar el control de capas una sola vez" resultó
peor que el bug que arreglaba: /fires seguía en gris Y además la portada y
/zones —que sí pintaban— se quedaron también sin teselas. Con la clave real, el
control acaba montándose después de que el mapa ya esté montado, y entonces no
se le añade ninguna capa base. O sea que la carrera no se arregla retrasando el
montaje: solo cambia de sitio.
Staging revertido a la imagen anterior y comprobado que vuelve a estar como
estaba (portada 36 teselas, /zones 18, /fires 0).
Se conserva todo lo aprendido, que es lo que vale: el bug se reproduce en local
poniendo una clave de Google en settings-ci.json (15 teselas sin clave, 0 con
ella), NO es cosa del navegador sin pantalla, y e2e/tests/fires-map.spec.js lo
deja como test.fixme para que aparezca en cada ejecución. El arreglo bueno pasa
por decidir el conjunto de capas base ANTES de montar el mapa.
Síntoma: en staging /fires no pintaba teselas ni fuegos, no creaba la
suscripción `activefiresmyloc` y se quedaba con "Actualizando…" para siempre. Se
había atribuido a que el navegador de las pruebas no compone; no era eso. El
mismo navegador pinta la portada, y pinta /fires perfectamente contra un
servidor local.
La diferencia era la clave de Google. `DefMapLayers` montaba el control de capas
con dos capas base (OSM color y gris) y, cuando `Gkeys` resolvía la clave,
volvía a renderizar añadiendo tres capas de Google. En esa segunda pasada
react-leaflet se dejaba por el camino la capa base marcada, y el mapa se quedaba
sin ninguna. En desarrollo no hay clave, así que la segunda pasada no añadía
nada y el bug no se veía nunca.
El control se monta ahora una sola vez, con la lista de capas ya cerrada, y con
un tope de 5 s por si el script de Google no llega: las capas de Google son un
extra, el mapa tiene que salir igual.
Reproducido en local poniendo una clave falsa en settings-ci.json (0 teselas
antes del arreglo, 15 después). Esa clave falsa se queda ahí a propósito, para
que la suite e2e recorra el mismo camino que staging y producción, y
e2e/tests/fires-map.spec.js lo fija: teselas, una única capa base marcada,
suscripción por viewport, y que no se quede en "Actualizando…".
16 tests e2e en verde.
MapReady entregaba el mapa en el useEffect de montaje, cuando el contenedor
puede no tener tamano todavia. En FiresMap eso hacia que getBounds() lanzara;
el catch solo avisaba ("Failed to set map bounds and scale") y mapSize nunca
se seteaba, con lo que la suscripcion de fuegos por viewport NI SE CREABA:
loading eterno y tile-pane vacio (0 capas) pese a haber 7470 fuegos.
Evidencia: en Meteor.connection._subscriptions solo aparecian activefirestotal,
activefiresuniontotal, settings y userData — ninguna por localizacion.
Ahora se entrega via map.whenReady() + invalidateSize(), solo cuando getSize()
no es 0, con reintento en el evento resize y entrega unica (flag delivered).
Toca el componente compartido por todos los mapas: al desplegar hay que
re-verificar /fires, /zones, /subscriptions, home y detalle de fuego.
SIN DESPLEGAR todavia (la imagen viva es la de 01:33, sin este cambio).
Post-swap hardening after a full BS4-removed-class sweep of the codebase:
- LocationAutocomplete passed `root: 'form-group'` to react-places-autocomplete;
BS5 removed `.form-group` (it gave the bottom margin) -> use `mb-3`.
- Drop the unused `popper.js@1` dependency (react-bootstrap bundles
@popperjs/core@2). No source imports it.
Sweep otherwise clean: no other BS4-only utility/component classes remain in JSX
or SCSS. Full-app build boots clean.
Completes the Bootstrap 4->5 migration now that every jQuery/BS4 widget is React
(navbar, carousel, dropdowns) — plus the feedback toggle here (Feedback.js:
global `$('#feedback-form').toggle()` -> React state).
- Load Bootstrap 5 CSS from the `bootstrap` npm package in client/index.js
(imported first so app + component styles and react-bootstrap override it).
- Remove the `alexwine:bootstrap-4` meteor package (BS4 CSS + jQuery + BS4 JS).
jQuery for jquery-validation still comes from the npm `jquery` dep.
- Utility renames to BS5: ml-auto->ms-auto, float-right->float-end,
btn-block->w-100, data-toggle->data-bs-toggle (FromNow tooltip).
- forms.scss `.form-label` is no longer a shim (BS5 ships it); comment updated.
Full-app build boots clean; server suite 36 passing. Needs a visual staging pass
across all pages (BS4->5 shifts grid gutters/typography); forms should improve
since react-bootstrap v2 already emitted BS5 markup.
Bootstrap's jQuery collapse (`data-toggle="collapse"` in Navigation.js, plus the
per-NavItem `data-target=".navbar-collapse.show"` auto-close) disappears when we
drop `alexwine:bootstrap-4` for `bootstrap@5`. Replace it with a React `useState`
that toggles `.show`, and close the mobile menu via an onClick on the nav <ul>.
Works on the current BS4 CSS (`.collapse.show` is pure CSS; jQuery only added the
height animation) and removes one of the two jQuery/BS4 JS blockers to the CSS
swap (the home carousel is the other). Also drops the dead sr-only toggler button
that targeted a non-existent id. No CSS changes.
react-progress-bar.js (unmaintained wrapper) rendered the progress line
through findDOMNode. Reimplemented LoadingBar with progressbar.js directly
(the wrapper's own underlying dep) via a ref + useEffect — same thin line
(strokeWidth 2, #5A7636), no findDOMNode. Promoted progressbar.js to a
direct dependency and removed react-progress-bar.js. Verified progressbar.js
draws its SVG in-browser; findDOMNode gone from /fires and home; REST smoke
byte-identical.
react-share 2.0 shipped function components with defaultProps (CreatedButton,
Icon) -> React-19-blocking warnings on fire-detail pages. v5 is React-18-safe
and drops them. Removed the GooglePlusShareButton/Icon (Google+ is dead;
removed from react-share in v4+); the other 6 buttons (Facebook, Twitter,
Telegram, WhatsApp, Reddit, Email) are API-compatible. Browser-verified 6
buttons render, no defaultProps warnings. REST smoke byte-identical.
Reconnect rendered the Blaze meteorStatus template via
gadicc:blaze-react-component, whose bridge uses the deprecated findDOMNode
(warned on every page since it's always mounted). Reimplemented natively
with useTracker(Meteor.status) + a countdown effect, same behaviour and
reusing 255kb:meteor-status's .meteor-status CSS. Also dropped the dead
Blaze import from App.js.
Remaining findDOMNode warnings are third-party only: react-progress-bar.js
(LoadingBar) and Status.js's Blaze serverFacts (/status admin page).
Browser-verified home renders, no banner while connected, no new errors.
REST smoke byte-identical.
The 4 class components on UNSAFE_componentWillReceiveProps converted:
- FromNow, FireStats: state is a pure mirror of props -> getDerivedStateFromProps
- Fires: split the derived state (getDerivedStateFromProps) from the URL-
canonicalization side effect (componentDidUpdate, guarded by prevProps) so
the side effect never runs inside the pure gDSFP
- SelectionMap: marker is also locally draggable, so gDSFP would clobber a
drag -> componentDidUpdate guarded on a real center/distance value change
(no clobber, no setState loop), merged with the existing fit()
Browser-verified: /fires count, fire detail + FromNow, active-fire URL
canonicalizes to /fire/archive/:id, home SelectionMap renders stably (no
render loop). No UNSAFE_ warnings remain from our code. REST smoke
byte-identical.
React 19 drops defaultProps on function components. Converted the 9 of
ours that used it (App, Navigation, ReSendEmail, Reconnect, OAuthLoginButton,
PageHeader, Page, EditDocument, EditSubscription) to destructured default
params; App defaults userId/emailAddress in its withTracker instead (it
spreads {...props} widely). Class components keep defaultProps (still
supported). The only defaultProps warnings left are from the react-share
npm package (CreatedButton/Icon), not our code. REST smoke byte-identical.
Removes the Router/Switch/Route/Link/LinkContainer legacy-context
warnings. Keeps the shared history singleton (used outside React by
NotificationsObserver + Utils/location) via unstable_HistoryRouter, and
bridges v6 hooks back to v4-shaped history/match/location props with a
new withRouterCompat HOC so the ~20 class pages stay untouched.
- <Switch> -> <Routes>, component= -> element=
- Authenticated/Public -> guard components (children or <Navigate replace>)
- LocationListener -> useLocation + useEffect function
- regex route /fire/:type(active|archive|alert)/:id -> /fire/:type/:id
- history.listen callback is ({ location }) in history v5
Browser-verified: SPA nav, /subscriptions->/login auth redirect,
deep-link /fire/archive/:id (params), browser back/forward. REST smoke
byte-identical.
Removes the largest batch of React-19-blocking warnings: the 0.31
components (Grid, FormGroup, ControlLabel, Navbar.Header/Brand, Checkbox,
SafeAnchor) all leaned on legacy context / defaultProps.
29 files converted: Grid->Container, FormGroup/ControlLabel/FormControl/
HelpBlock -> Form.Group/Label/Control/Text, Checkbox -> Form.Check (label
as prop), bsStyle->variant (default->secondary), bsSize->size,
pull-right->float-end. Custom Col.js now re-exports v2's Col; custom
NavItem.js rewritten self-contained (no SafeAnchor/createChainedFunction);
Navigation.js drops react-bootstrap Navbar (raw markup anyway).
CSS stays on Bootstrap 4 (alexwine:bootstrap-4) for now: the BS4->5 jump
is entangled with the jQuery carousel/swipe + navbar-collapse and is
tracked as separate debt in UPGRADE.md. Only .form-label needed a shim
(forms.scss). Browser-verified home carousel+navbar, signup form + terms
checkbox, login form; REST smoke byte-identical.
UNSAFE_ rename of our 4 componentWillReceiveProps (FireStats, Fires, FromNow,
SelectionMap) and Authenticated/Public component propType func -> elementType.
Rest of the console noise is legacy react-* dev-mode warnings, absent in prod.
Fire collections use idGeneration:'MONGO', so _id is a Mongo.ObjectID whose
toString() is ObjectID("<hex>"), not the bare hex. Interpolating _id into a
URL produced /fire/archive/ObjectID("c0..."), which no route matches -> the
fire-detail page 404'd. New hexId() helper returns the 24-char hex for an
ObjectID (and passes plain strings through); applied at the three string-context
sites: the map-marker click URL (MarkListeners), the active->archive redirect,
and the comments referenceId (Fires.js). Left falsePositives.insert untouched —
its check() expects a Meteor.Collection.ObjectID, so it takes the object.
Verified in browser: /fire/archive/<hex> and /fire/active/<hex> render the
detail page (map + comments), URL stays clean hex, no ObjectID( anywhere.
Silences the dart-sass deprecation warnings that flooded every build:
- All @import of local partials (colors, mixins, and the CSS-emitting
partials) -> @use '...' as * (partials are pure defs, so 'as *' keeps the
global names and the ~25 call sites unchanged). Added explicit @use './colors'
to bootstrap-overrides.scss and cookies-eu.scss, which used -palette*
transitively (broke under @use's scoping).
- lighten(c, x%) -> color.adjust(c, $lightness: x%) and darken -> negative,
with @use 'sass:color' in the 6 affected files.
Compiles clean (byte-for-byte CSS behavior preserved).
alanning:roles removed (client crashed the whole bundle; plain user.roles
checks instead), selaias:cookie-consent replaced by in-repo React banner,
publish-performant-counts vendored with countAsync, Meteor.autorun dropped
(App)/Tracker.autorun (FiresMap), and the map publications not covered by
the REST smoke (activefiresmyloc, activefiresunionmyloc, fireAlerts,
oauth.verifyConfiguration) converted to async APIs.
Verified in browser: / and /fires render with map + cookie banner, zero
uncaught exceptions. REST smoke byte-identical (12/12).
Reaches Meteor 2.3 building + running against Mongo 3.2, REST smoke test
byte-identical to the 1.6.1.1 baseline (all 12 Flutter endpoints green).
Dead/abandoned Atmosphere packages removed or replaced (the upgrade blockers):
- arkham:comments-ui (no Meteor 2.x build; pinned accounts-password@1.x):
reimplemented the fire-page comments as a React feature:
imports/api/Comments/ (collection, server methods, publication, media
analyzers, new-fire-comment email) + imports/ui/components/Comments/CommentsBox.
Comment text now rendered as safe plain text + image/youtube embed (was
markdown-to-HTML). Wired into Fires.js; sitemaps.js + migration v11 updated
to the new collection. Old Blaze/startup comments files deleted.
- nimble:restivus (REST API; pinned accounts-password@1.3.3, CoffeeScript source
that crashes this build host): vendored as a local package
packages/nimble-restivus with the .coffee precompiled to plain JS and the
accounts-password constraint loosened to 2.x. REST behavior unchanged
(verified by smoke test). This also dropped the entire iron:router stack.
- maximum:server-transform (+ peerlibrary:*, meteorhacks:zones/inject-initial):
unused; removal broke Meteor.publishTransformed in FalsePositives publications
-> replaced with plain Meteor.publish (no transform was configured).
- less, markdown (no source files), and the dead test stack
(meteortesting:mocha, practicalmeteor:chai, xolvio:cleaner) which transitively
pulled coffeescript@1.0.17 — the build plugin that crashed meteor-tool
(node_contextify assertion) on this machine. Removing it unblocked the build.
- fourseven:scss 4.5.4 -> 4.14.1 (node-sass 4.5.3 doesn't build on node 12).
npm-mongo driver at 2.3 is 3.9.x — still compatible with the production Mongo
3.2 replica set.