web: Move web app to ‘web’ directory.

Ever since we started bundling the app with webpack, there’s been less
and less overlap between our ‘static’ directory (files belonging to
the frontend app) and Django’s interpretation of the ‘static’
directory (files served directly to the web).

Split the app out to its own ‘web’ directory outside of ‘static’, and
remove all the custom collectstatic --ignore rules.  This makes it
much clearer what’s actually being served to the web, and what’s being
bundled by webpack.  It also shrinks the release tarball by 3%.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
Anders Kaseorg 2023-02-22 14:03:47 -08:00
parent be0098146c
commit c1675913a2
866 changed files with 978 additions and 993 deletions

View File

@ -4,11 +4,12 @@
/docs/_build /docs/_build
/static/generated /static/generated
/static/third
/static/webpack-bundles /static/webpack-bundles
/var/* /var/*
!/var/puppeteer !/var/puppeteer
/var/puppeteer/* /var/puppeteer/*
!/var/puppeteer/test_credentials.d.ts !/var/puppeteer/test_credentials.d.ts
/web/generated
/web/third
/zulip-current-venv /zulip-current-venv
/zulip-py3-venv /zulip-py3-venv

View File

@ -137,7 +137,7 @@
} }
}, },
{ {
"files": ["static/js/**"], "files": ["web/src/**"],
"globals": { "globals": {
"StripeCheckout": false "StripeCheckout": false
} }
@ -217,7 +217,7 @@
} }
}, },
{ {
"files": ["tools/debug-require.js"], "files": ["web/debug-require.js"],
"env": { "env": {
"browser": true, "browser": true,
"es2020": false "es2020": false
@ -231,7 +231,7 @@
} }
}, },
{ {
"files": ["static/**"], "files": ["web/shared/**", "web/src/**", "web/third/**"],
"env": { "env": {
"browser": true, "browser": true,
"node": false "node": false
@ -244,7 +244,7 @@
} }
}, },
{ {
"files": ["static/shared/**"], "files": ["web/shared/**"],
"env": { "env": {
"browser": false, "browser": false,
"shared-node-browser": true "shared-node-browser": true
@ -255,9 +255,9 @@
{ {
"zones": [ "zones": [
{ {
"target": "./static/shared", "target": "./web/shared",
"from": ".", "from": ".",
"except": ["./node_modules", "./static/shared"] "except": ["./node_modules", "./web/shared"]
} }
] ]
} }

View File

@ -14,9 +14,8 @@ on:
- puppet/** - puppet/**
- requirements/** - requirements/**
- scripts/** - scripts/**
- static/assets/**
- static/third/**
- tools/** - tools/**
- web/third/**
- webpack.config.ts - webpack.config.ts
- yarn.lock - yarn.lock
- zerver/worker/queue_processors.py - zerver/worker/queue_processors.py

View File

@ -155,9 +155,9 @@ jobs:
# Ban check-database-compatibility.py from transitively # Ban check-database-compatibility.py from transitively
# relying on static/generated, because it might not be # relying on static/generated, because it might not be
# up-to-date at that point in upgrade-zulip-stage-2. # up-to-date at that point in upgrade-zulip-stage-2.
chmod 000 static/generated chmod 000 static/generated web/generated
./scripts/lib/check-database-compatibility.py ./scripts/lib/check-database-compatibility.py
chmod 755 static/generated chmod 755 static/generated web/generated
- name: Run documentation and api tests - name: Run documentation and api tests
if: ${{ matrix.include_documentation_tests }} if: ${{ matrix.include_documentation_tests }}

View File

@ -2,9 +2,9 @@
/corporate/tests/stripe_fixtures /corporate/tests/stripe_fixtures
/help/**/*.md /help/**/*.md
/locale /locale
/static/third
/templates/**/*.md /templates/**/*.md
/tools/setup/emoji/emoji_map.json /tools/setup/emoji/emoji_map.json
/web/third
/zerver/tests/fixtures /zerver/tests/fixtures
/zerver/webhooks/*/doc.md /zerver/webhooks/*/doc.md
/zerver/webhooks/*/fixtures /zerver/webhooks/*/fixtures

View File

@ -51,25 +51,25 @@ Files: static/audio/notification_sounds/zulip.*
Copyright: 2011 Vidsyn Copyright: 2011 Vidsyn
License: CC0-1.0 License: CC0-1.0
Files: static/third/bootstrap/css/bootstrap-btn.css Files: web/third/bootstrap/css/bootstrap-btn.css
Copyright: 2011-2014 Twitter, Inc Copyright: 2011-2014 Twitter, Inc
License: Expat License: Expat
Files: static/third/bootstrap/css/bootstrap.css Files: web/third/bootstrap/css/bootstrap.css
Copyright: 2012 Twitter, Inc Copyright: 2012 Twitter, Inc
License: Apache-2.0 License: Apache-2.0
Comment: The software has been modified. Comment: The software has been modified.
Files: static/third/bootstrap/js/bootstrap.js Files: web/third/bootstrap/js/bootstrap.js
Copyright: 2012 Twitter, Inc Copyright: 2012 Twitter, Inc
License: Apache-2.0 License: Apache-2.0
Files: static/third/bootstrap-typeahead/* Files: web/third/bootstrap-typeahead/*
Copyright: 2012 Twitter, Inc Copyright: 2012 Twitter, Inc
License: Apache-2.0 License: Apache-2.0
Comment: Bootstrap typeahead. The software has been modified. Comment: Bootstrap typeahead. The software has been modified.
Files: static/third/bootstrap-tooltip/* Files: web/third/bootstrap-tooltip/*
Copyright: 2012 Twitter, Inc Copyright: 2012 Twitter, Inc
License: Apache-2.0 License: Apache-2.0
Comment: Bootstrap tooltip and bootstrap popover. The software has been modified. Comment: Bootstrap tooltip and bootstrap popover. The software has been modified.
@ -78,16 +78,16 @@ Files: static/generated/emoji/images/emoji/unicode/*
Copyright: Google, Inc. Copyright: Google, Inc.
License: Apache-2.0 License: Apache-2.0
Files: static/third/jquery-idle/jquery.idle.js Files: web/third/jquery-idle/jquery.idle.js
Copyright: 2011-2013 Henrique Boaventura Copyright: 2011-2013 Henrique Boaventura
License: Expat License: Expat
Comment: The software has been modified. Comment: The software has been modified.
Files: static/third/marked/* Files: web/third/marked/*
Copyright: 2011-2013, Christopher Jeffrey Copyright: 2011-2013, Christopher Jeffrey
License: Expat License: Expat
Files: static/shared/icons/ellipsis-v-solid.svg Files: web/shared/icons/ellipsis-v-solid.svg
Copyright: 2017 Fonticons, Inc. Copyright: 2017 Fonticons, Inc.
License: CC-BY-4.0 License: CC-BY-4.0
Comment: This icon is picked from Version 5.13.0 of Font Awesome Comment: This icon is picked from Version 5.13.0 of Font Awesome
@ -109,7 +109,7 @@ Files: static/audio/notification_sounds/*
Copyright: 2021 Stefan Mertens Copyright: 2021 Stefan Mertens
License: CC0-1.0 License: CC0-1.0
Files: static/shared/icons/globe.svg Files: web/shared/icons/globe.svg
Source: https://github.com/ionic-team/ionicons/blob/v5.5.2/src/svg/earth.svg, modified to increase the width of the globe outline. Source: https://github.com/ionic-team/ionicons/blob/v5.5.2/src/svg/earth.svg, modified to increase the width of the globe outline.
Copyright: 2015-present Ionic (http://ionic.io/) Copyright: 2015-present Ionic (http://ionic.io/)
License: Expat License: Expat
@ -118,7 +118,7 @@ Files: tools/check-thirdparty
Copyright: 2020 Kandra Labs, Inc. Copyright: 2020 Kandra Labs, Inc.
License: GPL-2.0+ License: GPL-2.0+
Files: static/shared/icons/mute.svg Files: web/shared/icons/mute.svg
Source: https://fonts.google.com/icons?selected=Material+Symbols+Rounded:volume_mute Source: https://fonts.google.com/icons?selected=Material+Symbols+Rounded:volume_mute
Copyright: Google, Inc. Copyright: Google, Inc.
License: Apache-2.0 License: Apache-2.0

View File

@ -274,7 +274,7 @@ editor](https://prettier.io/docs/en/editors.html).
Combine adjacent on-ready functions, if they are logically related. Combine adjacent on-ready functions, if they are logically related.
The best way to build complicated DOM elements is a Handlebars template The best way to build complicated DOM elements is a Handlebars template
like `static/templates/message_reactions.hbs`. For simpler things like `web/templates/message_reactions.hbs`. For simpler things
you can use jQuery DOM building APIs like so: you can use jQuery DOM building APIs like so:
```js ```js

View File

@ -75,8 +75,8 @@ the development environment][authentication-dev-server].
- Most changes will take effect automatically. Details: - Most changes will take effect automatically. Details:
- If you change CSS files, your changes will appear immediately via - If you change CSS files, your changes will appear immediately via
webpack hot module replacement. webpack hot module replacement.
- If you change JavaScript code (`static/js`) or Handlebars - If you change JavaScript code (`web/src`) or Handlebars
templates (`static/templates`), the browser window will be templates (`web/templates`), the browser window will be
reloaded automatically. reloaded automatically.
- For Jinja2 backend templates (`templates/*`), you'll need to reload - For Jinja2 backend templates (`templates/*`), you'll need to reload
the browser window to see your changes. the browser window to see your changes.

View File

@ -241,7 +241,7 @@ Use non-Mac keyboard keys; for example `Enter`, instead of `Return`. Zulip will
automatically translate non-Mac keys to the Mac versions for users with a Mac automatically translate non-Mac keys to the Mac versions for users with a Mac
user agent. If you want to confirm that your documentation is rendering Mac keys user agent. If you want to confirm that your documentation is rendering Mac keys
correctly when writing documentation in Windows or Linux, you can temporarily correctly when writing documentation in Windows or Linux, you can temporarily
change `has_mac_keyboard` in `/static/js/common.ts` to always return `True`. change `has_mac_keyboard` in `/web/src/common.ts` to always return `True`.
Then when you view your documentation changes in the development environment, Then when you view your documentation changes in the development environment,
the keyboard shortcuts should be rendered with Mac keys where appropriate. the keyboard shortcuts should be rendered with Mac keys where appropriate.

View File

@ -79,7 +79,7 @@ See also [fixing commits][fix-commit]
- `git fetch origin`: fetch origin repository - `git fetch origin`: fetch origin repository
- `git fetch upstream`: fetch upstream repository - `git fetch upstream`: fetch upstream repository
- grep - grep
- `git grep update_unread_counts static/js`: Search our JS for references to update_unread_counts. - `git grep update_unread_counts web/src`: Search our JS for references to update_unread_counts.
- log - log
- `git log`: show commit logs - `git log`: show commit logs
- `git log --oneline | head`: To quickly see the latest ten commits on a branch. - `git log --oneline | head`: To quickly see the latest ten commits on a branch.

View File

@ -50,23 +50,25 @@ templating systems.
- `templates/zerver/` For [Jinja2](http://jinja.pocoo.org/) templates - `templates/zerver/` For [Jinja2](http://jinja.pocoo.org/) templates
for the backend (for zerver app; logged-in content is in `templates/zerver/app`). for the backend (for zerver app; logged-in content is in `templates/zerver/app`).
- `static/templates/` [Handlebars](https://handlebarsjs.com/) templates for the frontend. - `web/templates/` [Handlebars](https://handlebarsjs.com/) templates for the frontend.
--- ---
### JavaScript, TypeScript, and other static assets ### JavaScript, TypeScript, and other frontend assets
- `static/js/` Zulip's own JavaScript and TypeScript sources. - `web/src/` Zulip's own JavaScript and TypeScript sources.
- `static/styles/` Zulip's own CSS. - `web/styles/` Zulip's own CSS.
- `static/images/` Zulip's images. - `web/images/` Images bundled with webpack.
- `static/third/` Third-party JavaScript and CSS that has been vendored. - `static/images/` Images served directly to the web.
- `web/third/` Third-party JavaScript and CSS that has been vendored.
- `node_modules/` Third-party JavaScript installed via `yarn`. - `node_modules/` Third-party JavaScript installed via `yarn`.
- `static/shared/icons/` Icons placed in this directory are compiled - `web/shared/icons/` Icons placed in this directory are compiled
into an icon font. into an icon font.
--- ---

View File

@ -182,9 +182,9 @@ The relevant files are:
get_chart_data in this file. The bottom half of this file (with all the get_chart_data in this file. The bottom half of this file (with all the
raw sql queries) is for a different page (/activity), not related to raw sql queries) is for a different page (/activity), not related to
/stats. /stats.
- static/js/stats/stats.js: The JavaScript and Plotly code. - web/src/stats/stats.js: The JavaScript and Plotly code.
- templates/analytics/stats.html - templates/analytics/stats.html
- static/styles/stats.css and static/styles/portico.css: We are in the - web/styles/stats.css and web/styles/portico.css: We are in the
process of re-styling this page to use in-app css instead of portico css, process of re-styling this page to use in-app css instead of portico css,
but there is currently still a lot of portico influence. but there is currently still a lot of portico influence.
- analytics/urls.py: Has the URL routes; it's unlikely you will have to - analytics/urls.py: Has the URL routes; it's unlikely you will have to

View File

@ -242,7 +242,7 @@ reasoning here.
release tarball. release tarball.
- **Checked-in packages**. In contrast with Python, we have a few - **Checked-in packages**. In contrast with Python, we have a few
JavaScript dependencies that we have copied into the main Zulip JavaScript dependencies that we have copied into the main Zulip
repository under `static/third`, often with patches. These date repository under `web/third`, often with patches. These date
from an era before `npm` existed. It is a project goal to eliminate from an era before `npm` existed. It is a project goal to eliminate
these checked-in versions of dependencies and instead use versions these checked-in versions of dependencies and instead use versions
managed by the npm repositories. managed by the npm repositories.
@ -317,7 +317,7 @@ implementation of that tool.
The list of languages supported by our Markdown syntax highlighting The list of languages supported by our Markdown syntax highlighting
comes from the [pygments][] package. `tools/setup/build_pygments_data` is comes from the [pygments][] package. `tools/setup/build_pygments_data` is
responsible for generating `static/generated/pygments_data.json` so that responsible for generating `web/generated/pygments_data.json` so that
our JavaScript Markdown processor has access to the supported list. our JavaScript Markdown processor has access to the supported list.
## Modifying provisioning ## Modifying provisioning

View File

@ -17,7 +17,7 @@ Some examples are:
stream.) stream.)
The main module in the frontend that manages this all is The main module in the frontend that manages this all is
`static/js/hashchange.js` (plus `hash_util.js` for all the parsing `web/src/hashchange.js` (plus `hash_util.js` for all the parsing
code), which is unfortunately one of our thorniest modules. Part of code), which is unfortunately one of our thorniest modules. Part of
the reason that it's thorny is that it needs to support a lot of the reason that it's thorny is that it needs to support a lot of
different flows: different flows:
@ -54,7 +54,7 @@ all of this (would be a good project to add them to the
[Puppeteer suite][testing-with-puppeteer]) and there's enough complexity [Puppeteer suite][testing-with-puppeteer]) and there's enough complexity
that it's easy to accidentally break something. that it's easy to accidentally break something.
The main external API lives in `static/js/browser_history.js`: The main external API lives in `web/src/browser_history.js`:
- `browser_history.update` is used to update the browser - `browser_history.update` is used to update the browser
history, and it should be called when the app code is taking care history, and it should be called when the app code is taking care
@ -97,7 +97,7 @@ reload itself:
start looking for a good time to reload, based on when the user is start looking for a good time to reload, based on when the user is
idle (ideally, we'd reload when they're not looking and restore idle (ideally, we'd reload when they're not looking and restore
state so that the user never knew it happened!). The logic for state so that the user never knew it happened!). The logic for
doing this is in `static/js/reload.js`; but regardless we'll reload doing this is in `web/src/reload.js`; but regardless we'll reload
within 30 minutes unconditionally. within 30 minutes unconditionally.
An important detail in server-initiated reloads is that we An important detail in server-initiated reloads is that we

View File

@ -30,7 +30,7 @@ ALL_HOTSPOTS = {
### Step 2: Configure hotspot placement ### Step 2: Configure hotspot placement
The target element and visual orientation of each hotspot is specified in The target element and visual orientation of each hotspot is specified in
`HOTSPOT_LOCATIONS` of `static/js/hotspots.js`. `HOTSPOT_LOCATIONS` of `web/src/hotspots.js`.
The `icon_offset` property specifies where the pulsing icon is placed _relative to The `icon_offset` property specifies where the pulsing icon is placed _relative to
the width and height of the target element_. the width and height of the target element_.
@ -67,7 +67,7 @@ content and behind sidebars and overlays. If a hotspot is associated with
a target element on a sidebar or overlay, the icon's z-index may need to a target element on a sidebar or overlay, the icon's z-index may need to
be increased to 101, 102, or 103. be increased to 101, 102, or 103.
This adjustment can be made at the bottom of `static/styles/hotspots.css`: This adjustment can be made at the bottom of `web/styles/hotspots.css`:
```css ```css
#hotspot_new_hotspot_name_icon { #hotspot_new_hotspot_name_icon {

View File

@ -2,13 +2,13 @@
## Zulip CSS organization ## Zulip CSS organization
The Zulip application's CSS can be found in the `static/styles/` The Zulip application's CSS can be found in the `web/styles/`
directory. Zulip uses [Bootstrap](https://getbootstrap.com/) as its directory. Zulip uses [Bootstrap](https://getbootstrap.com/) as its
main third-party CSS library. main third-party CSS library.
Zulip uses PostCSS for its CSS files. There are two high-level sections Zulip uses PostCSS for its CSS files. There are two high-level sections
of CSS: the "portico" (logged-out pages like /help/, /login/, etc.), of CSS: the "portico" (logged-out pages like /help/, /login/, etc.),
and the app. The portico CSS lives under the `static/styles/portico` and the app. The portico CSS lives under the `web/styles/portico`
subdirectory. subdirectory.
## Editing Zulip CSS ## Editing Zulip CSS
@ -111,7 +111,7 @@ path('config-error/google', TemplateView.as_view(
For text generated in the frontend, live-rendering HTML from For text generated in the frontend, live-rendering HTML from
JavaScript for things like the main message feed, we use the JavaScript for things like the main message feed, we use the
[Handlebars][] template engine (files in `static/templates/`) and [Handlebars][] template engine (files in `web/templates/`) and
sometimes work directly from JavaScript code (though as a policy sometimes work directly from JavaScript code (though as a policy
matter, we try to avoid generating HTML directly in JavaScript matter, we try to avoid generating HTML directly in JavaScript
wherever possible). wherever possible).
@ -150,13 +150,13 @@ relevant background as well.
### Primary build process ### Primary build process
Zulip's frontend is primarily JavaScript in the `static/js` directory; Zulip's frontend is primarily JavaScript in the `web/src` directory;
we are working on migrating these to TypeScript modules. Stylesheets we are working on migrating these to TypeScript modules. Stylesheets
are written in CSS extended by various PostCSS plugins; they are are written in CSS extended by various PostCSS plugins; they are
converted from plain CSS, and we have yet to take full advantage of converted from plain CSS, and we have yet to take full advantage of
the features PostCSS offers. We use Webpack to transpile and build JS the features PostCSS offers. We use Webpack to transpile and build JS
and CSS bundles that the browser can understand, one for each entry and CSS bundles that the browser can understand, one for each entry
points specified in `tools/webpack.*assets.json`; source maps are points specified in `web/webpack.*assets.json`; source maps are
generated in the process for better debugging experience. generated in the process for better debugging experience.
In development mode, bundles are built and served on the fly using In development mode, bundles are built and served on the fly using
@ -169,7 +169,7 @@ ready for deployment.
You can trace which source files are included in which HTML templates You can trace which source files are included in which HTML templates
by comparing the `entrypoint` variables in the HTML templates under by comparing the `entrypoint` variables in the HTML templates under
`templates/` with the bundles declared in `tools/webpack.*assets.json`. `templates/` with the bundles declared in `web/webpack.*assets.json`.
### Adding static files ### Adding static files
@ -187,34 +187,34 @@ first add it to the appropriate place under `static/`.
We update those versions periodically to ensure we're running a recent We update those versions periodically to ensure we're running a recent
version of third-party libraries. version of third-party libraries.
- Third-party files that we have patched should all go in - Third-party files that we have patched should all go in
`static/third/`. Tag the commit with "[third]" when adding or `web/third/`. Tag the commit with "[third]" when adding or
modifying a third-party package. Our goal is to the extent possible modifying a third-party package. Our goal is to the extent possible
to eliminate patched third-party code from the project. to eliminate patched third-party code from the project.
- Our own JavaScript and TypeScript files live under `static/js`. Ideally, - Our own JavaScript and TypeScript files live under `web/src`. Ideally,
new modules should be written in TypeScript (details on this policy below). new modules should be written in TypeScript (details on this policy below).
- CSS files live under `static/styles`. - CSS files live under `web/styles`.
- Portico JavaScript ("portico" means for logged-out pages) lives under - Portico JavaScript ("portico" means for logged-out pages) lives under
`static/js/portico`. `web/src/portico`.
- Custom SVG graphics living under `static/assets/icons` are compiled into - Custom SVG graphics living under `web/images/icons` are compiled into
custom icon webfonts by webfont-loader according to the custom icon webfonts by webfont-loader according to the
`static/assets/icons/template.hbs` template. `web/images/icons/template.hbs` template.
For your asset to be included in a development/production bundle, it For your asset to be included in a development/production bundle, it
needs to be accessible from one of the entry points defined either in needs to be accessible from one of the entry points defined either in
`tools/webpack.assets.json` or `tools/webpack.dev-assets.json`. `web/webpack.assets.json` or `web/webpack.dev-assets.json`.
- If you plan to only use the file within the app proper, and not on the login - If you plan to only use the file within the app proper, and not on the login
page or other standalone pages, put it in the `app` bundle by importing it page or other standalone pages, put it in the `app` bundle by importing it
in `static/js/bundles/app.js`. in `web/src/bundles/app.js`.
- If it needs to be available both in the app and all - If it needs to be available both in the app and all
logged-out/portico pages, import it to logged-out/portico pages, import it to
`static/js/bundles/common.js` which itself is imported to the `web/src/bundles/common.js` which itself is imported to the
`app` and `common` bundles. `app` and `common` bundles.
- If it's just used on a single standalone page which is only used in - If it's just used on a single standalone page which is only used in
a development environment (e.g. `/devlogin`) create a new entry a development environment (e.g. `/devlogin`) create a new entry
point in `tools/webpack.dev-assets.json` or it's used in both point in `web/webpack.dev-assets.json` or it's used in both
production and development (e.g. `/stats`) create a new entry point production and development (e.g. `/stats`) create a new entry point
in `tools/webpack.assets.json`. Use the `bundle` macro (defined in in `web/webpack.assets.json`. Use the `bundle` macro (defined in
`templates/zerver/base.html`) in the relevant Jinja2 template to `templates/zerver/base.html`) in the relevant Jinja2 template to
inject the compiled JS and CSS. inject the compiled JS and CSS.
@ -267,11 +267,11 @@ TypeScript also uses the ES6 module system. See our documentation on
Webpack does not ordinarily allow modules to be accessed directly from Webpack does not ordinarily allow modules to be accessed directly from
the browser console, but for debugging convenience, we have a custom the browser console, but for debugging convenience, we have a custom
webpack plugin (`tools/debug-require-webpack-plugin.ts`) that exposes webpack plugin (`web/debug-require-webpack-plugin.ts`) that exposes
a version of the `require()` function to the development environment a version of the `require()` function to the development environment
browser console for this purpose. For example, you can access our browser console for this purpose. For example, you can access our
`people` module by evaluating `people` module by evaluating
`people = require("./static/js/people")`, or the third-party `lodash` `people = require("./web/src/people")`, or the third-party `lodash`
module with `_ = require("lodash")`. This mechanism is **not** a module with `_ = require("lodash")`. This mechanism is **not** a
stable API and should not be used for any purpose other than stable API and should not be used for any purpose other than
interactive debugging. interactive debugging.

View File

@ -26,7 +26,7 @@ var pills = input_pill.create({
}); });
``` ```
You can look at `static/js/user_pill.js` to see how the above You can look at `web/src/user_pill.js` to see how the above
methods are implemented. Essentially you just need to convert methods are implemented. Essentially you just need to convert
from raw data (like an email) to structured data (like an object from raw data (like an email) to structured data (like an object
with display_value, email, and user_id for a user), and vice with display_value, email, and user_id for a user), and vice

View File

@ -191,7 +191,7 @@ might use). In development, this means displaying a highly visible
overlay over the message view area, to make exceptions in testing a overlay over the message view area, to make exceptions in testing a
new feature hard to miss. new feature hard to miss.
- Blueslip is implemented in `static/js/blueslip.js`. - Blueslip is implemented in `web/src/blueslip.js`.
- In order to capture essentially any error occurring in the browser, - In order to capture essentially any error occurring in the browser,
Blueslip listens for the `error` event on `window`, and has methods Blueslip listens for the `error` event on `window`, and has methods
for being manually triggered by Zulip JavaScript code for warnings for being manually triggered by Zulip JavaScript code for warnings
@ -200,7 +200,7 @@ new feature hard to miss.
browser session, and includes them in reports to the server, so that browser session, and includes them in reports to the server, so that
one can see cases where exceptions chained together. You can print one can see cases where exceptions chained together. You can print
this log from the browser console using this log from the browser console using
`blueslip = require("./static/js/blueslip"); blueslip.get_log()`. `blueslip = require("./web/src/blueslip"); blueslip.get_log()`.
Blueslip supports several error levels: Blueslip supports several error levels:
@ -236,7 +236,7 @@ and report to the server the following whenever a message is sent:
the server-rendered content, which can be used for statistics on how the server-rendered content, which can be used for statistics on how
effective our [local echo system](markdown.md) is. effective our [local echo system](markdown.md) is.
The code is all in `zerver/lib/report.py` and `static/js/sent_messages.js`. The code is all in `zerver/lib/report.py` and `web/src/sent_messages.js`.
We have similar reporting for the time it takes to narrow / switch to We have similar reporting for the time it takes to narrow / switch to
a new view: a new view:

View File

@ -17,7 +17,7 @@ authoritatively render messages to HTML (and implements
slow/expensive/complex features like querying the Twitter API to slow/expensive/complex features like querying the Twitter API to
render tweets nicely). The frontend implementation is in JavaScript, render tweets nicely). The frontend implementation is in JavaScript,
based on [marked.js](https://github.com/chjj/marked) based on [marked.js](https://github.com/chjj/marked)
(`static/js/echo.js`), and is used to preview and locally echo (`web/src/echo.js`), and is used to preview and locally echo
messages the moment the sender hits Enter, without waiting for round messages the moment the sender hits Enter, without waiting for round
trip from the server. Those frontend renderings are only shown to the trip from the server. Those frontend renderings are only shown to the
sender of a message, and they are (ideally) identical to the backend sender of a message, and they are (ideally) identical to the backend
@ -101,12 +101,12 @@ When changing Zulip's Markdown syntax, you need to update several
places: places:
- The backend Markdown processor (`zerver/lib/markdown/__init__.py`). - The backend Markdown processor (`zerver/lib/markdown/__init__.py`).
- The frontend Markdown processor (`static/js/markdown.js` and sometimes - The frontend Markdown processor (`web/src/markdown.js` and sometimes
`static/third/marked/lib/marked.js`), or `markdown.contains_backend_only_syntax` if `web/third/marked/lib/marked.js`), or `markdown.contains_backend_only_syntax` if
your changes won't be supported in the frontend processor. your changes won't be supported in the frontend processor.
- If desired, the typeahead logic in `static/js/composebox_typeahead.js`. - If desired, the typeahead logic in `web/src/composebox_typeahead.js`.
- The test suite, probably via adding entries to `zerver/tests/fixtures/markdown_test_cases.json`. - The test suite, probably via adding entries to `zerver/tests/fixtures/markdown_test_cases.json`.
- The in-app Markdown documentation (`markdown_help_rows` in `static/js/info_overlay.js`). - The in-app Markdown documentation (`markdown_help_rows` in `web/src/info_overlay.js`).
- The list of changes to Markdown at the end of this document. - The list of changes to Markdown at the end of this document.
Important considerations for any changes are: Important considerations for any changes are:

View File

@ -97,7 +97,7 @@ as follows:
debugging this system, since it has so much complexity. debugging this system, since it has so much complexity.
- Desktop notifications are the simplest; they are implemented - Desktop notifications are the simplest; they are implemented
client-side by the web/desktop app's logic client-side by the web/desktop app's logic
(`static/js/notifications.js`) inspecting the `flags` fields that (`web/src/notifications.js`) inspecting the `flags` fields that
were spliced into `message` events by the Tornado system, as well as were spliced into `message` events by the Tornado system, as well as
the user's notification settings. the user's notification settings.
- The queue processors for those queues make the final determination - The queue processors for those queues make the final determination

View File

@ -47,7 +47,7 @@ about that data structure:
- Users can disable their own presence updates in user settings - Users can disable their own presence updates in user settings
(`UserProfile.presence_enabled` is the flag storing [this user (`UserProfile.presence_enabled` is the flag storing [this user
preference](https://zulip.com/help/status-and-availability#disable-updating-availability)). preference](https://zulip.com/help/status-and-availability#disable-updating-availability)).
- The `status_from_timestamp` function in `static/js/presence.js` is - The `status_from_timestamp` function in `web/src/presence.js` is
useful sample code; the `OFFLINE_THRESHOLD_SECS` check is critical useful sample code; the `OFFLINE_THRESHOLD_SECS` check is critical
to correct output. to correct output.
- We provide the data for e.g. whether the user was online on their - We provide the data for e.g. whether the user was online on their

View File

@ -162,7 +162,7 @@ messages.
properties (at the very least, message ID and timestamp) and properties (at the very least, message ID and timestamp) and
rerenders it in any message lists where it appears. This is rerenders it in any message lists where it appears. This is
primarily done in the `process_from_server` function in primarily done in the `process_from_server` function in
`static/js/echo.js`. `web/src/echo.js`.
### Local echo in message editing ### Local echo in message editing

View File

@ -52,4 +52,4 @@ send a message with the raw content.
## Typeahead ## Typeahead
Typeahead for both slash commands (and widgets) is implemented Typeahead for both slash commands (and widgets) is implemented
via the `slash_commands` object in `static/js/composebox_typeahead.js`. via the `slash_commands` object in `web/src/composebox_typeahead.js`.

View File

@ -45,7 +45,7 @@ repeated updates to the server, so that downstream clients know that the
user is still typing. (Zulip messages tend to be longer than user is still typing. (Zulip messages tend to be longer than
messages in other chat/text clients, so this detail is important.) messages in other chat/text clients, so this detail is important.)
We have a small state machine in `static/shared/js/typing_status.js` that We have a small state machine in `web/shared/src/typing_status.js` that
makes sure subsequent "start" requests get sent out every ten makes sure subsequent "start" requests get sent out every ten
seconds. (This document is intended to describe the high level seconds. (This document is intended to describe the high level
architecture; the actual time values may be tuned in future releases. architecture; the actual time values may be tuned in future releases.
@ -107,15 +107,15 @@ structures, and then it eventually shows or hides status messages.
We'll describe the flow of data through the web app We'll describe the flow of data through the web app
as a concrete example. as a concrete example.
The events will come in to `static/js/server_events_dispatch.js`. The events will come in to `web/src/server_events_dispatch.js`.
The `stop` and `start` operations get further handled by The `stop` and `start` operations get further handled by
`static/js/typing_events.js`. `web/src/typing_events.js`.
The main goal is then to triage which events should lead to The main goal is then to triage which events should lead to
display changes. display changes.
The web app client maintains a list of incoming "typists" using The web app client maintains a list of incoming "typists" using
code in `static/js/typing_data.js`. The API here has functions code in `web/src/typing_data.js`. The API here has functions
like the following: like the following:
- `add_typist` - `add_typist`

View File

@ -51,11 +51,11 @@ Some important code entities for the widget implementation are:
- `SubMessage` database table - `SubMessage` database table
- `/json/submessage` API endpoint - `/json/submessage` API endpoint
- `static/js/submessage.js` - `web/src/submessage.js`
- `static/js/poll_widget.js` - `web/src/poll_widget.js`
- `static/js/widgetize.js` - `web/src/widgetize.js`
- `static/js/zform.js` - `web/src/zform.js`
- `static/templates/widgets/` - `web/templates/widgets/`
- `zerver/lib/widget.py` - `zerver/lib/widget.py`
- `zerver/views/submessage.py` - `zerver/views/submessage.py`
@ -105,10 +105,10 @@ is given a parent `elem` when its `activate` function
is called. This is just a `<div>` inside of the parent is called. This is just a `<div>` inside of the parent
message in the message pane. The widget has access to message in the message pane. The widget has access to
jQuery and template.render, and the developer can create jQuery and template.render, and the developer can create
new templates in `static/templates/widgets/`. new templates in `web/templates/widgets/`.
A good way to learn the system is to read the code A good way to learn the system is to read the code
in `static/js/poll_widget.js`. It is worth noting that in `web/src/poll_widget.js`. It is worth noting that
writing a new widget requires only minor backend writing a new widget requires only minor backend
changes in the current architecture. This could change changes in the current architecture. This could change
in the future, but for now, a frontend developer mostly in the future, but for now, a frontend developer mostly
@ -299,7 +299,7 @@ When the message gets to the client, the codepath for **zform**
is actually quite similar to what happens with a more is actually quite similar to what happens with a more
customized widget like **poll**. (In fact, **zform** is a customized widget like **poll**. (In fact, **zform** is a
sibling of **poll** and **zform** just has a somewhat more sibling of **poll** and **zform** just has a somewhat more
generic job to do.) In `static/js/widgetize.js` you will see generic job to do.) In `web/src/widgetize.js` you will see
where this code converges, with snippets like this: where this code converges, with snippets like this:
```js ```js
@ -308,7 +308,7 @@ widgets.todo = todo_widget;
widgets.zform = zform; widgets.zform = zform;
``` ```
The code in `static/js/zform.js` renders the form (not The code in `web/src/zform.js` renders the form (not
shown here) and then sets up a click handler like below: shown here) and then sets up a click handler like below:
```js ```js

View File

@ -45,8 +45,8 @@ You can also run them individually or pass specific files:
```bash ```bash
./tools/lint ./tools/lint
./tools/lint static/js/compose.js ./tools/lint web/src/compose.js
./tools/lint static/js/ ./tools/lint web/src/
``` ```
`./tools/lint` has many useful options; you can read about them in its `./tools/lint` has many useful options; you can read about them in its

View File

@ -39,7 +39,7 @@ in `frontend_tests/node_tests`. Here is an example test from
``` ```
The names of the node tests generally align with the names of the The names of the node tests generally align with the names of the
modules they test. If you modify a JS module in `static/js` you should modules they test. If you modify a JS module in `web/src` you should
see if there are corresponding test in `frontend_tests/node_tests`. If see if there are corresponding test in `frontend_tests/node_tests`. If
there are, you should strive to follow the patterns of the existing tests there are, you should strive to follow the patterns of the existing tests
and add your own tests. and add your own tests.
@ -120,7 +120,7 @@ For modules that you want to completely stub out, use a pattern like
this: this:
```js ```js
const reminder = mock_esm("../../static/js/reminder", { const reminder = mock_esm("../../web/src/reminder", {
is_deferred_delivery: noop, is_deferred_delivery: noop,
}); });

View File

@ -239,7 +239,7 @@ $("#foo").html(
The only HTML tags allowed directly in translated strings are the The only HTML tags allowed directly in translated strings are the
simple HTML tags enumerated in `default_html_elements` simple HTML tags enumerated in `default_html_elements`
(`static/js/i18n.js`) with no attributes. This helps to avoid (`web/src/i18n.js`) with no attributes. This helps to avoid
exposing HTML details to translators. If you need to include more exposing HTML details to translators. If you need to include more
complex markup such as a link, you can define a custom HTML tag complex markup such as a link, you can define a custom HTML tag
locally to the translation: locally to the translation:

View File

@ -44,11 +44,11 @@ organization in Zulip). The following files are involved in the process:
**Frontend** **Frontend**
- `static/templates/settings/organization_permissions_admin.hbs`: defines - `web/templates/settings/organization_permissions_admin.hbs`: defines
the structure of the admin permissions page (checkboxes for each organization the structure of the admin permissions page (checkboxes for each organization
permission setting). permission setting).
- `static/js/settings_org.js`: handles organization setting form submission. - `web/src/settings_org.js`: handles organization setting form submission.
- `static/js/server_events_dispatch.js`: handles events coming from the server - `web/src/server_events_dispatch.js`: handles events coming from the server
(ex: pushing an organization change to other open browsers and updating (ex: pushing an organization change to other open browsers and updating
the application's state). the application's state).
@ -124,17 +124,17 @@ Realm setting, in `test_realm.py`).
### Frontend changes ### Frontend changes
**JavaScript/TypeScript:** Zulip's JavaScript and TypeScript sources are **JavaScript/TypeScript:** Zulip's JavaScript and TypeScript sources are
located in the directory `static/js/`. The exact files you may need to change located in the directory `web/src/`. The exact files you may need to change
depend on your feature. If you've added a new event that is sent to clients, depend on your feature. If you've added a new event that is sent to clients,
be sure to add a handler for it in `static/js/server_events_dispatch.js`. be sure to add a handler for it in `web/src/server_events_dispatch.js`.
**CSS:** The primary CSS file is `static/styles/zulip.css`. If your new **CSS:** The primary CSS file is `web/styles/zulip.css`. If your new
feature requires UI changes, you may need to add additional CSS to this feature requires UI changes, you may need to add additional CSS to this
file. file.
**Templates:** The initial page structure is rendered via Jinja2 **Templates:** The initial page structure is rendered via Jinja2
templates located in `templates/zerver/app`. For JavaScript, Zulip uses templates located in `templates/zerver/app`. For JavaScript, Zulip uses
Handlebars templates located in `static/templates`. Templates are Handlebars templates located in `web/templates`. Templates are
precompiled as part of the build/deploy process. precompiled as part of the build/deploy process.
Zulip is fully internationalized, so when writing both HTML templates Zulip is fully internationalized, so when writing both HTML templates
@ -532,7 +532,7 @@ to server when a realm is updated) and the change event needs to be
handled on the client. handled on the client.
To add the checkbox to the admin page, modify the relevant template in To add the checkbox to the admin page, modify the relevant template in
`static/templates/settings/`, which can be `web/templates/settings/`, which can be
`organization_permissions_admin.hbs` or `organization_settings_admin.hbs` `organization_permissions_admin.hbs` or `organization_settings_admin.hbs`
(omitted here since it is relatively straightforward). (omitted here since it is relatively straightforward).
@ -540,10 +540,10 @@ If you're adding a non-checkbox field, you'll need to specify the type
of the field via the `data-setting-widget-type` attribute in the HTML of the field via the `data-setting-widget-type` attribute in the HTML
template. template.
Then add the new form control in `static/js/admin.js`. Then add the new form control in `web/src/admin.js`.
```diff ```diff
// static/js/admin.js // web/src/admin.js
export function build_page() { export function build_page() {
const options = { const options = {
@ -556,7 +556,7 @@ Then add the new form control in `static/js/admin.js`.
``` ```
The JavaScript code for organization settings and permissions can be found in The JavaScript code for organization settings and permissions can be found in
`static/js/settings_org.js`. `web/src/settings_org.js`.
In frontend, we have split the `property_types` into three objects: In frontend, we have split the `property_types` into three objects:
@ -616,7 +616,7 @@ setting has changed, your function should be referenced in the
`settings_emoji.update_custom_emoji_ui`. `settings_emoji.update_custom_emoji_ui`.
```diff ```diff
// static/js/server_events_dispatch.js // web/src/server_events_dispatch.js
function dispatch_normal_event(event) { function dispatch_normal_event(event) {
switch (event.type) { switch (event.type) {

View File

@ -282,7 +282,7 @@ Zulip realm).
You should always use `channel.<method>` to make an `HTTP <method>` call You should always use `channel.<method>` to make an `HTTP <method>` call
to the Zulip JSON API. As an example, in to the Zulip JSON API. As an example, in
[static/js/admin.js](https://github.com/zulip/zulip/blob/main/static/js/admin.js) [web/src/admin.js](https://github.com/zulip/zulip/blob/main/web/src/admin.js)
```js ```js
var url = "/json/realm"; var url = "/json/realm";

View File

@ -18,15 +18,15 @@ const _document = {
}, },
}; };
const channel = mock_esm("../../static/js/channel"); const channel = mock_esm("../../web/src/channel");
const compose_state = mock_esm("../../static/js/compose_state"); const compose_state = mock_esm("../../web/src/compose_state");
const narrow = mock_esm("../../static/js/narrow"); const narrow = mock_esm("../../web/src/narrow");
const padded_widget = mock_esm("../../static/js/padded_widget"); const padded_widget = mock_esm("../../web/src/padded_widget");
const pm_list = mock_esm("../../static/js/pm_list"); const pm_list = mock_esm("../../web/src/pm_list");
const popovers = mock_esm("../../static/js/popovers"); const popovers = mock_esm("../../web/src/popovers");
const resize = mock_esm("../../static/js/resize"); const resize = mock_esm("../../web/src/resize");
const scroll_util = mock_esm("../../static/js/scroll_util"); const scroll_util = mock_esm("../../web/src/scroll_util");
const watchdog = mock_esm("../../static/js/watchdog"); const watchdog = mock_esm("../../web/src/watchdog");
set_global("document", _document); set_global("document", _document);

View File

@ -7,7 +7,7 @@ const {mock_esm, zrequire} = require("../zjsunit/namespace");
const {run_test} = require("../zjsunit/test"); const {run_test} = require("../zjsunit/test");
const $ = require("../zjsunit/zjquery"); const $ = require("../zjsunit/zjquery");
const channel = mock_esm("../../static/js/channel"); const channel = mock_esm("../../web/src/channel");
const alert_words = zrequire("alert_words"); const alert_words = zrequire("alert_words");
const alert_words_ui = zrequire("alert_words_ui"); const alert_words_ui = zrequire("alert_words_ui");
@ -20,7 +20,7 @@ const noop = () => {};
run_test("rerender_alert_words_ui", ({mock_template}) => { run_test("rerender_alert_words_ui", ({mock_template}) => {
let list_widget_create_called = false; let list_widget_create_called = false;
alert_words_ui.reset(); alert_words_ui.reset();
const ListWidget = mock_esm("../../static/js/list_widget", { const ListWidget = mock_esm("../../web/src/list_widget", {
modifier: noop, modifier: noop,
create(container, words, opts) { create(container, words, opts) {
const alert_words = []; const alert_words = [];

View File

@ -14,7 +14,7 @@ const dom = new JSDOM(template, {pretendToBeVisual: true});
const document = dom.window.document; const document = dom.window.document;
const location = set_global("location", {}); const location = set_global("location", {});
const helpers = mock_esm("../../static/js/billing/helpers", { const helpers = mock_esm("../../web/src/billing/helpers", {
set_tab() {}, set_tab() {},
}); });

View File

@ -19,7 +19,7 @@ const dom = new JSDOM(template, {
const jquery = jQueryFactory(dom.window); const jquery = jQueryFactory(dom.window);
const history = set_global("history", {}); const history = set_global("history", {});
const loading = mock_esm("../../static/js/loading"); const loading = mock_esm("../../web/src/loading");
set_global("document", { set_global("document", {
title: "Zulip", title: "Zulip",
}); });

View File

@ -10,8 +10,8 @@ const blueslip_stacktrace = zrequire("blueslip_stacktrace");
run_test("clean_path", () => { run_test("clean_path", () => {
// Local file // Local file
assert.strictEqual( assert.strictEqual(
blueslip_stacktrace.clean_path("webpack:///static/js/upload.js"), blueslip_stacktrace.clean_path("webpack:///web/src/upload.js"),
"/static/js/upload.js", "/web/src/upload.js",
); );
// Third party library (jQuery) // Third party library (jQuery)
@ -36,9 +36,9 @@ run_test("clean_function_name", () => {
// Local file // Local file
assert.deepEqual( assert.deepEqual(
blueslip_stacktrace.clean_function_name("Object../static/js/upload.js.exports.options"), blueslip_stacktrace.clean_function_name("Object../web/src/upload.js.exports.options"),
{ {
scope: "Object../static/js/upload.js.exports.", scope: "Object../web/src/upload.js.exports.",
name: "options", name: "options",
}, },
); );

View File

@ -9,7 +9,7 @@ const {run_test} = require("../zjsunit/test");
const blueslip = require("../zjsunit/zblueslip"); const blueslip = require("../zjsunit/zblueslip");
const {page_params, user_settings} = require("../zjsunit/zpage_params"); const {page_params, user_settings} = require("../zjsunit/zpage_params");
const timerender = mock_esm("../../static/js/timerender"); const timerender = mock_esm("../../web/src/timerender");
const compose_fade_helper = zrequire("compose_fade_helper"); const compose_fade_helper = zrequire("compose_fade_helper");
const muted_users = zrequire("muted_users"); const muted_users = zrequire("muted_users");

View File

@ -9,8 +9,8 @@ const {run_test} = require("../zjsunit/test");
const blueslip = require("../zjsunit/zblueslip"); const blueslip = require("../zjsunit/zblueslip");
const $ = require("../zjsunit/zjquery"); const $ = require("../zjsunit/zjquery");
const padded_widget = mock_esm("../../static/js/padded_widget"); const padded_widget = mock_esm("../../web/src/padded_widget");
const message_viewport = mock_esm("../../static/js/message_viewport"); const message_viewport = mock_esm("../../web/src/message_viewport");
const people = zrequire("people"); const people = zrequire("people");
const {BuddyList} = zrequire("buddy_list"); const {BuddyList} = zrequire("buddy_list");

View File

@ -13,7 +13,7 @@ const xhr_401 = {
}; };
let login_to_access_shown = false; let login_to_access_shown = false;
mock_esm("../../static/js/spectators", { mock_esm("../../web/src/spectators", {
login_to_access() { login_to_access() {
login_to_access_shown = true; login_to_access_shown = true;
}, },

View File

@ -28,19 +28,19 @@ set_global(
const fake_now = 555; const fake_now = 555;
const channel = mock_esm("../../static/js/channel"); const channel = mock_esm("../../web/src/channel");
const compose_actions = mock_esm("../../static/js/compose_actions"); const compose_actions = mock_esm("../../web/src/compose_actions");
const compose_fade = mock_esm("../../static/js/compose_fade"); const compose_fade = mock_esm("../../web/src/compose_fade");
const compose_pm_pill = mock_esm("../../static/js/compose_pm_pill"); const compose_pm_pill = mock_esm("../../web/src/compose_pm_pill");
const loading = mock_esm("../../static/js/loading"); const loading = mock_esm("../../web/src/loading");
const markdown = mock_esm("../../static/js/markdown"); const markdown = mock_esm("../../web/src/markdown");
const reminder = mock_esm("../../static/js/reminder"); const reminder = mock_esm("../../web/src/reminder");
const rendered_markdown = mock_esm("../../static/js/rendered_markdown"); const rendered_markdown = mock_esm("../../web/src/rendered_markdown");
const resize = mock_esm("../../static/js/resize"); const resize = mock_esm("../../web/src/resize");
const sent_messages = mock_esm("../../static/js/sent_messages"); const sent_messages = mock_esm("../../web/src/sent_messages");
const server_events = mock_esm("../../static/js/server_events"); const server_events = mock_esm("../../web/src/server_events");
const transmit = mock_esm("../../static/js/transmit"); const transmit = mock_esm("../../web/src/transmit");
const upload = mock_esm("../../static/js/upload"); const upload = mock_esm("../../web/src/upload");
const compose_ui = zrequire("compose_ui"); const compose_ui = zrequire("compose_ui");
const compose_banner = zrequire("compose_banner"); const compose_banner = zrequire("compose_banner");

View File

@ -17,38 +17,38 @@ set_global("document", {
to_$: () => $("document-stub"), to_$: () => $("document-stub"),
}); });
const channel = mock_esm("../../static/js/channel"); const channel = mock_esm("../../web/src/channel");
const compose_fade = mock_esm("../../static/js/compose_fade", { const compose_fade = mock_esm("../../web/src/compose_fade", {
clear_compose: noop, clear_compose: noop,
}); });
const compose_pm_pill = mock_esm("../../static/js/compose_pm_pill"); const compose_pm_pill = mock_esm("../../web/src/compose_pm_pill");
const compose_ui = mock_esm("../../static/js/compose_ui", { const compose_ui = mock_esm("../../web/src/compose_ui", {
autosize_textarea: noop, autosize_textarea: noop,
is_full_size: () => false, is_full_size: () => false,
}); });
const hash_util = mock_esm("../../static/js/hash_util"); const hash_util = mock_esm("../../web/src/hash_util");
const narrow_state = mock_esm("../../static/js/narrow_state", { const narrow_state = mock_esm("../../web/src/narrow_state", {
set_compose_defaults: noop, set_compose_defaults: noop,
}); });
mock_esm("../../static/js/reload_state", { mock_esm("../../web/src/reload_state", {
is_in_progress: () => false, is_in_progress: () => false,
}); });
mock_esm("../../static/js/recent_topics_util", { mock_esm("../../web/src/recent_topics_util", {
is_visible: noop, is_visible: noop,
}); });
mock_esm("../../static/js/drafts", { mock_esm("../../web/src/drafts", {
update_draft: noop, update_draft: noop,
}); });
mock_esm("../../static/js/unread_ops", { mock_esm("../../web/src/unread_ops", {
notify_server_message_read: noop, notify_server_message_read: noop,
}); });
mock_esm("../../static/js/message_lists", { mock_esm("../../web/src/message_lists", {
current: { current: {
can_mark_messages_read: () => true, can_mark_messages_read: () => true,
}, },
}); });
mock_esm("../../static/js/resize", { mock_esm("../../web/src/resize", {
reset_compose_message_max_height: noop, reset_compose_message_max_height: noop,
}); });

View File

@ -7,13 +7,13 @@ const {mock_esm, set_global, zrequire} = require("../zjsunit/namespace");
const {run_test} = require("../zjsunit/test"); const {run_test} = require("../zjsunit/test");
const $ = require("../zjsunit/zjquery"); const $ = require("../zjsunit/zjquery");
mock_esm("../../static/js/recent_topics_util", { mock_esm("../../web/src/recent_topics_util", {
is_visible: () => false, is_visible: () => false,
}); });
const noop = () => {}; const noop = () => {};
// Mocking and stubbing things // Mocking and stubbing things
set_global("document", "document-stub"); set_global("document", "document-stub");
const message_lists = mock_esm("../../static/js/message_lists"); const message_lists = mock_esm("../../web/src/message_lists");
function MessageListView() { function MessageListView() {
return { return {
maybe_rerender: noop, maybe_rerender: noop,
@ -21,7 +21,7 @@ function MessageListView() {
prepend: noop, prepend: noop,
}; };
} }
mock_esm("../../static/js/message_list_view", { mock_esm("../../web/src/message_list_view", {
MessageListView, MessageListView,
}); });
// Code we're actually using/testing // Code we're actually using/testing

View File

@ -6,8 +6,8 @@ const {mock_esm, zrequire} = require("../zjsunit/namespace");
const {run_test} = require("../zjsunit/test"); const {run_test} = require("../zjsunit/test");
const $ = require("../zjsunit/zjquery"); const $ = require("../zjsunit/zjquery");
const compose_actions = mock_esm("../../static/js/compose_actions"); const compose_actions = mock_esm("../../web/src/compose_actions");
const input_pill = mock_esm("../../static/js/input_pill"); const input_pill = mock_esm("../../web/src/input_pill");
const people = zrequire("people"); const people = zrequire("people");
const compose_pm_pill = zrequire("compose_pm_pill"); const compose_pm_pill = zrequire("compose_pm_pill");

View File

@ -5,7 +5,7 @@ const {strict: assert} = require("assert");
const {mock_esm, zrequire} = require("../zjsunit/namespace"); const {mock_esm, zrequire} = require("../zjsunit/namespace");
const {run_test} = require("../zjsunit/test"); const {run_test} = require("../zjsunit/test");
const compose_pm_pill = mock_esm("../../static/js/compose_pm_pill"); const compose_pm_pill = mock_esm("../../web/src/compose_pm_pill");
const compose_state = zrequire("compose_state"); const compose_state = zrequire("compose_state");

View File

@ -13,15 +13,15 @@ const noop = () => {};
set_global("navigator", {}); set_global("navigator", {});
mock_esm("../../static/js/message_lists", { mock_esm("../../web/src/message_lists", {
current: {}, current: {},
}); });
const compose_ui = zrequire("compose_ui"); const compose_ui = zrequire("compose_ui");
const people = zrequire("people"); const people = zrequire("people");
const user_status = zrequire("user_status"); const user_status = zrequire("user_status");
const hash_util = mock_esm("../../static/js/hash_util"); const hash_util = mock_esm("../../web/src/hash_util");
const channel = mock_esm("../../static/js/channel"); const channel = mock_esm("../../web/src/channel");
const compose_actions = zrequire("compose_actions"); const compose_actions = zrequire("compose_actions");
const message_lists = zrequire("message_lists"); const message_lists = zrequire("message_lists");
const text_field_edit = mock_esm("text-field-edit"); const text_field_edit = mock_esm("text-field-edit");

View File

@ -11,8 +11,8 @@ const {page_params} = require("../zjsunit/zpage_params");
const {mock_banners} = require("./lib/compose_banner"); const {mock_banners} = require("./lib/compose_banner");
const channel = mock_esm("../../static/js/channel"); const channel = mock_esm("../../web/src/channel");
const compose_actions = mock_esm("../../static/js/compose_actions"); const compose_actions = mock_esm("../../web/src/compose_actions");
const compose_banner = zrequire("compose_banner"); const compose_banner = zrequire("compose_banner");
const compose_pm_pill = zrequire("compose_pm_pill"); const compose_pm_pill = zrequire("compose_pm_pill");
@ -20,9 +20,9 @@ const compose_state = zrequire("compose_state");
const compose_validate = zrequire("compose_validate"); const compose_validate = zrequire("compose_validate");
const peer_data = zrequire("peer_data"); const peer_data = zrequire("peer_data");
const people = zrequire("people"); const people = zrequire("people");
const resolved_topic = zrequire("../shared/js/resolved_topic"); const resolved_topic = zrequire("../shared/src/resolved_topic");
const settings_config = zrequire("settings_config"); const settings_config = zrequire("settings_config");
const settings_data = mock_esm("../../static/js/settings_data"); const settings_data = mock_esm("../../web/src/settings_data");
const stream_data = zrequire("stream_data"); const stream_data = zrequire("stream_data");
const me = { const me = {

View File

@ -9,10 +9,10 @@ const {page_params} = require("../zjsunit/zpage_params");
const events = require("./lib/events"); const events = require("./lib/events");
const channel = mock_esm("../../static/js/channel"); const channel = mock_esm("../../web/src/channel");
const compose_ui = mock_esm("../../static/js/compose_ui"); const compose_ui = mock_esm("../../web/src/compose_ui");
const upload = mock_esm("../../static/js/upload"); const upload = mock_esm("../../web/src/upload");
mock_esm("../../static/js/resize", { mock_esm("../../web/src/resize", {
watch_manual_resize() {}, watch_manual_resize() {},
}); });
set_global("document", { set_global("document", {

View File

@ -9,20 +9,20 @@ const {user_settings} = require("../zjsunit/zpage_params");
const noop = () => {}; const noop = () => {};
const compose = mock_esm("../../static/js/compose", { const compose = mock_esm("../../web/src/compose", {
finish: noop, finish: noop,
}); });
const compose_validate = mock_esm("../../static/js/compose_validate", { const compose_validate = mock_esm("../../web/src/compose_validate", {
warn_for_text_overflow_when_tries_to_send: () => true, warn_for_text_overflow_when_tries_to_send: () => true,
}); });
const input_pill = mock_esm("../../static/js/input_pill"); const input_pill = mock_esm("../../web/src/input_pill");
const message_user_ids = mock_esm("../../static/js/message_user_ids", { const message_user_ids = mock_esm("../../web/src/message_user_ids", {
user_ids: () => [], user_ids: () => [],
}); });
const stream_topic_history = mock_esm("../../static/js/stream_topic_history", { const stream_topic_history = mock_esm("../../web/src/stream_topic_history", {
stream_has_topics: () => false, stream_has_topics: () => false,
}); });
const stream_topic_history_util = mock_esm("../../static/js/stream_topic_history_util"); const stream_topic_history_util = mock_esm("../../web/src/stream_topic_history_util");
let autosize_called; let autosize_called;
@ -34,7 +34,7 @@ set_global("setTimeout", (f, time) => {
}); });
set_global("document", "document-stub"); set_global("document", "document-stub");
const typeahead = zrequire("../shared/js/typeahead"); const typeahead = zrequire("../shared/src/typeahead");
const compose_state = zrequire("compose_state"); const compose_state = zrequire("compose_state");
const emoji = zrequire("emoji"); const emoji = zrequire("emoji");
const typeahead_helper = zrequire("typeahead_helper"); const typeahead_helper = zrequire("typeahead_helper");

View File

@ -14,7 +14,7 @@ const {window} = new JSDOM("<!DOCTYPE html><p>Hello world</p>");
const {document} = window; const {document} = window;
const $ = jquery(window); const $ = jquery(window);
const compose_ui = mock_esm("../../static/js/compose_ui"); const compose_ui = mock_esm("../../web/src/compose_ui");
set_global("document", document); set_global("document", document);
const copy_and_paste = zrequire("copy_and_paste"); const copy_and_paste = zrequire("copy_and_paste");

View File

@ -24,64 +24,64 @@ const typing_person1 = events.typing_person1;
set_global("setTimeout", (func) => func()); set_global("setTimeout", (func) => func());
const activity = mock_esm("../../static/js/activity"); const activity = mock_esm("../../web/src/activity");
const alert_words_ui = mock_esm("../../static/js/alert_words_ui"); const alert_words_ui = mock_esm("../../web/src/alert_words_ui");
const attachments_ui = mock_esm("../../static/js/attachments_ui"); const attachments_ui = mock_esm("../../web/src/attachments_ui");
const bot_data = mock_esm("../../static/js/bot_data"); const bot_data = mock_esm("../../web/src/bot_data");
const compose_pm_pill = mock_esm("../../static/js/compose_pm_pill"); const compose_pm_pill = mock_esm("../../web/src/compose_pm_pill");
const composebox_typeahead = mock_esm("../../static/js/composebox_typeahead"); const composebox_typeahead = mock_esm("../../web/src/composebox_typeahead");
const dark_theme = mock_esm("../../static/js/dark_theme"); const dark_theme = mock_esm("../../web/src/dark_theme");
const emoji_picker = mock_esm("../../static/js/emoji_picker"); const emoji_picker = mock_esm("../../web/src/emoji_picker");
const hotspots = mock_esm("../../static/js/hotspots"); const hotspots = mock_esm("../../web/src/hotspots");
const linkifiers = mock_esm("../../static/js/linkifiers"); const linkifiers = mock_esm("../../web/src/linkifiers");
const message_events = mock_esm("../../static/js/message_events"); const message_events = mock_esm("../../web/src/message_events");
const message_lists = mock_esm("../../static/js/message_lists"); const message_lists = mock_esm("../../web/src/message_lists");
const muted_topics_ui = mock_esm("../../static/js/muted_topics_ui"); const muted_topics_ui = mock_esm("../../web/src/muted_topics_ui");
const muted_users_ui = mock_esm("../../static/js/muted_users_ui"); const muted_users_ui = mock_esm("../../web/src/muted_users_ui");
const notifications = mock_esm("../../static/js/notifications"); const notifications = mock_esm("../../web/src/notifications");
const pm_list = mock_esm("../../static/js/pm_list"); const pm_list = mock_esm("../../web/src/pm_list");
const reactions = mock_esm("../../static/js/reactions"); const reactions = mock_esm("../../web/src/reactions");
const realm_icon = mock_esm("../../static/js/realm_icon"); const realm_icon = mock_esm("../../web/src/realm_icon");
const realm_logo = mock_esm("../../static/js/realm_logo"); const realm_logo = mock_esm("../../web/src/realm_logo");
const realm_playground = mock_esm("../../static/js/realm_playground"); const realm_playground = mock_esm("../../web/src/realm_playground");
const reload = mock_esm("../../static/js/reload"); const reload = mock_esm("../../web/src/reload");
const scroll_bar = mock_esm("../../static/js/scroll_bar"); const scroll_bar = mock_esm("../../web/src/scroll_bar");
const settings_account = mock_esm("../../static/js/settings_account"); const settings_account = mock_esm("../../web/src/settings_account");
const settings_bots = mock_esm("../../static/js/settings_bots"); const settings_bots = mock_esm("../../web/src/settings_bots");
const settings_display = mock_esm("../../static/js/settings_display"); const settings_display = mock_esm("../../web/src/settings_display");
const settings_emoji = mock_esm("../../static/js/settings_emoji"); const settings_emoji = mock_esm("../../web/src/settings_emoji");
const settings_exports = mock_esm("../../static/js/settings_exports"); const settings_exports = mock_esm("../../web/src/settings_exports");
const settings_invites = mock_esm("../../static/js/settings_invites"); const settings_invites = mock_esm("../../web/src/settings_invites");
const settings_linkifiers = mock_esm("../../static/js/settings_linkifiers"); const settings_linkifiers = mock_esm("../../web/src/settings_linkifiers");
const settings_playgrounds = mock_esm("../../static/js/settings_playgrounds"); const settings_playgrounds = mock_esm("../../web/src/settings_playgrounds");
const settings_notifications = mock_esm("../../static/js/settings_notifications"); const settings_notifications = mock_esm("../../web/src/settings_notifications");
const settings_org = mock_esm("../../static/js/settings_org"); const settings_org = mock_esm("../../web/src/settings_org");
const settings_profile_fields = mock_esm("../../static/js/settings_profile_fields"); const settings_profile_fields = mock_esm("../../web/src/settings_profile_fields");
const settings_realm_user_settings_defaults = mock_esm( const settings_realm_user_settings_defaults = mock_esm(
"../../static/js/settings_realm_user_settings_defaults", "../../web/src/settings_realm_user_settings_defaults",
); );
const settings_realm_domains = mock_esm("../../static/js/settings_realm_domains"); const settings_realm_domains = mock_esm("../../web/src/settings_realm_domains");
const settings_streams = mock_esm("../../static/js/settings_streams"); const settings_streams = mock_esm("../../web/src/settings_streams");
const settings_user_groups_legacy = mock_esm("../../static/js/settings_user_groups_legacy"); const settings_user_groups_legacy = mock_esm("../../web/src/settings_user_groups_legacy");
const settings_users = mock_esm("../../static/js/settings_users"); const settings_users = mock_esm("../../web/src/settings_users");
const stream_data = mock_esm("../../static/js/stream_data"); const stream_data = mock_esm("../../web/src/stream_data");
const stream_events = mock_esm("../../static/js/stream_events"); const stream_events = mock_esm("../../web/src/stream_events");
const stream_list = mock_esm("../../static/js/stream_list"); const stream_list = mock_esm("../../web/src/stream_list");
const stream_settings_ui = mock_esm("../../static/js/stream_settings_ui"); const stream_settings_ui = mock_esm("../../web/src/stream_settings_ui");
const stream_topic_history = mock_esm("../../static/js/stream_topic_history"); const stream_topic_history = mock_esm("../../web/src/stream_topic_history");
const submessage = mock_esm("../../static/js/submessage"); const submessage = mock_esm("../../web/src/submessage");
mock_esm("../../static/js/top_left_corner", { mock_esm("../../web/src/top_left_corner", {
update_starred_count() {}, update_starred_count() {},
}); });
const typing_events = mock_esm("../../static/js/typing_events"); const typing_events = mock_esm("../../web/src/typing_events");
const ui = mock_esm("../../static/js/ui"); const ui = mock_esm("../../web/src/ui");
const unread_ops = mock_esm("../../static/js/unread_ops"); const unread_ops = mock_esm("../../web/src/unread_ops");
const user_events = mock_esm("../../static/js/user_events"); const user_events = mock_esm("../../web/src/user_events");
const user_groups = mock_esm("../../static/js/user_groups"); const user_groups = mock_esm("../../web/src/user_groups");
const user_group_edit = mock_esm("../../static/js/user_group_edit"); const user_group_edit = mock_esm("../../web/src/user_group_edit");
const overlays = mock_esm("../../static/js/overlays"); const overlays = mock_esm("../../web/src/overlays");
const user_groups_settings_ui = mock_esm("../../static/js/user_groups_settings_ui"); const user_groups_settings_ui = mock_esm("../../web/src/user_groups_settings_ui");
mock_esm("../../static/js/giphy"); mock_esm("../../web/src/giphy");
const electron_bridge = set_global("electron_bridge", {}); const electron_bridge = set_global("electron_bridge", {});
@ -125,7 +125,7 @@ people.add_active_user(test_user);
message_helper.process_new_message(test_message); message_helper.process_new_message(test_message);
const realm_emoji = {}; const realm_emoji = {};
const emoji_codes = zrequire("../generated/emoji/emoji_codes.json"); const emoji_codes = zrequire("../../static/generated/emoji/emoji_codes.json");
emoji.initialize({realm_emoji, emoji_codes}); emoji.initialize({realm_emoji, emoji_codes});

View File

@ -13,15 +13,15 @@ const events = require("./lib/events");
const event_fixtures = events.fixtures; const event_fixtures = events.fixtures;
const test_user = events.test_user; const test_user = events.test_user;
const compose_fade = mock_esm("../../static/js/compose_fade"); const compose_fade = mock_esm("../../web/src/compose_fade");
const message_lists = mock_esm("../../static/js/message_lists"); const message_lists = mock_esm("../../web/src/message_lists");
const narrow_state = mock_esm("../../static/js/narrow_state"); const narrow_state = mock_esm("../../web/src/narrow_state");
const overlays = mock_esm("../../static/js/overlays"); const overlays = mock_esm("../../web/src/overlays");
const settings_org = mock_esm("../../static/js/settings_org"); const settings_org = mock_esm("../../web/src/settings_org");
const settings_streams = mock_esm("../../static/js/settings_streams"); const settings_streams = mock_esm("../../web/src/settings_streams");
const stream_events = mock_esm("../../static/js/stream_events"); const stream_events = mock_esm("../../web/src/stream_events");
const stream_list = mock_esm("../../static/js/stream_list"); const stream_list = mock_esm("../../web/src/stream_list");
const stream_settings_ui = mock_esm("../../static/js/stream_settings_ui"); const stream_settings_ui = mock_esm("../../web/src/stream_settings_ui");
message_lists.current = {}; message_lists.current = {};
const peer_data = zrequire("peer_data"); const peer_data = zrequire("peer_data");

View File

@ -29,10 +29,10 @@ set_global("setTimeout", (f, delay) => {
assert.equal(delay, setTimeout_delay); assert.equal(delay, setTimeout_delay);
f(); f();
}); });
mock_esm("../../static/js/markdown", { mock_esm("../../web/src/markdown", {
apply_markdown: noop, apply_markdown: noop,
}); });
mock_esm("../../static/js/overlays", { mock_esm("../../web/src/overlays", {
open_overlay: noop, open_overlay: noop,
}); });

View File

@ -9,7 +9,7 @@ const blueslip = require("../zjsunit/zblueslip");
const $ = require("../zjsunit/zjquery"); const $ = require("../zjsunit/zjquery");
const noop = () => {}; const noop = () => {};
mock_esm("../../static/js/list_widget", { mock_esm("../../web/src/list_widget", {
create: () => ({init: noop}), create: () => ({init: noop}),
}); });

View File

@ -9,23 +9,23 @@ const {make_stub} = require("../zjsunit/stub");
const {run_test} = require("../zjsunit/test"); const {run_test} = require("../zjsunit/test");
const {page_params} = require("../zjsunit/zpage_params"); const {page_params} = require("../zjsunit/zpage_params");
const markdown = mock_esm("../../static/js/markdown"); const markdown = mock_esm("../../web/src/markdown");
const message_lists = mock_esm("../../static/js/message_lists"); const message_lists = mock_esm("../../web/src/message_lists");
const notifications = mock_esm("../../static/js/notifications"); const notifications = mock_esm("../../web/src/notifications");
let disparities = []; let disparities = [];
mock_esm("../../static/js/ui", { mock_esm("../../web/src/ui", {
show_failed_message_success() {}, show_failed_message_success() {},
}); });
mock_esm("../../static/js/sent_messages", { mock_esm("../../web/src/sent_messages", {
mark_disparity(local_id) { mark_disparity(local_id) {
disparities.push(local_id); disparities.push(local_id);
}, },
}); });
const message_store = mock_esm("../../static/js/message_store", { const message_store = mock_esm("../../web/src/message_store", {
get: () => ({failed_request: true}), get: () => ({failed_request: true}),
update_booleans() {}, update_booleans() {},

View File

@ -5,7 +5,7 @@ const {strict: assert} = require("assert");
const {zrequire} = require("../zjsunit/namespace"); const {zrequire} = require("../zjsunit/namespace");
const {run_test} = require("../zjsunit/test"); const {run_test} = require("../zjsunit/test");
const emoji_codes = zrequire("../generated/emoji/emoji_codes.json"); const emoji_codes = zrequire("../../static/generated/emoji/emoji_codes.json");
const events = require("./lib/events"); const events = require("./lib/events");

View File

@ -10,7 +10,7 @@ const {run_test} = require("../zjsunit/test");
const emoji = zrequire("emoji"); const emoji = zrequire("emoji");
const emoji_picker = zrequire("emoji_picker"); const emoji_picker = zrequire("emoji_picker");
const emoji_codes = zrequire("../generated/emoji/emoji_codes.json"); const emoji_codes = zrequire("../../static/generated/emoji/emoji_codes.json");
run_test("initialize", () => { run_test("initialize", () => {
emoji.initialize({ emoji.initialize({

View File

@ -7,7 +7,7 @@ const {run_test} = require("../zjsunit/test");
const $ = require("../zjsunit/zjquery"); const $ = require("../zjsunit/zjquery");
const event_status = zrequire("billing/event_status"); const event_status = zrequire("billing/event_status");
const helpers = mock_esm("../../static/js/billing/helpers"); const helpers = mock_esm("../../web/src/billing/helpers");
run_test("initialize_retry_with_another_card_link_click_handler", ({override}) => { run_test("initialize_retry_with_another_card_link_click_handler", ({override}) => {
override(helpers, "create_ajax_request", (url, form_name, ignored_inputs, method, callback) => { override(helpers, "create_ajax_request", (url, form_name, ignored_inputs, method, callback) => {

View File

@ -11,7 +11,7 @@ const {page_params} = require("../zjsunit/zpage_params");
// narrows more broadly, but first let's test out a core piece of // narrows more broadly, but first let's test out a core piece of
// code that makes things work. // code that makes things work.
const {Filter} = zrequire("../js/filter"); const {Filter} = zrequire("../src/filter");
const stream_data = zrequire("stream_data"); const stream_data = zrequire("stream_data");
// This is the first time we have to deal with page_params. // This is the first time we have to deal with page_params.

View File

@ -55,10 +55,10 @@ const {run_test} = require("../zjsunit/test");
*/ */
// We are going to use mock versions of some of our libraries. // We are going to use mock versions of some of our libraries.
const activity = mock_esm("../../static/js/activity"); const activity = mock_esm("../../web/src/activity");
const message_live_update = mock_esm("../../static/js/message_live_update"); const message_live_update = mock_esm("../../web/src/message_live_update");
const pm_list = mock_esm("../../static/js/pm_list"); const pm_list = mock_esm("../../web/src/pm_list");
const settings_users = mock_esm("../../static/js/settings_users"); const settings_users = mock_esm("../../web/src/settings_users");
// Use real versions of these modules. // Use real versions of these modules.
const people = zrequire("people"); const people = zrequire("people");

View File

@ -20,15 +20,15 @@ const {run_test} = require("../zjsunit/test");
// First we tell the compiler to skip certain modules and just // First we tell the compiler to skip certain modules and just
// replace them with {}. // replace them with {}.
const huddle_data = mock_esm("../../static/js/huddle_data"); const huddle_data = mock_esm("../../web/src/huddle_data");
const message_lists = mock_esm("../../static/js/message_lists"); const message_lists = mock_esm("../../web/src/message_lists");
const message_util = mock_esm("../../static/js/message_util"); const message_util = mock_esm("../../web/src/message_util");
const notifications = mock_esm("../../static/js/notifications"); const notifications = mock_esm("../../web/src/notifications");
const pm_list = mock_esm("../../static/js/pm_list"); const pm_list = mock_esm("../../web/src/pm_list");
const recent_topics_data = mock_esm("../../static/js/recent_topics_data"); const recent_topics_data = mock_esm("../../web/src/recent_topics_data");
const stream_list = mock_esm("../../static/js/stream_list"); const stream_list = mock_esm("../../web/src/stream_list");
const unread_ops = mock_esm("../../static/js/unread_ops"); const unread_ops = mock_esm("../../web/src/unread_ops");
const unread_ui = mock_esm("../../static/js/unread_ui"); const unread_ui = mock_esm("../../web/src/unread_ui");
message_lists.home = {}; message_lists.home = {};

View File

@ -49,11 +49,11 @@ const {run_test} = require("../zjsunit/test");
value.) value.)
*/ */
const channel = mock_esm("../../static/js/channel"); const channel = mock_esm("../../web/src/channel");
const message_lists = mock_esm("../../static/js/message_lists"); const message_lists = mock_esm("../../web/src/message_lists");
const message_viewport = mock_esm("../../static/js/message_viewport"); const message_viewport = mock_esm("../../web/src/message_viewport");
const notifications = mock_esm("../../static/js/notifications"); const notifications = mock_esm("../../web/src/notifications");
const unread_ui = mock_esm("../../static/js/unread_ui"); const unread_ui = mock_esm("../../web/src/unread_ui");
message_lists.current = {}; message_lists.current = {};
message_lists.home = {}; message_lists.home = {};

View File

@ -90,7 +90,7 @@ run_test("typing_events.render_notifications_for_narrow", ({override, mock_templ
const two_typing_users_rendered_html = "Two typing users rendered html stub"; const two_typing_users_rendered_html = "Two typing users rendered html stub";
// As you can see below, the first argument of mock_template takes // As you can see below, the first argument of mock_template takes
// the relative path of the template we want to mock w.r.t static/templates/ // the relative path of the template we want to mock w.r.t web/templates/
// //
// The second argument takes a boolean determining whether to render html. // The second argument takes a boolean determining whether to render html.
// We mostly set this to `false` and recommend you avoid setting this to `true` // We mostly set this to `false` and recommend you avoid setting this to `true`

View File

@ -5,7 +5,7 @@ const {strict: assert} = require("assert");
const {zrequire} = require("../zjsunit/namespace"); const {zrequire} = require("../zjsunit/namespace");
const {run_test} = require("../zjsunit/test"); const {run_test} = require("../zjsunit/test");
const fenced_code = zrequire("../shared/js/fenced_code"); const fenced_code = zrequire("../shared/src/fenced_code");
// Check the default behavior of fenced code blocks // Check the default behavior of fenced code blocks
// works properly before Markdown is initialized. // works properly before Markdown is initialized.

View File

@ -5,7 +5,7 @@ const {strict: assert} = require("assert");
const {mock_esm, zrequire} = require("../zjsunit/namespace"); const {mock_esm, zrequire} = require("../zjsunit/namespace");
const {run_test} = require("../zjsunit/test"); const {run_test} = require("../zjsunit/test");
mock_esm("../../static/js/message_scroll", { mock_esm("../../web/src/message_scroll", {
hide_loading_older() {}, hide_loading_older() {},
show_loading_older() {}, show_loading_older() {},

View File

@ -10,12 +10,12 @@ const blueslip = require("../zjsunit/zblueslip");
const $ = require("../zjsunit/zjquery"); const $ = require("../zjsunit/zjquery");
const {page_params} = require("../zjsunit/zpage_params"); const {page_params} = require("../zjsunit/zpage_params");
const message_store = mock_esm("../../static/js/message_store"); const message_store = mock_esm("../../web/src/message_store");
const resolved_topic = zrequire("../shared/js/resolved_topic"); const resolved_topic = zrequire("../shared/src/resolved_topic");
const stream_data = zrequire("stream_data"); const stream_data = zrequire("stream_data");
const people = zrequire("people"); const people = zrequire("people");
const {Filter} = zrequire("../js/filter"); const {Filter} = zrequire("../src/filter");
const me = { const me = {
email: "me@example.com", email: "me@example.com",

View File

@ -11,24 +11,24 @@ const {user_settings} = require("../zjsunit/zpage_params");
let $window_stub; let $window_stub;
set_global("to_$", () => $window_stub); set_global("to_$", () => $window_stub);
mock_esm("../../static/js/search", { mock_esm("../../web/src/search", {
update_button_visibility() {}, update_button_visibility() {},
}); });
set_global("document", "document-stub"); set_global("document", "document-stub");
const history = set_global("history", {}); const history = set_global("history", {});
const admin = mock_esm("../../static/js/admin"); const admin = mock_esm("../../web/src/admin");
const drafts = mock_esm("../../static/js/drafts"); const drafts = mock_esm("../../web/src/drafts");
const info_overlay = mock_esm("../../static/js/info_overlay"); const info_overlay = mock_esm("../../web/src/info_overlay");
const message_viewport = mock_esm("../../static/js/message_viewport"); const message_viewport = mock_esm("../../web/src/message_viewport");
const narrow = mock_esm("../../static/js/narrow"); const narrow = mock_esm("../../web/src/narrow");
const overlays = mock_esm("../../static/js/overlays"); const overlays = mock_esm("../../web/src/overlays");
const recent_topics_ui = mock_esm("../../static/js/recent_topics_ui"); const recent_topics_ui = mock_esm("../../web/src/recent_topics_ui");
const settings = mock_esm("../../static/js/settings"); const settings = mock_esm("../../web/src/settings");
const stream_settings_ui = mock_esm("../../static/js/stream_settings_ui"); const stream_settings_ui = mock_esm("../../web/src/stream_settings_ui");
const ui_util = mock_esm("../../static/js/ui_util"); const ui_util = mock_esm("../../web/src/ui_util");
const ui_report = mock_esm("../../static/js/ui_report"); const ui_report = mock_esm("../../web/src/ui_report");
mock_esm("../../static/js/top_left_corner", { mock_esm("../../web/src/top_left_corner", {
handle_narrow_deactivated() {}, handle_narrow_deactivated() {},
}); });
set_global("favicon", {}); set_global("favicon", {});

View File

@ -31,24 +31,24 @@ set_global("navigator", {
// jQuery stuff should go away if we make an initialize() method. // jQuery stuff should go away if we make an initialize() method.
set_global("document", "document-stub"); set_global("document", "document-stub");
const browser_history = mock_esm("../../static/js/browser_history"); const browser_history = mock_esm("../../web/src/browser_history");
const compose_actions = mock_esm("../../static/js/compose_actions"); const compose_actions = mock_esm("../../web/src/compose_actions");
const condense = mock_esm("../../static/js/condense"); const condense = mock_esm("../../web/src/condense");
const drafts = mock_esm("../../static/js/drafts"); const drafts = mock_esm("../../web/src/drafts");
const emoji_picker = mock_esm("../../static/js/emoji_picker", { const emoji_picker = mock_esm("../../web/src/emoji_picker", {
reactions_popped: () => false, reactions_popped: () => false,
}); });
const gear_menu = mock_esm("../../static/js/gear_menu", { const gear_menu = mock_esm("../../web/src/gear_menu", {
is_open: () => false, is_open: () => false,
}); });
const lightbox = mock_esm("../../static/js/lightbox"); const lightbox = mock_esm("../../web/src/lightbox");
const list_util = mock_esm("../../static/js/list_util"); const list_util = mock_esm("../../web/src/list_util");
const message_edit = mock_esm("../../static/js/message_edit"); const message_edit = mock_esm("../../web/src/message_edit");
const message_lists = mock_esm("../../static/js/message_lists"); const message_lists = mock_esm("../../web/src/message_lists");
const muted_topics_ui = mock_esm("../../static/js/muted_topics_ui"); const muted_topics_ui = mock_esm("../../web/src/muted_topics_ui");
const narrow = mock_esm("../../static/js/narrow"); const narrow = mock_esm("../../web/src/narrow");
const navigate = mock_esm("../../static/js/navigate"); const navigate = mock_esm("../../web/src/navigate");
const overlays = mock_esm("../../static/js/overlays", { const overlays = mock_esm("../../web/src/overlays", {
is_active: () => false, is_active: () => false,
settings_open: () => false, settings_open: () => false,
streams_open: () => false, streams_open: () => false,
@ -58,31 +58,31 @@ const overlays = mock_esm("../../static/js/overlays", {
is_modal_open: () => false, is_modal_open: () => false,
is_overlay_or_modal_open: () => overlays.is_modal_open() || overlays.is_active(), is_overlay_or_modal_open: () => overlays.is_modal_open() || overlays.is_active(),
}); });
const popovers = mock_esm("../../static/js/popovers", { const popovers = mock_esm("../../web/src/popovers", {
user_info_manage_menu_popped: () => false, user_info_manage_menu_popped: () => false,
message_info_popped: () => false, message_info_popped: () => false,
user_sidebar_popped: () => false, user_sidebar_popped: () => false,
user_info_popped: () => false, user_info_popped: () => false,
}); });
const popover_menus = mock_esm("../../static/js/popover_menus", { const popover_menus = mock_esm("../../web/src/popover_menus", {
actions_popped: () => false, actions_popped: () => false,
}); });
const reactions = mock_esm("../../static/js/reactions"); const reactions = mock_esm("../../web/src/reactions");
const search = mock_esm("../../static/js/search"); const search = mock_esm("../../web/src/search");
const settings_data = mock_esm("../../static/js/settings_data"); const settings_data = mock_esm("../../web/src/settings_data");
const stream_list = mock_esm("../../static/js/stream_list"); const stream_list = mock_esm("../../web/src/stream_list");
const stream_settings_ui = mock_esm("../../static/js/stream_settings_ui"); const stream_settings_ui = mock_esm("../../web/src/stream_settings_ui");
mock_esm("../../static/js/hotspots", { mock_esm("../../web/src/hotspots", {
is_open: () => false, is_open: () => false,
}); });
mock_esm("../../static/js/recent_topics_util", { mock_esm("../../web/src/recent_topics_util", {
is_visible: () => false, is_visible: () => false,
is_in_focus: () => false, is_in_focus: () => false,
}); });
const stream_popover = mock_esm("../../static/js/stream_popover", { const stream_popover = mock_esm("../../web/src/stream_popover", {
stream_popped: () => false, stream_popped: () => false,
topic_popped: () => false, topic_popped: () => false,
all_messages_popped: () => false, all_messages_popped: () => false,
@ -109,7 +109,7 @@ message_lists.current = {
const activity = zrequire("activity"); const activity = zrequire("activity");
const emoji = zrequire("emoji"); const emoji = zrequire("emoji");
const emoji_codes = zrequire("../generated/emoji/emoji_codes.json"); const emoji_codes = zrequire("../../static/generated/emoji/emoji_codes.json");
const hotkey = zrequire("hotkey"); const hotkey = zrequire("hotkey");
emoji.initialize({ emoji.initialize({

View File

@ -22,13 +22,13 @@ page_params.translation_data = {
// Re-register Zulip extensions so extensions registered previously with // Re-register Zulip extensions so extensions registered previously with
// mocked i18n.ts do not interfere with following tests. // mocked i18n.ts do not interfere with following tests.
require("../../static/js/templates"); require("../../web/src/templates");
// All of our other tests stub out i18n activity; // All of our other tests stub out i18n activity;
// here we do a quick sanity check on the engine itself. // here we do a quick sanity check on the engine itself.
// `i18n.js` initializes FormatJS and is imported by // `i18n.js` initializes FormatJS and is imported by
// `templates.js`. // `templates.js`.
unmock_module("../../static/js/i18n"); unmock_module("../../web/src/i18n");
const {$t, $t_html, get_language_name, get_language_list_columns, initialize} = zrequire("i18n"); const {$t, $t_html, get_language_name, get_language_list_columns, initialize} = zrequire("i18n");
run_test("$t", () => { run_test("$t", () => {
@ -89,7 +89,7 @@ run_test("t_tag", ({mock_template}) => {
assert.ok(html.indexOf("Citer et répondre ou transférer") > 0); assert.ok(html.indexOf("Citer et répondre ou transférer") > 0);
}); });
require("../../static/templates/actions_popover_content.hbs")(args); require("../../web/templates/actions_popover_content.hbs")(args);
}); });
run_test("tr_tag", ({mock_template}) => { run_test("tr_tag", ({mock_template}) => {
@ -117,7 +117,7 @@ run_test("tr_tag", ({mock_template}) => {
assert.equal(data, args); assert.equal(data, args);
assert.ok(html.indexOf("Déclencheurs de notification") > 0); assert.ok(html.indexOf("Déclencheurs de notification") > 0);
}); });
require("../../static/templates/settings_tab.hbs")(args); require("../../web/templates/settings_tab.hbs")(args);
}); });
run_test("language_list", () => { run_test("language_list", () => {

View File

@ -12,7 +12,7 @@ set_global("document", {});
const noop = () => {}; const noop = () => {};
const example_img_link = "http://example.com/example.png"; const example_img_link = "http://example.com/example.png";
mock_esm("../../static/js/ui_util", { mock_esm("../../web/src/ui_util", {
place_caret_at_end: noop, place_caret_at_end: noop,
}); });
@ -40,7 +40,7 @@ function pill_html(value, img_src, status_emoji_info) {
opts.status_emoji_info = status_emoji_info; opts.status_emoji_info = status_emoji_info;
} }
return require("../../static/templates/input_pill.hbs")(opts); return require("../../web/templates/input_pill.hbs")(opts);
} }
run_test("basics", ({mock_template}) => { run_test("basics", ({mock_template}) => {

View File

@ -5,7 +5,7 @@ const {strict: assert} = require("assert");
const {zrequire} = require("../zjsunit/namespace"); const {zrequire} = require("../zjsunit/namespace");
const {run_test} = require("../zjsunit/test"); const {run_test} = require("../zjsunit/test");
const internal_url = zrequire("../shared/js/internal_url"); const internal_url = zrequire("../shared/src/internal_url");
run_test("test encodeHashComponent", () => { run_test("test encodeHashComponent", () => {
const decoded = "https://www.zulipexample.com"; const decoded = "https://www.zulipexample.com";

View File

@ -1,6 +1,6 @@
"use strict"; "use strict";
const compose_banner = require("../../../static/js/compose_banner"); const compose_banner = require("../../../web/src/compose_banner");
const $ = require("../../zjsunit/zjquery"); const $ = require("../../zjsunit/zjquery");
exports.mock_banners = () => { exports.mock_banners = () => {

View File

@ -7,18 +7,18 @@ const {run_test} = require("../zjsunit/test");
const $ = require("../zjsunit/zjquery"); const $ = require("../zjsunit/zjquery");
set_global("Image", class Image {}); set_global("Image", class Image {});
mock_esm("../../static/js/overlays", { mock_esm("../../web/src/overlays", {
close_overlay() {}, close_overlay() {},
close_active() {}, close_active() {},
open_overlay() {}, open_overlay() {},
}); });
mock_esm("../../static/js/popovers", { mock_esm("../../web/src/popovers", {
hide_all() {}, hide_all() {},
}); });
const rows = mock_esm("../../static/js/rows"); const rows = mock_esm("../../web/src/rows");
const message_store = mock_esm("../../static/js/message_store"); const message_store = mock_esm("../../web/src/message_store");
const lightbox = zrequire("lightbox"); const lightbox = zrequire("lightbox");

View File

@ -10,7 +10,7 @@ const blueslip = require("../zjsunit/zblueslip");
// The ListWidget library allows you to insert objects // The ListWidget library allows you to insert objects
// that are either jQuery, Element, or just raw HTML // that are either jQuery, Element, or just raw HTML
// strings. We initially test with raw strings. // strings. We initially test with raw strings.
const ui = mock_esm("../../static/js/ui"); const ui = mock_esm("../../web/src/ui");
// We only need very simple jQuery wrappers for when the // We only need very simple jQuery wrappers for when the

View File

@ -30,10 +30,10 @@ user_settings.translate_emoticons = false;
set_global("document", {compatMode: "CSS1Compat"}); set_global("document", {compatMode: "CSS1Compat"});
const emoji = zrequire("emoji"); const emoji = zrequire("emoji");
const emoji_codes = zrequire("../generated/emoji/emoji_codes.json"); const emoji_codes = zrequire("../../static/generated/emoji/emoji_codes.json");
const linkifiers = zrequire("linkifiers"); const linkifiers = zrequire("linkifiers");
const pygments_data = zrequire("../generated/pygments_data.json"); const pygments_data = zrequire("../generated/pygments_data.json");
const fenced_code = zrequire("../shared/js/fenced_code"); const fenced_code = zrequire("../shared/src/fenced_code");
const markdown_config = zrequire("markdown_config"); const markdown_config = zrequire("markdown_config");
const markdown = zrequire("markdown"); const markdown = zrequire("markdown");
const people = zrequire("people"); const people = zrequire("people");

View File

@ -12,7 +12,7 @@ const message_edit = zrequire("message_edit");
const is_content_editable = message_edit.is_content_editable; const is_content_editable = message_edit.is_content_editable;
const settings_data = mock_esm("../../static/js/settings_data"); const settings_data = mock_esm("../../web/src/settings_data");
run_test("is_content_editable", () => { run_test("is_content_editable", () => {
// You can't edit a null message // You can't edit a null message

View File

@ -7,13 +7,13 @@ const {run_test} = require("../zjsunit/test");
const $ = require("../zjsunit/zjquery"); const $ = require("../zjsunit/zjquery");
const {page_params} = require("../zjsunit/zpage_params"); const {page_params} = require("../zjsunit/zpage_params");
const condense = mock_esm("../../static/js/condense"); const condense = mock_esm("../../web/src/condense");
const message_edit = mock_esm("../../static/js/message_edit"); const message_edit = mock_esm("../../web/src/message_edit");
const message_lists = mock_esm("../../static/js/message_lists"); const message_lists = mock_esm("../../web/src/message_lists");
const notifications = mock_esm("../../static/js/notifications"); const notifications = mock_esm("../../web/src/notifications");
const pm_list = mock_esm("../../static/js/pm_list"); const pm_list = mock_esm("../../web/src/pm_list");
const stream_list = mock_esm("../../static/js/stream_list"); const stream_list = mock_esm("../../web/src/stream_list");
const unread_ui = mock_esm("../../static/js/unread_ui"); const unread_ui = mock_esm("../../web/src/unread_ui");
message_lists.current = {}; message_lists.current = {};
message_lists.all_rendered_message_lists = () => [message_lists.home, message_lists.current]; message_lists.all_rendered_message_lists = () => [message_lists.home, message_lists.current];

View File

@ -20,27 +20,27 @@ function MessageListView() {
prepend: noop, prepend: noop,
}; };
} }
mock_esm("../../static/js/message_list_view", { mock_esm("../../web/src/message_list_view", {
MessageListView, MessageListView,
}); });
mock_esm("../../static/js/recent_topics_ui", { mock_esm("../../web/src/recent_topics_ui", {
process_messages: noop, process_messages: noop,
show_loading_indicator: noop, show_loading_indicator: noop,
hide_loading_indicator: noop, hide_loading_indicator: noop,
}); });
mock_esm("../../static/js/ui_report", { mock_esm("../../web/src/ui_report", {
hide_error: noop, hide_error: noop,
}); });
const channel = mock_esm("../../static/js/channel"); const channel = mock_esm("../../web/src/channel");
const message_helper = mock_esm("../../static/js/message_helper"); const message_helper = mock_esm("../../web/src/message_helper");
const message_lists = mock_esm("../../static/js/message_lists"); const message_lists = mock_esm("../../web/src/message_lists");
const message_util = mock_esm("../../static/js/message_util"); const message_util = mock_esm("../../web/src/message_util");
const stream_list = mock_esm("../../static/js/stream_list", { const stream_list = mock_esm("../../web/src/stream_list", {
maybe_scroll_narrow_into_view() {}, maybe_scroll_narrow_into_view() {},
}); });
mock_esm("../../static/js/message_scroll", { mock_esm("../../web/src/message_scroll", {
show_loading_older: noop, show_loading_older: noop,
hide_loading_older: noop, hide_loading_older: noop,
show_loading_newer: noop, show_loading_newer: noop,
@ -52,7 +52,7 @@ set_global("document", "document-stub");
const message_fetch = zrequire("message_fetch"); const message_fetch = zrequire("message_fetch");
const {all_messages_data} = zrequire("all_messages_data"); const {all_messages_data} = zrequire("all_messages_data");
const {Filter} = zrequire("../js/filter"); const {Filter} = zrequire("../src/filter");
const message_list = zrequire("message_list"); const message_list = zrequire("message_list");
const people = zrequire("people"); const people = zrequire("people");

View File

@ -5,10 +5,10 @@ const {strict: assert} = require("assert");
const {mock_esm, set_global, with_overrides, zrequire} = require("../zjsunit/namespace"); const {mock_esm, set_global, with_overrides, zrequire} = require("../zjsunit/namespace");
const {run_test} = require("../zjsunit/test"); const {run_test} = require("../zjsunit/test");
const channel = mock_esm("../../static/js/channel"); const channel = mock_esm("../../web/src/channel");
const ui = mock_esm("../../static/js/ui"); const ui = mock_esm("../../web/src/ui");
mock_esm("../../static/js/starred_messages", { mock_esm("../../web/src/starred_messages", {
add() {}, add() {},
get_starred_msg_ids: () => [1, 2, 3, 4, 5], get_starred_msg_ids: () => [1, 2, 3, 4, 5],
remove() {}, remove() {},

View File

@ -9,7 +9,7 @@ const blueslip = require("../zjsunit/zblueslip");
const $ = require("../zjsunit/zjquery"); const $ = require("../zjsunit/zjquery");
const {page_params} = require("../zjsunit/zpage_params"); const {page_params} = require("../zjsunit/zpage_params");
// These unit tests for static/js/message_list.js emphasize the model-ish // These unit tests for web/src/message_list.js emphasize the model-ish
// aspects of the MessageList class. We have to stub out a few functions // aspects of the MessageList class. We have to stub out a few functions
// related to views and events to get the tests working. // related to views and events to get the tests working.
@ -23,8 +23,8 @@ set_global("document", {
}, },
}); });
const narrow_state = mock_esm("../../static/js/narrow_state"); const narrow_state = mock_esm("../../web/src/narrow_state");
const stream_data = mock_esm("../../static/js/stream_data"); const stream_data = mock_esm("../../web/src/stream_data");
const {MessageList} = zrequire("message_list"); const {MessageList} = zrequire("message_list");
function MessageListView() { function MessageListView() {
@ -35,7 +35,7 @@ function MessageListView() {
clear_rendering_state: noop, clear_rendering_state: noop,
}; };
} }
mock_esm("../../static/js/message_list_view", { mock_esm("../../web/src/message_list_view", {
MessageListView, MessageListView,
}); });
const {Filter} = zrequire("filter"); const {Filter} = zrequire("filter");

View File

@ -8,7 +8,7 @@ const blueslip = require("../zjsunit/zblueslip");
const user_topics = zrequire("user_topics"); const user_topics = zrequire("user_topics");
const muted_users = zrequire("muted_users"); const muted_users = zrequire("muted_users");
const {MessageListData} = zrequire("../js/message_list_data"); const {MessageListData} = zrequire("../src/message_list_data");
const {Filter} = zrequire("filter"); const {Filter} = zrequire("filter");
function make_msg(msg_id) { function make_msg(msg_id) {

View File

@ -13,7 +13,7 @@ set_global("document", "document-stub");
const noop = () => {}; const noop = () => {};
// timerender calls setInterval when imported // timerender calls setInterval when imported
mock_esm("../../static/js/timerender", { mock_esm("../../web/src/timerender", {
render_date(time) { render_date(time) {
return [{outerHTML: String(time.getTime())}]; return [{outerHTML: String(time.getTime())}];
}, },
@ -22,7 +22,7 @@ mock_esm("../../static/js/timerender", {
}, },
}); });
mock_esm("../../static/js/rows", { mock_esm("../../web/src/rows", {
get_table() { get_table() {
return { return {
children() { children() {
@ -34,14 +34,14 @@ mock_esm("../../static/js/rows", {
}, },
}); });
mock_esm("../../static/js/people", { mock_esm("../../web/src/people", {
sender_is_bot: () => false, sender_is_bot: () => false,
sender_is_guest: () => false, sender_is_guest: () => false,
small_avatar_url: () => "fake/small/avatar/url", small_avatar_url: () => "fake/small/avatar/url",
}); });
const {Filter} = zrequire("../js/filter"); const {Filter} = zrequire("../src/filter");
const {MessageListView} = zrequire("../js/message_list_view"); const {MessageListView} = zrequire("../src/message_list_view");
const message_list = zrequire("message_list"); const message_list = zrequire("message_list");
const muted_users = zrequire("muted_users"); const muted_users = zrequire("muted_users");

View File

@ -9,11 +9,11 @@ const {page_params} = require("../zjsunit/zpage_params");
const noop = () => {}; const noop = () => {};
mock_esm("../../static/js/stream_topic_history", { mock_esm("../../web/src/stream_topic_history", {
add_message: noop, add_message: noop,
}); });
mock_esm("../../static/js/recent_senders", { mock_esm("../../web/src/recent_senders", {
process_stream_message: noop, process_stream_message: noop,
process_private_message: noop, process_private_message: noop,
}); });

View File

@ -14,15 +14,15 @@ const narrow_banner = zrequire("narrow_banner");
const narrow_state = zrequire("narrow_state"); const narrow_state = zrequire("narrow_state");
const people = zrequire("people"); const people = zrequire("people");
const stream_data = zrequire("stream_data"); const stream_data = zrequire("stream_data");
const {Filter} = zrequire("../js/filter"); const {Filter} = zrequire("../src/filter");
const narrow = zrequire("narrow"); const narrow = zrequire("narrow");
const settings_config = zrequire("settings_config"); const settings_config = zrequire("settings_config");
const compose_pm_pill = mock_esm("../../static/js/compose_pm_pill"); const compose_pm_pill = mock_esm("../../web/src/compose_pm_pill");
mock_esm("../../static/js/spectators", { mock_esm("../../web/src/spectators", {
login_to_access() {}, login_to_access() {},
}); });
const recent_topics_util = mock_esm("../../static/js/recent_topics_util", { const recent_topics_util = mock_esm("../../web/src/recent_topics_util", {
is_visible() {}, is_visible() {},
}); });
@ -32,7 +32,7 @@ function empty_narrow_html(title, html, search_data) {
html, html,
search_data, search_data,
}; };
return require("../../static/templates/empty_feed_notice.hbs")(opts); return require("../../web/templates/empty_feed_notice.hbs")(opts);
} }
function set_filter(operators) { function set_filter(operators) {

View File

@ -6,34 +6,34 @@ const {mock_esm, set_global, zrequire} = require("../zjsunit/namespace");
const {run_test} = require("../zjsunit/test"); const {run_test} = require("../zjsunit/test");
const $ = require("../zjsunit/zjquery"); const $ = require("../zjsunit/zjquery");
mock_esm("../../static/js/resize", { mock_esm("../../web/src/resize", {
resize_stream_filters_container() {}, resize_stream_filters_container() {},
}); });
const all_messages_data = mock_esm("../../static/js/all_messages_data"); const all_messages_data = mock_esm("../../web/src/all_messages_data");
const channel = mock_esm("../../static/js/channel"); const channel = mock_esm("../../web/src/channel");
const compose_actions = mock_esm("../../static/js/compose_actions"); const compose_actions = mock_esm("../../web/src/compose_actions");
const compose_banner = mock_esm("../../static/js/compose_banner"); const compose_banner = mock_esm("../../web/src/compose_banner");
const compose_closed_ui = mock_esm("../../static/js/compose_closed_ui"); const compose_closed_ui = mock_esm("../../web/src/compose_closed_ui");
const hashchange = mock_esm("../../static/js/hashchange"); const hashchange = mock_esm("../../web/src/hashchange");
const message_fetch = mock_esm("../../static/js/message_fetch"); const message_fetch = mock_esm("../../web/src/message_fetch");
const message_list = mock_esm("../../static/js/message_list"); const message_list = mock_esm("../../web/src/message_list");
const message_lists = mock_esm("../../static/js/message_lists", { const message_lists = mock_esm("../../web/src/message_lists", {
home: {}, home: {},
current: {}, current: {},
set_current(msg_list) { set_current(msg_list) {
message_lists.current = msg_list; message_lists.current = msg_list;
}, },
}); });
const message_scroll = mock_esm("../../static/js/message_scroll"); const message_scroll = mock_esm("../../web/src/message_scroll");
const message_view_header = mock_esm("../../static/js/message_view_header"); const message_view_header = mock_esm("../../web/src/message_view_header");
const notifications = mock_esm("../../static/js/notifications"); const notifications = mock_esm("../../web/src/notifications");
const search = mock_esm("../../static/js/search"); const search = mock_esm("../../web/src/search");
const stream_list = mock_esm("../../static/js/stream_list"); const stream_list = mock_esm("../../web/src/stream_list");
const top_left_corner = mock_esm("../../static/js/top_left_corner"); const top_left_corner = mock_esm("../../web/src/top_left_corner");
const typing_events = mock_esm("../../static/js/typing_events"); const typing_events = mock_esm("../../web/src/typing_events");
const unread_ops = mock_esm("../../static/js/unread_ops"); const unread_ops = mock_esm("../../web/src/unread_ops");
mock_esm("../../static/js/recent_topics_util", { mock_esm("../../web/src/recent_topics_util", {
is_visible() {}, is_visible() {},
}); });
@ -45,7 +45,7 @@ set_global("setTimeout", (f, t) => {
f(); f();
}); });
mock_esm("../../static/js/user_topics", { mock_esm("../../web/src/user_topics", {
is_topic_muted: () => false, is_topic_muted: () => false,
}); });

View File

@ -5,13 +5,13 @@ const {strict: assert} = require("assert");
const {mock_esm, zrequire} = require("../zjsunit/namespace"); const {mock_esm, zrequire} = require("../zjsunit/namespace");
const {run_test} = require("../zjsunit/test"); const {run_test} = require("../zjsunit/test");
const all_messages_data = mock_esm("../../static/js/all_messages_data"); const all_messages_data = mock_esm("../../web/src/all_messages_data");
const {Filter} = zrequire("../js/filter"); const {Filter} = zrequire("../src/filter");
const {MessageListData} = zrequire("../js/message_list_data"); const {MessageListData} = zrequire("../src/message_list_data");
const narrow_state = zrequire("narrow_state"); const narrow_state = zrequire("narrow_state");
const narrow = zrequire("narrow"); const narrow = zrequire("narrow");
const resolved_topic = zrequire("../shared/js/resolved_topic"); const resolved_topic = zrequire("../shared/src/resolved_topic");
function test_with(fixture) { function test_with(fixture) {
const filter = new Filter(fixture.filter_terms); const filter = new Filter(fixture.filter_terms);

View File

@ -6,7 +6,7 @@ const {zrequire} = require("../zjsunit/namespace");
const {run_test} = require("../zjsunit/test"); const {run_test} = require("../zjsunit/test");
const people = zrequire("people"); const people = zrequire("people");
const {Filter} = zrequire("../js/filter"); const {Filter} = zrequire("../src/filter");
const stream_data = zrequire("stream_data"); const stream_data = zrequire("stream_data");
const narrow_state = zrequire("narrow_state"); const narrow_state = zrequire("narrow_state");

View File

@ -6,11 +6,11 @@ const {mock_esm, zrequire} = require("../zjsunit/namespace");
const {run_test} = require("../zjsunit/test"); const {run_test} = require("../zjsunit/test");
const blueslip = require("../zjsunit/zblueslip"); const blueslip = require("../zjsunit/zblueslip");
mock_esm("../../static/js/user_topics", { mock_esm("../../web/src/user_topics", {
is_topic_muted: () => false, is_topic_muted: () => false,
}); });
const {Filter} = zrequire("../js/filter"); const {Filter} = zrequire("../src/filter");
const message_store = zrequire("message_store"); const message_store = zrequire("message_store");
const people = zrequire("people"); const people = zrequire("people");
const stream_data = zrequire("stream_data"); const stream_data = zrequire("stream_data");

View File

@ -12,7 +12,7 @@ const {run_test} = require("../zjsunit/test");
const blueslip = require("../zjsunit/zblueslip"); const blueslip = require("../zjsunit/zblueslip");
const {page_params, user_settings} = require("../zjsunit/zpage_params"); const {page_params, user_settings} = require("../zjsunit/zpage_params");
const message_user_ids = mock_esm("../../static/js/message_user_ids"); const message_user_ids = mock_esm("../../web/src/message_user_ids");
const muted_users = zrequire("muted_users"); const muted_users = zrequire("muted_users");
const people = zrequire("people"); const people = zrequire("people");

View File

@ -6,7 +6,7 @@ const {mock_esm, zrequire} = require("../zjsunit/namespace");
const {run_test} = require("../zjsunit/test"); const {run_test} = require("../zjsunit/test");
const blueslip = require("../zjsunit/zblueslip"); const blueslip = require("../zjsunit/zblueslip");
const reload_state = mock_esm("../../static/js/reload_state", { const reload_state = mock_esm("../../web/src/reload_state", {
is_in_progress: () => false, is_in_progress: () => false,
}); });

View File

@ -23,7 +23,7 @@ const $fake_rendered_person = $.create("fake-rendered-person");
const $fake_rendered_stream = $.create("fake-rendered-stream"); const $fake_rendered_stream = $.create("fake-rendered-stream");
const $fake_rendered_group = $.create("fake-rendered-group"); const $fake_rendered_group = $.create("fake-rendered-group");
mock_esm("../../static/js/typeahead_helper", { mock_esm("../../web/src/typeahead_helper", {
render_person() { render_person() {
return $fake_rendered_person; return $fake_rendered_person;
}, },

View File

@ -5,9 +5,9 @@ const {strict: assert} = require("assert");
const {mock_esm, zrequire} = require("../zjsunit/namespace"); const {mock_esm, zrequire} = require("../zjsunit/namespace");
const {run_test} = require("../zjsunit/test"); const {run_test} = require("../zjsunit/test");
const unread = mock_esm("../../static/js/unread"); const unread = mock_esm("../../web/src/unread");
mock_esm("../../static/js/user_status", { mock_esm("../../web/src/user_status", {
get_status_emoji: () => ({ get_status_emoji: () => ({
emoji_code: 20, emoji_code: 20,
}), }),

View File

@ -7,7 +7,7 @@ const {run_test} = require("../zjsunit/test");
const blueslip = require("../zjsunit/zblueslip"); const blueslip = require("../zjsunit/zblueslip");
const $ = require("../zjsunit/zjquery"); const $ = require("../zjsunit/zjquery");
const {PollData} = zrequire("../../static/shared/js/poll_data"); const {PollData} = zrequire("../../web/shared/src/poll_data");
const poll_widget = zrequire("poll_widget"); const poll_widget = zrequire("poll_widget");

View File

@ -15,21 +15,21 @@ class Clipboard {
} }
mock_cjs("clipboard", Clipboard); mock_cjs("clipboard", Clipboard);
const rows = mock_esm("../../static/js/rows"); const rows = mock_esm("../../web/src/rows");
mock_esm("../../static/js/emoji_picker", { mock_esm("../../web/src/emoji_picker", {
hide_emoji_popover: noop, hide_emoji_popover: noop,
}); });
mock_esm("../../static/js/giphy", { mock_esm("../../web/src/giphy", {
hide_giphy_popover: noop, hide_giphy_popover: noop,
}); });
const message_lists = mock_esm("../../static/js/message_lists", { const message_lists = mock_esm("../../web/src/message_lists", {
current: { current: {
view: { view: {
message_containers: {}, message_containers: {},
}, },
}, },
}); });
mock_esm("../../static/js/stream_popover", { mock_esm("../../web/src/stream_popover", {
hide_stream_popover: noop, hide_stream_popover: noop,
hide_topic_popover: noop, hide_topic_popover: noop,
hide_all_messages_popover: noop, hide_all_messages_popover: noop,

View File

@ -7,7 +7,7 @@ const {run_test} = require("../zjsunit/test");
const blueslip = require("../zjsunit/zblueslip"); const blueslip = require("../zjsunit/zblueslip");
const {page_params, user_settings} = require("../zjsunit/zpage_params"); const {page_params, user_settings} = require("../zjsunit/zpage_params");
const reload_state = mock_esm("../../static/js/reload_state", { const reload_state = mock_esm("../../web/src/reload_state", {
is_in_progress: () => false, is_in_progress: () => false,
}); });

View File

@ -38,13 +38,13 @@ const sample_message = {
], ],
}; };
const channel = mock_esm("../../static/js/channel"); const channel = mock_esm("../../web/src/channel");
const emoji_picker = mock_esm("../../static/js/emoji_picker", { const emoji_picker = mock_esm("../../web/src/emoji_picker", {
hide_emoji_popover() {}, hide_emoji_popover() {},
}); });
const message_lists = mock_esm("../../static/js/message_lists"); const message_lists = mock_esm("../../web/src/message_lists");
const message_store = mock_esm("../../static/js/message_store"); const message_store = mock_esm("../../web/src/message_store");
const spectators = mock_esm("../../static/js/spectators", { const spectators = mock_esm("../../web/src/spectators", {
login_to_access() {}, login_to_access() {},
}); });
@ -59,7 +59,7 @@ message_lists.current = {
set_global("document", "document-stub"); set_global("document", "document-stub");
const emoji = zrequire("emoji"); const emoji = zrequire("emoji");
const emoji_codes = zrequire("../generated/emoji/emoji_codes.json"); const emoji_codes = zrequire("../../static/generated/emoji/emoji_codes.json");
const people = zrequire("people"); const people = zrequire("people");
const reactions = zrequire("reactions"); const reactions = zrequire("reactions");

View File

@ -23,10 +23,10 @@ function make_stream_message({stream_id, topic, sender_id}) {
return message; return message;
} }
mock_esm("../../static/js/message_store", { mock_esm("../../web/src/message_store", {
get: (message_id) => messages.get(message_id), get: (message_id) => messages.get(message_id),
}); });
mock_esm("../../static/js/people", { mock_esm("../../web/src/people", {
my_current_user_id: () => 1, my_current_user_id: () => 1,
}); });

View File

@ -39,7 +39,7 @@ const topic10 = "topic-10";
let expected_data_to_replace_in_list_widget; let expected_data_to_replace_in_list_widget;
const ListWidget = mock_esm("../../static/js/list_widget", { const ListWidget = mock_esm("../../web/src/list_widget", {
modifier: noop, modifier: noop,
create(container, mapped_topic_values, opts) { create(container, mapped_topic_values, opts) {
@ -75,25 +75,25 @@ const ListWidget = mock_esm("../../static/js/list_widget", {
}, },
}); });
mock_esm("../../static/js/compose_closed_ui", { mock_esm("../../web/src/compose_closed_ui", {
set_standard_text_for_reply_button: noop, set_standard_text_for_reply_button: noop,
update_buttons_for_recent_topics: noop, update_buttons_for_recent_topics: noop,
}); });
mock_esm("../../static/js/hash_util", { mock_esm("../../web/src/hash_util", {
by_stream_url: test_url, by_stream_url: test_url,
by_stream_topic_url: test_url, by_stream_topic_url: test_url,
by_conversation_and_time_url: test_url, by_conversation_and_time_url: test_url,
}); });
mock_esm("../../static/js/message_list_data", { mock_esm("../../web/src/message_list_data", {
MessageListData: class {}, MessageListData: class {},
}); });
mock_esm("../../static/js/message_store", { mock_esm("../../web/src/message_store", {
get: (msg_id) => messages[msg_id - 1], get: (msg_id) => messages[msg_id - 1],
}); });
mock_esm("../../static/js/message_view_header", { mock_esm("../../web/src/message_view_header", {
render_title_area: noop, render_title_area: noop,
}); });
mock_esm("../../static/js/user_topics", { mock_esm("../../web/src/user_topics", {
is_topic_muted(stream_id, topic) { is_topic_muted(stream_id, topic) {
if (stream_id === stream1 && topic === topic7) { if (stream_id === stream1 && topic === topic7) {
return true; return true;
@ -101,33 +101,33 @@ mock_esm("../../static/js/user_topics", {
return false; return false;
}, },
}); });
const narrow = mock_esm("../../static/js/narrow", { const narrow = mock_esm("../../web/src/narrow", {
update_narrow_title: noop, update_narrow_title: noop,
hide_mark_as_read_turned_off_banner: noop, hide_mark_as_read_turned_off_banner: noop,
handle_middle_pane_transition: noop, handle_middle_pane_transition: noop,
has_shown_message_list_view: true, has_shown_message_list_view: true,
}); });
mock_esm("../../static/js/pm_list", { mock_esm("../../web/src/pm_list", {
update_private_messages: noop, update_private_messages: noop,
handle_narrow_deactivated: noop, handle_narrow_deactivated: noop,
}); });
mock_esm("../../static/js/recent_senders", { mock_esm("../../web/src/recent_senders", {
get_topic_recent_senders: () => [2, 1], get_topic_recent_senders: () => [2, 1],
}); });
mock_esm("../../static/js/stream_data", { mock_esm("../../web/src/stream_data", {
is_muted: () => is_muted: () =>
// We only test via muted topics for now. // We only test via muted topics for now.
// TODO: Make muted streams and test them. // TODO: Make muted streams and test them.
false, false,
}); });
mock_esm("../../static/js/stream_list", { mock_esm("../../web/src/stream_list", {
handle_narrow_deactivated: noop, handle_narrow_deactivated: noop,
}); });
mock_esm("../../static/js/timerender", { mock_esm("../../web/src/timerender", {
last_seen_status_from_date: () => "Just now", last_seen_status_from_date: () => "Just now",
get_full_datetime: () => "date at time", get_full_datetime: () => "date at time",
}); });
mock_esm("../../static/js/sub_store", { mock_esm("../../web/src/sub_store", {
get(stream) { get(stream) {
if (stream === stream5) { if (stream === stream5) {
// No data is available for deactivated streams // No data is available for deactivated streams
@ -142,10 +142,10 @@ mock_esm("../../static/js/sub_store", {
}; };
}, },
}); });
mock_esm("../../static/js/top_left_corner", { mock_esm("../../web/src/top_left_corner", {
narrow_to_recent_topics: noop, narrow_to_recent_topics: noop,
}); });
mock_esm("../../static/js/unread", { mock_esm("../../web/src/unread", {
num_unread_for_topic(stream_id, topic) { num_unread_for_topic(stream_id, topic) {
if (stream_id === 1 && topic === "topic-1") { if (stream_id === 1 && topic === "topic-1") {
return 0; return 0;

View File

@ -17,7 +17,7 @@ class Clipboard {
mock_cjs("clipboard", Clipboard); mock_cjs("clipboard", Clipboard);
const realm_playground = mock_esm("../../static/js/realm_playground"); const realm_playground = mock_esm("../../web/src/realm_playground");
user_settings.emojiset = "apple"; user_settings.emojiset = "apple";
const rm = zrequire("rendered_markdown"); const rm = zrequire("rendered_markdown");

View File

@ -5,7 +5,7 @@ const {strict: assert} = require("assert");
const {zrequire} = require("../zjsunit/namespace"); const {zrequire} = require("../zjsunit/namespace");
const {run_test} = require("../zjsunit/test"); const {run_test} = require("../zjsunit/test");
const resolved_topic = zrequire("../shared/js/resolved_topic"); const resolved_topic = zrequire("../shared/src/resolved_topic");
const topic_name = "asdf"; const topic_name = "asdf";
const resolved_name = "✔ " + topic_name; const resolved_name = "✔ " + topic_name;

View File

@ -5,7 +5,7 @@ const {strict: assert} = require("assert");
const {mock_esm, zrequire} = require("../zjsunit/namespace"); const {mock_esm, zrequire} = require("../zjsunit/namespace");
const {run_test} = require("../zjsunit/test"); const {run_test} = require("../zjsunit/test");
mock_esm("../../static/js/ui", { mock_esm("../../web/src/ui", {
get_scroll_element: (element) => element, get_scroll_element: (element) => element,
}); });

View File

@ -9,24 +9,24 @@ const {page_params} = require("../zjsunit/zpage_params");
const noop = () => {}; const noop = () => {};
const narrow = mock_esm("../../static/js/narrow"); const narrow = mock_esm("../../web/src/narrow");
const narrow_state = mock_esm("../../static/js/narrow_state", { const narrow_state = mock_esm("../../web/src/narrow_state", {
filter: () => false, filter: () => false,
}); });
const search_suggestion = mock_esm("../../static/js/search_suggestion"); const search_suggestion = mock_esm("../../web/src/search_suggestion");
mock_esm("../../static/js/search_pill_widget", { mock_esm("../../web/src/search_pill_widget", {
widget: { widget: {
getByElement: () => true, getByElement: () => true,
}, },
}); });
mock_esm("../../static/js/ui_util", { mock_esm("../../web/src/ui_util", {
place_caret_at_end: noop, place_caret_at_end: noop,
}); });
const search = zrequire("search"); const search = zrequire("search");
const search_pill = zrequire("search_pill"); const search_pill = zrequire("search_pill");
const {Filter} = zrequire("../js/filter"); const {Filter} = zrequire("../src/filter");
function test(label, f) { function test(label, f) {
run_test(label, ({override, mock_template}) => { run_test(label, ({override, mock_template}) => {

Some files were not shown because too many files have changed in this diff Show More