Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
6173347
build(vite): Add basic vite setup.
binh-dam-ibigroup Oct 7, 2025
1548e66
refactor: Fix flow type imports
binh-dam-ibigroup Oct 7, 2025
2fab6d7
build(vite): Restore yaml dependency optimization
binh-dam-ibigroup Oct 7, 2025
b325302
refactor(config): Convert require into import.
binh-dam-ibigroup Oct 7, 2025
935cc80
refactor(main): fix reducer import
binh-dam-ibigroup Oct 7, 2025
8ba91b0
build(vite): set dev proxy, don't append dev dt-server URL
binh-dam-ibigroup Oct 7, 2025
4ececc7
refactor: Adjust other NODE_ENV for vite
binh-dam-ibigroup Oct 7, 2025
e840dc6
fix(App): Wrap router with app info component
binh-dam-ibigroup Oct 8, 2025
3a7082c
build(vite): Replace process.env.* using config.yml content
binh-dam-ibigroup Oct 8, 2025
a9c4bba
build(flow): Skip hermes* modules.
binh-dam-ibigroup Oct 8, 2025
344554a
refactor(index): Update CSS paths
binh-dam-ibigroup Oct 14, 2025
12dd69b
build(vite): Add build script using vite.
binh-dam-ibigroup Oct 17, 2025
93aeab0
refactor(config): Adjust flow exceptions
binh-dam-ibigroup Oct 17, 2025
67d4517
ci: Use node v22
binh-dam-ibigroup Oct 17, 2025
e5e306e
refactor: Use different yml file imports for vite and jest.
binh-dam-ibigroup Oct 20, 2025
e6c80a4
refactor(config): Move test hack to jest-specific file.
binh-dam-ibigroup Oct 20, 2025
f5b0cf9
chore(deps): Upgrade nock to 13.3.1.
binh-dam-ibigroup Oct 21, 2025
20c74e9
refactor: Put back test-specific code
binh-dam-ibigroup Oct 21, 2025
51ed97b
test(map): Remove call to nock.log.
binh-dam-ibigroup Oct 21, 2025
6eb449f
refactor(analytics): Avoid using analytics in tests.
binh-dam-ibigroup Oct 21, 2025
d92a6a3
test: attempt to not transform source (should fail)
binh-dam-ibigroup Oct 21, 2025
f882bb3
Revert "test: attempt to not transform source (should fail)"
binh-dam-ibigroup Oct 21, 2025
b7949f0
refactor(config): Move test process.env to test file.
binh-dam-ibigroup Oct 21, 2025
0e24394
test(ActiveProjectViewer): Make test async bc code is async.
binh-dam-ibigroup Oct 22, 2025
966161a
build: Downgrade nock to 12
binh-dam-ibigroup Oct 22, 2025
05f0290
Revert "test(ActiveProjectViewer): Make test async bc code is async."
binh-dam-ibigroup Oct 22, 2025
8c8a029
test(ActiveProjectViewer): Add missing mocks
binh-dam-ibigroup Oct 22, 2025
43be0eb
build: Return to nock 13
binh-dam-ibigroup Oct 22, 2025
522758e
ci: Update e2e test docker
binh-dam-ibigroup Oct 22, 2025
5d48fb9
ci: Update docker for e2e test
binh-dam-ibigroup Oct 22, 2025
2cb2247
docs: Update dev/build docs [skip ci]
binh-dam-ibigroup Oct 22, 2025
ea5635c
build(vite): Add buld info to UI.
binh-dam-ibigroup Oct 30, 2025
eea1536
ci(e2e): Update base puppeteer image
binh-dam-ibigroup Oct 30, 2025
e8f0d1c
ci(e2e): try to fix puppeteer image
binh-dam-ibigroup Oct 30, 2025
bdced5c
build(vite): Add polyfills to support process.nextTick()
binh-dam-ibigroup Oct 31, 2025
cf65c36
Revert "ci(e2e): Update base puppeteer image"
binh-dam-ibigroup Oct 31, 2025
cc26059
ci: Update docker images
binh-dam-ibigroup Nov 3, 2025
ada0c46
ci: update puppeteer image
binh-dam-ibigroup Nov 3, 2025
2807b88
Update image for arm/amd processors
binh-dam-ibigroup Nov 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .flowconfig
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@
.*/node_modules/reqwest/.*
.*/node_modules/module-deps/test/invalid_pkg/package.json
.*/node_modules/immutable/dist/immutable.js.flow
.*/node_modules/hermes-.*/.*

[include]

[libs]

[options]
esproposal.optional_chaining=enable
6 changes: 3 additions & 3 deletions .github/workflows/node-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ jobs:
run: |
pip install Jinja2==3.0.3 mkdocs
mkdocs --version
- name: Use Node.js 14.x
- name: Use Node.js 22.x
uses: actions/setup-node@v1
with:
node-version: 14.x
node-version: 22.x
- name: Install npm/yarn packages using cache
uses: bahmutov/npm-install@v1
- name: Lint code
Expand All @@ -35,7 +35,7 @@ jobs:
- name: Run tests
run: yarn test-client
- name: Build with minification
run: yarn run build -- --minify
run: yarn build
- name: Build docs
run: mkdocs build
- name: Whether e2e should run
Expand Down
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
22
2 changes: 1 addition & 1 deletion __tests__/e2e/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# syntax=docker/dockerfile:1
FROM public.ecr.aws/s2a5w2n9/puppeteer:latest
FROM ghcr.io/ibi-group/datatools-ui-puppeteer:alp3.22pup13.5
WORKDIR /datatools-ui

USER root
Expand Down
9 changes: 5 additions & 4 deletions __tests__/e2e/puppeteer/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
FROM alpine
FROM alpine:3.22

# Installs latest Chromium (100) package.
# alpine 3.22 already ships with Node 22 and Chromium 141/142,
# so the install commands for these components is redundant.
RUN apk add --no-cache \
chromium \
nss \
freetype \
harfbuzz \
ca-certificates \
ttf-freefont \
nodejs \
nodejs=~22 \
yarn

# Tell Puppeteer to skip installing Chrome. We'll be using the installed package.
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true \
PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser

# Puppeteer v13.5.0 works with Chromium 100.
RUN yarn add puppeteer
RUN yarn add puppeteer@13.5.0

# Add user so we don't need --no-sandbox.
RUN addgroup -S pptruser && adduser -S -G pptruser pptruser \
Expand Down
6 changes: 4 additions & 2 deletions __tests__/e2e/ui/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# syntax=docker/dockerfile:1
FROM node:14
FROM node:22
WORKDIR /datatools-build

ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD true
Expand All @@ -10,4 +10,6 @@ COPY package.json yarn.lock patches /datatools-build/
RUN yarn
COPY . /datatools-build/
COPY configurations/default /datatools-config/
CMD yarn run mastarm build --env dev --serve --proxy http://datatools-server:4000/api #

CMD env YAML_CONFIG=/datatools-config/env.yml yarn build
CMD yarn e2e-preview --port 9966
57 changes: 57 additions & 0 deletions __tests__/test-utils/mock-data/config-resources.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// @flow

import objectPath from 'object-path'

// This file is used for jest.
// The paths below are relative to file lib/common/util/config-resources.js
// that is replaced with this file for jest, where support for `import '...yml'` syntax does not exist.

// $FlowFixMe - assume file exists and make flow happy
const english = require('../../../i18n/english.yml')
// $FlowFixMe - assume file exists and make flow happy
const polish = require('../../../i18n/polish.yml')
// $FlowFixMe - assume file exists and make flow happy
const german = require('../../../i18n/german.yml')
// Add additional language files here.
// E.g., require('../../../i18n/espanol.yml')

// Note: The GTFS+ file should be required regardless of whether the module is
// enabled. Otherwise, it will not be loaded properly because the UI depends on
// the server config from the appinfo endpoint.
// $FlowFixMe - assume file exists and make flow happy
const gtfsplus = require('../../../gtfsplus.yml')
// $FlowFixMe - assume file exists and make flow happy
const gtfs = require('../../../gtfs.yml')

const languages = [
english,
polish,
german
]

// For some weird reason that probably has to do with how yaml files are
// required in the test environment, the message files are stored with an
// object key that contains the full path. Therefore, do a little hack to
// fix this.
languages.forEach(lang => {
Object.keys(lang).forEach(key => {
if (key.indexOf('.') > -1) {
objectPath.set(lang, key, lang[key])
}
})
})

if (!process.env.SETTINGS) {
throw new Error('SETTINGS environment variable not set')
}

const extraSettings = JSON.parse(process.env.SETTINGS)

export default {
english,
extraSettings,
german,
gtfs,
gtfsplus,
polish
}
5 changes: 3 additions & 2 deletions docker/ui/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM node:14
FROM node:22
WORKDIR /datatools-build

ARG BUGSNAG_KEY
Expand All @@ -13,4 +13,5 @@ COPY configurations/default /datatools-config/
# Copy the tmp file to the env.yml if no env.yml is present
RUN cp -R -u -p /datatools-config/env.yml.tmp /datatools-config/env.yml

CMD yarn run mastarm build --env dev --serve --proxy http://datatools-server:4000/api #
CMD env YAML_CONFIG=/datatools-config/env.yml yarn build
CMD yarn e2e-preview --port 9966
9 changes: 4 additions & 5 deletions docs/dev/deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ The application consists of two repositories: a [Spark-powered Java backend](htt
and a [Javascript frontend written with React and Redux](https://github.com/ibi-group/datatools-ui).
To install and deploy the application, you will need Java 8 and Maven for the
[datatools-server](https://github.com/ibi-group/datatools-server)
and Node (>= v10 required, >= v14 recommended), npm, yarn and
and Node (>= v20 required, >= v22 recommended), npm, yarn and
[mastarm](https://github.com/conveyal/mastarm) for the
[datatools-ui](https://github.com/ibi-group/datatools-ui).

Expand Down Expand Up @@ -42,10 +42,10 @@ The default
[settings.yml](https://github.com/ibi-group/datatools-ui/blob/dev/configurations/default/settings.yml) for
`datatools-ui` should work out of the box, but you may want to specify
alternative settings files outside of these repositories.
These can be specified as a directory during `datatools-ui` build with mastarm:
These can be specified as a directory during `datatools-ui` build:

```bash
$ mastarm build --config /path/to/configurations/dir
$ env YAML_CONFIG /path/to/configurations/dir yarn build
```

AND as individual file args for `datatools-server`:
Expand Down Expand Up @@ -194,8 +194,7 @@ $ cd datatools-ui
$ yarn
```

Build and deploy `datatools-ui` to s3 using npm script
(which calls [mastarm](https://github.com/conveyal/mastarm)):
Build and deploy `datatools-ui` to s3 using npm script:

```bash
$ npm run deploy -- s3://$S3_BUCKET_NAME/dist
Expand Down
6 changes: 3 additions & 3 deletions docs/dev/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,19 @@ After running this configuration, the Java application should be running at [htt

## Front end

We use Conveyal's front-end JS tool-belt [`mastarm`](https://github.com/conveyal/mastarm) to build, run, and lint while developing.
We use [Vite](https://vite.dev) to build and run while developing.
To kick off a development server at [http://localhost:9966](http://localhost:9966):

```
yarn start
```

This will use `mastarm` to run a `browserify` server at the above port, along with a proxy for the back-end API, which is assumed to be running on `http://localhost:4000`.
This will cause Vite to build and launch a development server at the above port, along with a proxy for the back-end API, which is assumed to be running on `http://localhost:4000`.

To specify your own configuration that overrides the defaults:

```
yarn start -- --config /path/to/config
env YAML_CONFIG=/path/to/config yarn start
```

## E2E tests
Expand Down
5 changes: 2 additions & 3 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0">
<title>Data Tools</title>
<link href="https://fonts.googleapis.com/css?family=Sarabun" rel="stylesheet">
<link href="/dist/index.css" rel="stylesheet">
<link href="/lib/index.css" rel="stylesheet">
<link rel="shortcut icon" href="https://d2tyb7byn1fef9.cloudfront.net/ibi-logo-original%402x.png" type="image/x-icon">
</head>
<body>
<div id="root"></div>
<script src="/dist/index.js"></script>
<div id="root"><script type="module" src="/lib/main.js"></script></div>
</body>
</html>
4 changes: 2 additions & 2 deletions lib/common/components/StatusModal.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// @flow

import React, {Component} from 'react'
import { Auth0ContextInterface } from '@auth0/auth0-react'
import type { Auth0ContextInterface } from '@auth0/auth0-react'
import {Modal, Button} from 'react-bootstrap'

import {getComponentMessages} from '../../common/util/config'
Expand All @@ -17,7 +17,7 @@ type Props = ContainerProps & ModalStatus & {
}

type State = ModalStatus & {
auth0: typeof Auth0ContextInterface,
auth0: Auth0ContextInterface,
disabled?: boolean,
// put in here to make general destructuring just work
removeEditorLock?: typeof editorActions.removeEditorLock,
Expand Down
7 changes: 3 additions & 4 deletions lib/common/containers/App.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @flow

import { AppState, Auth0Provider } from '@auth0/auth0-react'
import { type AppState, Auth0Provider } from '@auth0/auth0-react'
// minified file is imported because of https://github.com/bugsnag/bugsnag-js/issues/366
import bugsnag from 'bugsnag-js/dist/bugsnag.min'
import createPlugin from 'bugsnag-react'
Expand Down Expand Up @@ -129,14 +129,13 @@ export default class App extends React.Component<AppProps> {
}
]
const appContent = (
<>
<AppInfoRetriever />
<AppInfoRetriever>
<Router
history={browserHistory}
onUpdate={logPageView}>
{routes.map((r, i) => (<Route {...r} key={i} />))}
</Router>
</>
</AppInfoRetriever>
)
const routerWithAuth0 = AUTH0_DISABLED ? <>
<LocalUserRetriever />
Expand Down
11 changes: 8 additions & 3 deletions lib/common/containers/AppInfoRetriever.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,25 @@ import { useEffect } from 'react'
import { connect } from 'react-redux'

import * as statusActions from '../../manager/actions/status'
import type { AppState } from '../../types/reducers'

/**
* Retrieves the app info and updates the redux state accordingly.
*/
const AppInfoRetriever = ({ fetchAppInfo }) => {
const AppInfoRetriever = ({ children, fetchAppInfo, loaded }) => {
// Fetch app info only once.
useEffect(fetchAppInfo, [])

// Component renders nothing.
return null
return loaded ? children : null
}

const mapStateToProps = (state: AppState) => ({
loaded: state.status.appInfo?.config
})

const mapDispatchToProps = {
fetchAppInfo: statusActions.fetchAppInfo
}

export default connect(null, mapDispatchToProps)(AppInfoRetriever)
export default connect(mapStateToProps, mapDispatchToProps)(AppInfoRetriever)
2 changes: 1 addition & 1 deletion lib/common/containers/CurrentStatusModal.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @flow

import { Auth0ContextInterface, withAuth0 } from '@auth0/auth0-react'
import { type Auth0ContextInterface, withAuth0 } from '@auth0/auth0-react'
import {connect} from 'react-redux'

import StatusModal from '../components/StatusModal'
Expand Down
6 changes: 3 additions & 3 deletions lib/common/containers/StarButton.js
Copy link
Contributor Author

@binh-dam-ibigroup binh-dam-ibigroup Oct 22, 2025

Choose a reason for hiding this comment

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

Keeping this component around in this PR, although it is not clear how it works.

Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {connect} from 'react-redux'

import {getComponentMessages} from '../util/config'
// $FlowFixMe FIXME action no longer present in user actions
import {updateStar} from '../../manager/actions/user'
// import {updateStar} from '../../manager/actions/user'

import type {dispatchFn, ManagerUserState} from '../../types/reducers'

Expand All @@ -22,8 +22,8 @@ class StarButton extends Component<Props> {
messages = getComponentMessages('StarButton')

_onClick = () => {
const {dispatch, isStarred, user, target} = this.props
dispatch(updateStar(user.profile, target, !isStarred))
// const {dispatch, isStarred, user, target} = this.props
// dispatch(updateStar(user.profile, target, !isStarred))
}

render () {
Expand Down
2 changes: 1 addition & 1 deletion lib/common/util/analytics.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import ReactGA from 'react-ga'

// Check if Google Analytics is enabled for the application.
const hasAnalytics: boolean =
process.env.NODE_ENV !== 'dev' &&
process.env.NODE_ENV !== 'development' &&
process.env.NODE_ENV !== 'test' &&
!!process.env.GOOGLE_ANALYTICS_TRACKING_ID
if (!hasAnalytics) console.warn('Google Analytics not enabled.')
Expand Down
34 changes: 34 additions & 0 deletions lib/common/util/config-resources.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// @flow

// Note: The GTFS+ file should be required regardless of whether the module is
// enabled. Otherwise, it will not be loaded properly because the UI depends on
// the server config from the appinfo endpoint.

// $FlowFixMe Not sure why flow is not able to resolve this file.
import gtfsplus from '../../../gtfsplus.yml'
// $FlowFixMe Not sure why flow is not able to resolve this file.
import gtfs from '../../../gtfs.yml'

// Note: We are not using Vite's glob import feature (import.meta.glob(...)).
// Flow treats that as a syntax error that cannot be waived.

// $FlowFixMe Not sure why flow is not able to resolve this file.
import english from '../../../i18n/english.yml'
// $FlowFixMe Not sure why flow is not able to resolve this file.
import polish from '../../../i18n/polish.yml'
// $FlowFixMe Not sure why flow is not able to resolve this file.
import german from '../../../i18n/german.yml'
// Import additional language files here, e.g.:
// import spanish from '../../../i18n/espanol.yml'

// Only used in the test environment for now.
const extraSettings = {}

export default {
english,
extraSettings,
german,
gtfs,
gtfsplus,
polish
}
Loading
Loading