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
/static/generated
/static/third
/static/webpack-bundles
/var/*
!/var/puppeteer
/var/puppeteer/*
!/var/puppeteer/test_credentials.d.ts
/web/generated
/web/third
/zulip-current-venv
/zulip-py3-venv

View File

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

View File

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

View File

@ -155,9 +155,9 @@ jobs:
# Ban check-database-compatibility.py from transitively
# relying on static/generated, because it might not be
# 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
chmod 755 static/generated
chmod 755 static/generated web/generated
- name: Run documentation and api tests
if: ${{ matrix.include_documentation_tests }}

View File

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

View File

@ -51,25 +51,25 @@ Files: static/audio/notification_sounds/zulip.*
Copyright: 2011 Vidsyn
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
License: Expat
Files: static/third/bootstrap/css/bootstrap.css
Files: web/third/bootstrap/css/bootstrap.css
Copyright: 2012 Twitter, Inc
License: Apache-2.0
Comment: The software has been modified.
Files: static/third/bootstrap/js/bootstrap.js
Files: web/third/bootstrap/js/bootstrap.js
Copyright: 2012 Twitter, Inc
License: Apache-2.0
Files: static/third/bootstrap-typeahead/*
Files: web/third/bootstrap-typeahead/*
Copyright: 2012 Twitter, Inc
License: Apache-2.0
Comment: Bootstrap typeahead. The software has been modified.
Files: static/third/bootstrap-tooltip/*
Files: web/third/bootstrap-tooltip/*
Copyright: 2012 Twitter, Inc
License: Apache-2.0
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.
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
License: Expat
Comment: The software has been modified.
Files: static/third/marked/*
Files: web/third/marked/*
Copyright: 2011-2013, Christopher Jeffrey
License: Expat
Files: static/shared/icons/ellipsis-v-solid.svg
Files: web/shared/icons/ellipsis-v-solid.svg
Copyright: 2017 Fonticons, Inc.
License: CC-BY-4.0
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
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.
Copyright: 2015-present Ionic (http://ionic.io/)
License: Expat
@ -118,7 +118,7 @@ Files: tools/check-thirdparty
Copyright: 2020 Kandra Labs, Inc.
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
Copyright: Google, Inc.
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.
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:
```js

View File

@ -75,8 +75,8 @@ the development environment][authentication-dev-server].
- Most changes will take effect automatically. Details:
- If you change CSS files, your changes will appear immediately via
webpack hot module replacement.
- If you change JavaScript code (`static/js`) or Handlebars
templates (`static/templates`), the browser window will be
- If you change JavaScript code (`web/src`) or Handlebars
templates (`web/templates`), the browser window will be
reloaded automatically.
- For Jinja2 backend templates (`templates/*`), you'll need to reload
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
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
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,
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 upstream`: fetch upstream repository
- 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
- `git log`: show commit logs
- `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
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`.
- `static/shared/icons/` Icons placed in this directory are compiled
- `web/shared/icons/` Icons placed in this directory are compiled
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
raw sql queries) is for a different page (/activity), not related to
/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
- 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,
but there is currently still a lot of portico influence.
- analytics/urls.py: Has the URL routes; it's unlikely you will have to

View File

@ -242,7 +242,7 @@ reasoning here.
release tarball.
- **Checked-in packages**. In contrast with Python, we have a few
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
these checked-in versions of dependencies and instead use versions
managed by the npm repositories.
@ -317,7 +317,7 @@ implementation of that tool.
The list of languages supported by our Markdown syntax highlighting
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.
## Modifying provisioning

View File

@ -17,7 +17,7 @@ Some examples are:
stream.)
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
the reason that it's thorny is that it needs to support a lot of
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
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
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
idle (ideally, we'd reload when they're not looking and restore
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.
An important detail in server-initiated reloads is that we

View File

@ -30,7 +30,7 @@ ALL_HOTSPOTS = {
### Step 2: Configure hotspot placement
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 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
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
#hotspot_new_hotspot_name_icon {

View File

@ -2,13 +2,13 @@
## 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
main third-party CSS library.
Zulip uses PostCSS for its CSS files. There are two high-level sections
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.
## Editing Zulip CSS
@ -111,7 +111,7 @@ path('config-error/google', TemplateView.as_view(
For text generated in the frontend, live-rendering HTML from
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
matter, we try to avoid generating HTML directly in JavaScript
wherever possible).
@ -150,13 +150,13 @@ relevant background as well.
### 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
are written in CSS extended by various PostCSS plugins; they are
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
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.
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
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
@ -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
version of third-party libraries.
- 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
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).
- CSS files live under `static/styles`.
- CSS files live under `web/styles`.
- Portico JavaScript ("portico" means for logged-out pages) lives under
`static/js/portico`.
- Custom SVG graphics living under `static/assets/icons` are compiled into
`web/src/portico`.
- Custom SVG graphics living under `web/images/icons` are compiled into
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
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
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
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.
- 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
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
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
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
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
browser console for this purpose. For example, you can access our
`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
stable API and should not be used for any purpose other than
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
from raw data (like an email) to structured data (like an object
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
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,
Blueslip listens for the `error` event on `window`, and has methods
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
one can see cases where exceptions chained together. You can print
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:
@ -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
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
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
render tweets nicely). The frontend implementation is in JavaScript,
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
trip from the server. Those frontend renderings are only shown to the
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:
- The backend Markdown processor (`zerver/lib/markdown/__init__.py`).
- The frontend Markdown processor (`static/js/markdown.js` and sometimes
`static/third/marked/lib/marked.js`), or `markdown.contains_backend_only_syntax` if
- The frontend Markdown processor (`web/src/markdown.js` and sometimes
`web/third/marked/lib/marked.js`), or `markdown.contains_backend_only_syntax` if
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 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.
Important considerations for any changes are:

View File

@ -97,7 +97,7 @@ as follows:
debugging this system, since it has so much complexity.
- Desktop notifications are the simplest; they are implemented
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
the user's notification settings.
- 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
(`UserProfile.presence_enabled` is the flag storing [this user
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
to correct output.
- 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
rerenders it in any message lists where it appears. This is
primarily done in the `process_from_server` function in
`static/js/echo.js`.
`web/src/echo.js`.
### Local echo in message editing

View File

@ -52,4 +52,4 @@ send a message with the raw content.
## Typeahead
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
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
seconds. (This document is intended to describe the high level
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
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
`static/js/typing_events.js`.
`web/src/typing_events.js`.
The main goal is then to triage which events should lead to
display changes.
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:
- `add_typist`

View File

@ -51,11 +51,11 @@ Some important code entities for the widget implementation are:
- `SubMessage` database table
- `/json/submessage` API endpoint
- `static/js/submessage.js`
- `static/js/poll_widget.js`
- `static/js/widgetize.js`
- `static/js/zform.js`
- `static/templates/widgets/`
- `web/src/submessage.js`
- `web/src/poll_widget.js`
- `web/src/widgetize.js`
- `web/src/zform.js`
- `web/templates/widgets/`
- `zerver/lib/widget.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
message in the message pane. The widget has access to
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
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
changes in the current architecture. This could change
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
customized widget like **poll**. (In fact, **zform** is a
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:
```js
@ -308,7 +308,7 @@ widgets.todo = todo_widget;
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:
```js

View File

@ -45,8 +45,8 @@ You can also run them individually or pass specific files:
```bash
./tools/lint
./tools/lint static/js/compose.js
./tools/lint static/js/
./tools/lint web/src/compose.js
./tools/lint web/src/
```
`./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
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
there are, you should strive to follow the patterns of the existing tests
and add your own tests.
@ -120,7 +120,7 @@ For modules that you want to completely stub out, use a pattern like
this:
```js
const reminder = mock_esm("../../static/js/reminder", {
const reminder = mock_esm("../../web/src/reminder", {
is_deferred_delivery: noop,
});

View File

@ -239,7 +239,7 @@ $("#foo").html(
The only HTML tags allowed directly in translated strings are the
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
complex markup such as a link, you can define a custom HTML tag
locally to the translation:

View File

@ -44,11 +44,11 @@ organization in Zulip). The following files are involved in the process:
**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
permission setting).
- `static/js/settings_org.js`: handles organization setting form submission.
- `static/js/server_events_dispatch.js`: handles events coming from the server
- `web/src/settings_org.js`: handles organization setting form submission.
- `web/src/server_events_dispatch.js`: handles events coming from the server
(ex: pushing an organization change to other open browsers and updating
the application's state).
@ -124,17 +124,17 @@ Realm setting, in `test_realm.py`).
### Frontend changes
**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,
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
file.
**Templates:** The initial page structure is rendered via Jinja2
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.
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.
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`
(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
template.
Then add the new form control in `static/js/admin.js`.
Then add the new form control in `web/src/admin.js`.
```diff
// static/js/admin.js
// web/src/admin.js
export function build_page() {
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
`static/js/settings_org.js`.
`web/src/settings_org.js`.
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`.
```diff
// static/js/server_events_dispatch.js
// web/src/server_events_dispatch.js
function dispatch_normal_event(event) {
switch (event.type) {

View File

@ -282,7 +282,7 @@ Zulip realm).
You should always use `channel.<method>` to make an `HTTP <method>` call
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
var url = "/json/realm";

View File

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

View File

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

View File

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

View File

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

View File

@ -10,8 +10,8 @@ const blueslip_stacktrace = zrequire("blueslip_stacktrace");
run_test("clean_path", () => {
// Local file
assert.strictEqual(
blueslip_stacktrace.clean_path("webpack:///static/js/upload.js"),
"/static/js/upload.js",
blueslip_stacktrace.clean_path("webpack:///web/src/upload.js"),
"/web/src/upload.js",
);
// Third party library (jQuery)
@ -36,9 +36,9 @@ run_test("clean_function_name", () => {
// Local file
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",
},
);

View File

@ -9,7 +9,7 @@ const {run_test} = require("../zjsunit/test");
const blueslip = require("../zjsunit/zblueslip");
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 muted_users = zrequire("muted_users");

View File

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

View File

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

View File

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

View File

@ -17,38 +17,38 @@ set_global("document", {
to_$: () => $("document-stub"),
});
const channel = mock_esm("../../static/js/channel");
const compose_fade = mock_esm("../../static/js/compose_fade", {
const channel = mock_esm("../../web/src/channel");
const compose_fade = mock_esm("../../web/src/compose_fade", {
clear_compose: noop,
});
const compose_pm_pill = mock_esm("../../static/js/compose_pm_pill");
const compose_ui = mock_esm("../../static/js/compose_ui", {
const compose_pm_pill = mock_esm("../../web/src/compose_pm_pill");
const compose_ui = mock_esm("../../web/src/compose_ui", {
autosize_textarea: noop,
is_full_size: () => false,
});
const hash_util = mock_esm("../../static/js/hash_util");
const narrow_state = mock_esm("../../static/js/narrow_state", {
const hash_util = mock_esm("../../web/src/hash_util");
const narrow_state = mock_esm("../../web/src/narrow_state", {
set_compose_defaults: noop,
});
mock_esm("../../static/js/reload_state", {
mock_esm("../../web/src/reload_state", {
is_in_progress: () => false,
});
mock_esm("../../static/js/recent_topics_util", {
mock_esm("../../web/src/recent_topics_util", {
is_visible: noop,
});
mock_esm("../../static/js/drafts", {
mock_esm("../../web/src/drafts", {
update_draft: noop,
});
mock_esm("../../static/js/unread_ops", {
mock_esm("../../web/src/unread_ops", {
notify_server_message_read: noop,
});
mock_esm("../../static/js/message_lists", {
mock_esm("../../web/src/message_lists", {
current: {
can_mark_messages_read: () => true,
},
});
mock_esm("../../static/js/resize", {
mock_esm("../../web/src/resize", {
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 $ = require("../zjsunit/zjquery");
mock_esm("../../static/js/recent_topics_util", {
mock_esm("../../web/src/recent_topics_util", {
is_visible: () => false,
});
const noop = () => {};
// Mocking and stubbing things
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() {
return {
maybe_rerender: noop,
@ -21,7 +21,7 @@ function MessageListView() {
prepend: noop,
};
}
mock_esm("../../static/js/message_list_view", {
mock_esm("../../web/src/message_list_view", {
MessageListView,
});
// 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 $ = require("../zjsunit/zjquery");
const compose_actions = mock_esm("../../static/js/compose_actions");
const input_pill = mock_esm("../../static/js/input_pill");
const compose_actions = mock_esm("../../web/src/compose_actions");
const input_pill = mock_esm("../../web/src/input_pill");
const people = zrequire("people");
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 {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");

View File

@ -13,15 +13,15 @@ const noop = () => {};
set_global("navigator", {});
mock_esm("../../static/js/message_lists", {
mock_esm("../../web/src/message_lists", {
current: {},
});
const compose_ui = zrequire("compose_ui");
const people = zrequire("people");
const user_status = zrequire("user_status");
const hash_util = mock_esm("../../static/js/hash_util");
const channel = mock_esm("../../static/js/channel");
const hash_util = mock_esm("../../web/src/hash_util");
const channel = mock_esm("../../web/src/channel");
const compose_actions = zrequire("compose_actions");
const message_lists = zrequire("message_lists");
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 channel = mock_esm("../../static/js/channel");
const compose_actions = mock_esm("../../static/js/compose_actions");
const channel = mock_esm("../../web/src/channel");
const compose_actions = mock_esm("../../web/src/compose_actions");
const compose_banner = zrequire("compose_banner");
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 peer_data = zrequire("peer_data");
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_data = mock_esm("../../static/js/settings_data");
const settings_data = mock_esm("../../web/src/settings_data");
const stream_data = zrequire("stream_data");
const me = {

View File

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

View File

@ -9,20 +9,20 @@ const {user_settings} = require("../zjsunit/zpage_params");
const noop = () => {};
const compose = mock_esm("../../static/js/compose", {
const compose = mock_esm("../../web/src/compose", {
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,
});
const input_pill = mock_esm("../../static/js/input_pill");
const message_user_ids = mock_esm("../../static/js/message_user_ids", {
const input_pill = mock_esm("../../web/src/input_pill");
const message_user_ids = mock_esm("../../web/src/message_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,
});
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;
@ -34,7 +34,7 @@ set_global("setTimeout", (f, time) => {
});
set_global("document", "document-stub");
const typeahead = zrequire("../shared/js/typeahead");
const typeahead = zrequire("../shared/src/typeahead");
const compose_state = zrequire("compose_state");
const emoji = zrequire("emoji");
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 $ = jquery(window);
const compose_ui = mock_esm("../../static/js/compose_ui");
const compose_ui = mock_esm("../../web/src/compose_ui");
set_global("document", document);
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());
const activity = mock_esm("../../static/js/activity");
const alert_words_ui = mock_esm("../../static/js/alert_words_ui");
const attachments_ui = mock_esm("../../static/js/attachments_ui");
const bot_data = mock_esm("../../static/js/bot_data");
const compose_pm_pill = mock_esm("../../static/js/compose_pm_pill");
const composebox_typeahead = mock_esm("../../static/js/composebox_typeahead");
const dark_theme = mock_esm("../../static/js/dark_theme");
const emoji_picker = mock_esm("../../static/js/emoji_picker");
const hotspots = mock_esm("../../static/js/hotspots");
const linkifiers = mock_esm("../../static/js/linkifiers");
const message_events = mock_esm("../../static/js/message_events");
const message_lists = mock_esm("../../static/js/message_lists");
const muted_topics_ui = mock_esm("../../static/js/muted_topics_ui");
const muted_users_ui = mock_esm("../../static/js/muted_users_ui");
const notifications = mock_esm("../../static/js/notifications");
const pm_list = mock_esm("../../static/js/pm_list");
const reactions = mock_esm("../../static/js/reactions");
const realm_icon = mock_esm("../../static/js/realm_icon");
const realm_logo = mock_esm("../../static/js/realm_logo");
const realm_playground = mock_esm("../../static/js/realm_playground");
const reload = mock_esm("../../static/js/reload");
const scroll_bar = mock_esm("../../static/js/scroll_bar");
const settings_account = mock_esm("../../static/js/settings_account");
const settings_bots = mock_esm("../../static/js/settings_bots");
const settings_display = mock_esm("../../static/js/settings_display");
const settings_emoji = mock_esm("../../static/js/settings_emoji");
const settings_exports = mock_esm("../../static/js/settings_exports");
const settings_invites = mock_esm("../../static/js/settings_invites");
const settings_linkifiers = mock_esm("../../static/js/settings_linkifiers");
const settings_playgrounds = mock_esm("../../static/js/settings_playgrounds");
const settings_notifications = mock_esm("../../static/js/settings_notifications");
const settings_org = mock_esm("../../static/js/settings_org");
const settings_profile_fields = mock_esm("../../static/js/settings_profile_fields");
const activity = mock_esm("../../web/src/activity");
const alert_words_ui = mock_esm("../../web/src/alert_words_ui");
const attachments_ui = mock_esm("../../web/src/attachments_ui");
const bot_data = mock_esm("../../web/src/bot_data");
const compose_pm_pill = mock_esm("../../web/src/compose_pm_pill");
const composebox_typeahead = mock_esm("../../web/src/composebox_typeahead");
const dark_theme = mock_esm("../../web/src/dark_theme");
const emoji_picker = mock_esm("../../web/src/emoji_picker");
const hotspots = mock_esm("../../web/src/hotspots");
const linkifiers = mock_esm("../../web/src/linkifiers");
const message_events = mock_esm("../../web/src/message_events");
const message_lists = mock_esm("../../web/src/message_lists");
const muted_topics_ui = mock_esm("../../web/src/muted_topics_ui");
const muted_users_ui = mock_esm("../../web/src/muted_users_ui");
const notifications = mock_esm("../../web/src/notifications");
const pm_list = mock_esm("../../web/src/pm_list");
const reactions = mock_esm("../../web/src/reactions");
const realm_icon = mock_esm("../../web/src/realm_icon");
const realm_logo = mock_esm("../../web/src/realm_logo");
const realm_playground = mock_esm("../../web/src/realm_playground");
const reload = mock_esm("../../web/src/reload");
const scroll_bar = mock_esm("../../web/src/scroll_bar");
const settings_account = mock_esm("../../web/src/settings_account");
const settings_bots = mock_esm("../../web/src/settings_bots");
const settings_display = mock_esm("../../web/src/settings_display");
const settings_emoji = mock_esm("../../web/src/settings_emoji");
const settings_exports = mock_esm("../../web/src/settings_exports");
const settings_invites = mock_esm("../../web/src/settings_invites");
const settings_linkifiers = mock_esm("../../web/src/settings_linkifiers");
const settings_playgrounds = mock_esm("../../web/src/settings_playgrounds");
const settings_notifications = mock_esm("../../web/src/settings_notifications");
const settings_org = mock_esm("../../web/src/settings_org");
const settings_profile_fields = mock_esm("../../web/src/settings_profile_fields");
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_streams = mock_esm("../../static/js/settings_streams");
const settings_user_groups_legacy = mock_esm("../../static/js/settings_user_groups_legacy");
const settings_users = mock_esm("../../static/js/settings_users");
const stream_data = mock_esm("../../static/js/stream_data");
const stream_events = mock_esm("../../static/js/stream_events");
const stream_list = mock_esm("../../static/js/stream_list");
const stream_settings_ui = mock_esm("../../static/js/stream_settings_ui");
const stream_topic_history = mock_esm("../../static/js/stream_topic_history");
const submessage = mock_esm("../../static/js/submessage");
mock_esm("../../static/js/top_left_corner", {
const settings_realm_domains = mock_esm("../../web/src/settings_realm_domains");
const settings_streams = mock_esm("../../web/src/settings_streams");
const settings_user_groups_legacy = mock_esm("../../web/src/settings_user_groups_legacy");
const settings_users = mock_esm("../../web/src/settings_users");
const stream_data = mock_esm("../../web/src/stream_data");
const stream_events = mock_esm("../../web/src/stream_events");
const stream_list = mock_esm("../../web/src/stream_list");
const stream_settings_ui = mock_esm("../../web/src/stream_settings_ui");
const stream_topic_history = mock_esm("../../web/src/stream_topic_history");
const submessage = mock_esm("../../web/src/submessage");
mock_esm("../../web/src/top_left_corner", {
update_starred_count() {},
});
const typing_events = mock_esm("../../static/js/typing_events");
const ui = mock_esm("../../static/js/ui");
const unread_ops = mock_esm("../../static/js/unread_ops");
const user_events = mock_esm("../../static/js/user_events");
const user_groups = mock_esm("../../static/js/user_groups");
const user_group_edit = mock_esm("../../static/js/user_group_edit");
const overlays = mock_esm("../../static/js/overlays");
const user_groups_settings_ui = mock_esm("../../static/js/user_groups_settings_ui");
mock_esm("../../static/js/giphy");
const typing_events = mock_esm("../../web/src/typing_events");
const ui = mock_esm("../../web/src/ui");
const unread_ops = mock_esm("../../web/src/unread_ops");
const user_events = mock_esm("../../web/src/user_events");
const user_groups = mock_esm("../../web/src/user_groups");
const user_group_edit = mock_esm("../../web/src/user_group_edit");
const overlays = mock_esm("../../web/src/overlays");
const user_groups_settings_ui = mock_esm("../../web/src/user_groups_settings_ui");
mock_esm("../../web/src/giphy");
const electron_bridge = set_global("electron_bridge", {});
@ -125,7 +125,7 @@ people.add_active_user(test_user);
message_helper.process_new_message(test_message);
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});

View File

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

View File

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

View File

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

View File

@ -9,23 +9,23 @@ const {make_stub} = require("../zjsunit/stub");
const {run_test} = require("../zjsunit/test");
const {page_params} = require("../zjsunit/zpage_params");
const markdown = mock_esm("../../static/js/markdown");
const message_lists = mock_esm("../../static/js/message_lists");
const notifications = mock_esm("../../static/js/notifications");
const markdown = mock_esm("../../web/src/markdown");
const message_lists = mock_esm("../../web/src/message_lists");
const notifications = mock_esm("../../web/src/notifications");
let disparities = [];
mock_esm("../../static/js/ui", {
mock_esm("../../web/src/ui", {
show_failed_message_success() {},
});
mock_esm("../../static/js/sent_messages", {
mock_esm("../../web/src/sent_messages", {
mark_disparity(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}),
update_booleans() {},

View File

@ -5,7 +5,7 @@ const {strict: assert} = require("assert");
const {zrequire} = require("../zjsunit/namespace");
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");

View File

@ -10,7 +10,7 @@ const {run_test} = require("../zjsunit/test");
const emoji = zrequire("emoji");
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", () => {
emoji.initialize({

View File

@ -7,7 +7,7 @@ const {run_test} = require("../zjsunit/test");
const $ = require("../zjsunit/zjquery");
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}) => {
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
// code that makes things work.
const {Filter} = zrequire("../js/filter");
const {Filter} = zrequire("../src/filter");
const stream_data = zrequire("stream_data");
// 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.
const activity = mock_esm("../../static/js/activity");
const message_live_update = mock_esm("../../static/js/message_live_update");
const pm_list = mock_esm("../../static/js/pm_list");
const settings_users = mock_esm("../../static/js/settings_users");
const activity = mock_esm("../../web/src/activity");
const message_live_update = mock_esm("../../web/src/message_live_update");
const pm_list = mock_esm("../../web/src/pm_list");
const settings_users = mock_esm("../../web/src/settings_users");
// Use real versions of these modules.
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
// replace them with {}.
const huddle_data = mock_esm("../../static/js/huddle_data");
const message_lists = mock_esm("../../static/js/message_lists");
const message_util = mock_esm("../../static/js/message_util");
const notifications = mock_esm("../../static/js/notifications");
const pm_list = mock_esm("../../static/js/pm_list");
const recent_topics_data = mock_esm("../../static/js/recent_topics_data");
const stream_list = mock_esm("../../static/js/stream_list");
const unread_ops = mock_esm("../../static/js/unread_ops");
const unread_ui = mock_esm("../../static/js/unread_ui");
const huddle_data = mock_esm("../../web/src/huddle_data");
const message_lists = mock_esm("../../web/src/message_lists");
const message_util = mock_esm("../../web/src/message_util");
const notifications = mock_esm("../../web/src/notifications");
const pm_list = mock_esm("../../web/src/pm_list");
const recent_topics_data = mock_esm("../../web/src/recent_topics_data");
const stream_list = mock_esm("../../web/src/stream_list");
const unread_ops = mock_esm("../../web/src/unread_ops");
const unread_ui = mock_esm("../../web/src/unread_ui");
message_lists.home = {};

View File

@ -49,11 +49,11 @@ const {run_test} = require("../zjsunit/test");
value.)
*/
const channel = mock_esm("../../static/js/channel");
const message_lists = mock_esm("../../static/js/message_lists");
const message_viewport = mock_esm("../../static/js/message_viewport");
const notifications = mock_esm("../../static/js/notifications");
const unread_ui = mock_esm("../../static/js/unread_ui");
const channel = mock_esm("../../web/src/channel");
const message_lists = mock_esm("../../web/src/message_lists");
const message_viewport = mock_esm("../../web/src/message_viewport");
const notifications = mock_esm("../../web/src/notifications");
const unread_ui = mock_esm("../../web/src/unread_ui");
message_lists.current = {};
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";
// 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.
// 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 {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
// 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 {run_test} = require("../zjsunit/test");
mock_esm("../../static/js/message_scroll", {
mock_esm("../../web/src/message_scroll", {
hide_loading_older() {},
show_loading_older() {},

View File

@ -10,12 +10,12 @@ const blueslip = require("../zjsunit/zblueslip");
const $ = require("../zjsunit/zjquery");
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 people = zrequire("people");
const {Filter} = zrequire("../js/filter");
const {Filter} = zrequire("../src/filter");
const me = {
email: "me@example.com",

View File

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

View File

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

View File

@ -22,13 +22,13 @@ page_params.translation_data = {
// Re-register Zulip extensions so extensions registered previously with
// 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;
// here we do a quick sanity check on the engine itself.
// `i18n.js` initializes FormatJS and is imported by
// `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");
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);
});
require("../../static/templates/actions_popover_content.hbs")(args);
require("../../web/templates/actions_popover_content.hbs")(args);
});
run_test("tr_tag", ({mock_template}) => {
@ -117,7 +117,7 @@ run_test("tr_tag", ({mock_template}) => {
assert.equal(data, args);
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", () => {

View File

@ -12,7 +12,7 @@ set_global("document", {});
const noop = () => {};
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,
});
@ -40,7 +40,7 @@ function pill_html(value, img_src, 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}) => {

View File

@ -5,7 +5,7 @@ const {strict: assert} = require("assert");
const {zrequire} = require("../zjsunit/namespace");
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", () => {
const decoded = "https://www.zulipexample.com";

View File

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

View File

@ -7,18 +7,18 @@ const {run_test} = require("../zjsunit/test");
const $ = require("../zjsunit/zjquery");
set_global("Image", class Image {});
mock_esm("../../static/js/overlays", {
mock_esm("../../web/src/overlays", {
close_overlay() {},
close_active() {},
open_overlay() {},
});
mock_esm("../../static/js/popovers", {
mock_esm("../../web/src/popovers", {
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");

View File

@ -10,7 +10,7 @@ const blueslip = require("../zjsunit/zblueslip");
// The ListWidget library allows you to insert objects
// that are either jQuery, Element, or just raw HTML
// 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

View File

@ -30,10 +30,10 @@ user_settings.translate_emoticons = false;
set_global("document", {compatMode: "CSS1Compat"});
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 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 = zrequire("markdown");
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 settings_data = mock_esm("../../static/js/settings_data");
const settings_data = mock_esm("../../web/src/settings_data");
run_test("is_content_editable", () => {
// You can't edit a null message

View File

@ -7,13 +7,13 @@ const {run_test} = require("../zjsunit/test");
const $ = require("../zjsunit/zjquery");
const {page_params} = require("../zjsunit/zpage_params");
const condense = mock_esm("../../static/js/condense");
const message_edit = mock_esm("../../static/js/message_edit");
const message_lists = mock_esm("../../static/js/message_lists");
const notifications = mock_esm("../../static/js/notifications");
const pm_list = mock_esm("../../static/js/pm_list");
const stream_list = mock_esm("../../static/js/stream_list");
const unread_ui = mock_esm("../../static/js/unread_ui");
const condense = mock_esm("../../web/src/condense");
const message_edit = mock_esm("../../web/src/message_edit");
const message_lists = mock_esm("../../web/src/message_lists");
const notifications = mock_esm("../../web/src/notifications");
const pm_list = mock_esm("../../web/src/pm_list");
const stream_list = mock_esm("../../web/src/stream_list");
const unread_ui = mock_esm("../../web/src/unread_ui");
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,
};
}
mock_esm("../../static/js/message_list_view", {
mock_esm("../../web/src/message_list_view", {
MessageListView,
});
mock_esm("../../static/js/recent_topics_ui", {
mock_esm("../../web/src/recent_topics_ui", {
process_messages: noop,
show_loading_indicator: noop,
hide_loading_indicator: noop,
});
mock_esm("../../static/js/ui_report", {
mock_esm("../../web/src/ui_report", {
hide_error: noop,
});
const channel = mock_esm("../../static/js/channel");
const message_helper = mock_esm("../../static/js/message_helper");
const message_lists = mock_esm("../../static/js/message_lists");
const message_util = mock_esm("../../static/js/message_util");
const stream_list = mock_esm("../../static/js/stream_list", {
const channel = mock_esm("../../web/src/channel");
const message_helper = mock_esm("../../web/src/message_helper");
const message_lists = mock_esm("../../web/src/message_lists");
const message_util = mock_esm("../../web/src/message_util");
const stream_list = mock_esm("../../web/src/stream_list", {
maybe_scroll_narrow_into_view() {},
});
mock_esm("../../static/js/message_scroll", {
mock_esm("../../web/src/message_scroll", {
show_loading_older: noop,
hide_loading_older: noop,
show_loading_newer: noop,
@ -52,7 +52,7 @@ set_global("document", "document-stub");
const message_fetch = zrequire("message_fetch");
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 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 {run_test} = require("../zjsunit/test");
const channel = mock_esm("../../static/js/channel");
const ui = mock_esm("../../static/js/ui");
const channel = mock_esm("../../web/src/channel");
const ui = mock_esm("../../web/src/ui");
mock_esm("../../static/js/starred_messages", {
mock_esm("../../web/src/starred_messages", {
add() {},
get_starred_msg_ids: () => [1, 2, 3, 4, 5],
remove() {},

View File

@ -9,7 +9,7 @@ const blueslip = require("../zjsunit/zblueslip");
const $ = require("../zjsunit/zjquery");
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
// 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 stream_data = mock_esm("../../static/js/stream_data");
const narrow_state = mock_esm("../../web/src/narrow_state");
const stream_data = mock_esm("../../web/src/stream_data");
const {MessageList} = zrequire("message_list");
function MessageListView() {
@ -35,7 +35,7 @@ function MessageListView() {
clear_rendering_state: noop,
};
}
mock_esm("../../static/js/message_list_view", {
mock_esm("../../web/src/message_list_view", {
MessageListView,
});
const {Filter} = zrequire("filter");

View File

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

View File

@ -13,7 +13,7 @@ set_global("document", "document-stub");
const noop = () => {};
// timerender calls setInterval when imported
mock_esm("../../static/js/timerender", {
mock_esm("../../web/src/timerender", {
render_date(time) {
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() {
return {
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_guest: () => false,
small_avatar_url: () => "fake/small/avatar/url",
});
const {Filter} = zrequire("../js/filter");
const {MessageListView} = zrequire("../js/message_list_view");
const {Filter} = zrequire("../src/filter");
const {MessageListView} = zrequire("../src/message_list_view");
const message_list = zrequire("message_list");
const muted_users = zrequire("muted_users");

View File

@ -9,11 +9,11 @@ const {page_params} = require("../zjsunit/zpage_params");
const noop = () => {};
mock_esm("../../static/js/stream_topic_history", {
mock_esm("../../web/src/stream_topic_history", {
add_message: noop,
});
mock_esm("../../static/js/recent_senders", {
mock_esm("../../web/src/recent_senders", {
process_stream_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 people = zrequire("people");
const stream_data = zrequire("stream_data");
const {Filter} = zrequire("../js/filter");
const {Filter} = zrequire("../src/filter");
const narrow = zrequire("narrow");
const settings_config = zrequire("settings_config");
const compose_pm_pill = mock_esm("../../static/js/compose_pm_pill");
mock_esm("../../static/js/spectators", {
const compose_pm_pill = mock_esm("../../web/src/compose_pm_pill");
mock_esm("../../web/src/spectators", {
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() {},
});
@ -32,7 +32,7 @@ function empty_narrow_html(title, html, search_data) {
html,
search_data,
};
return require("../../static/templates/empty_feed_notice.hbs")(opts);
return require("../../web/templates/empty_feed_notice.hbs")(opts);
}
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 $ = require("../zjsunit/zjquery");
mock_esm("../../static/js/resize", {
mock_esm("../../web/src/resize", {
resize_stream_filters_container() {},
});
const all_messages_data = mock_esm("../../static/js/all_messages_data");
const channel = mock_esm("../../static/js/channel");
const compose_actions = mock_esm("../../static/js/compose_actions");
const compose_banner = mock_esm("../../static/js/compose_banner");
const compose_closed_ui = mock_esm("../../static/js/compose_closed_ui");
const hashchange = mock_esm("../../static/js/hashchange");
const message_fetch = mock_esm("../../static/js/message_fetch");
const message_list = mock_esm("../../static/js/message_list");
const message_lists = mock_esm("../../static/js/message_lists", {
const all_messages_data = mock_esm("../../web/src/all_messages_data");
const channel = mock_esm("../../web/src/channel");
const compose_actions = mock_esm("../../web/src/compose_actions");
const compose_banner = mock_esm("../../web/src/compose_banner");
const compose_closed_ui = mock_esm("../../web/src/compose_closed_ui");
const hashchange = mock_esm("../../web/src/hashchange");
const message_fetch = mock_esm("../../web/src/message_fetch");
const message_list = mock_esm("../../web/src/message_list");
const message_lists = mock_esm("../../web/src/message_lists", {
home: {},
current: {},
set_current(msg_list) {
message_lists.current = msg_list;
},
});
const message_scroll = mock_esm("../../static/js/message_scroll");
const message_view_header = mock_esm("../../static/js/message_view_header");
const notifications = mock_esm("../../static/js/notifications");
const search = mock_esm("../../static/js/search");
const stream_list = mock_esm("../../static/js/stream_list");
const top_left_corner = mock_esm("../../static/js/top_left_corner");
const typing_events = mock_esm("../../static/js/typing_events");
const unread_ops = mock_esm("../../static/js/unread_ops");
mock_esm("../../static/js/recent_topics_util", {
const message_scroll = mock_esm("../../web/src/message_scroll");
const message_view_header = mock_esm("../../web/src/message_view_header");
const notifications = mock_esm("../../web/src/notifications");
const search = mock_esm("../../web/src/search");
const stream_list = mock_esm("../../web/src/stream_list");
const top_left_corner = mock_esm("../../web/src/top_left_corner");
const typing_events = mock_esm("../../web/src/typing_events");
const unread_ops = mock_esm("../../web/src/unread_ops");
mock_esm("../../web/src/recent_topics_util", {
is_visible() {},
});
@ -45,7 +45,7 @@ set_global("setTimeout", (f, t) => {
f();
});
mock_esm("../../static/js/user_topics", {
mock_esm("../../web/src/user_topics", {
is_topic_muted: () => false,
});

View File

@ -5,13 +5,13 @@ const {strict: assert} = require("assert");
const {mock_esm, zrequire} = require("../zjsunit/namespace");
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 {MessageListData} = zrequire("../js/message_list_data");
const {Filter} = zrequire("../src/filter");
const {MessageListData} = zrequire("../src/message_list_data");
const narrow_state = zrequire("narrow_state");
const narrow = zrequire("narrow");
const resolved_topic = zrequire("../shared/js/resolved_topic");
const resolved_topic = zrequire("../shared/src/resolved_topic");
function test_with(fixture) {
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 people = zrequire("people");
const {Filter} = zrequire("../js/filter");
const {Filter} = zrequire("../src/filter");
const stream_data = zrequire("stream_data");
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 blueslip = require("../zjsunit/zblueslip");
mock_esm("../../static/js/user_topics", {
mock_esm("../../web/src/user_topics", {
is_topic_muted: () => false,
});
const {Filter} = zrequire("../js/filter");
const {Filter} = zrequire("../src/filter");
const message_store = zrequire("message_store");
const people = zrequire("people");
const stream_data = zrequire("stream_data");

View File

@ -12,7 +12,7 @@ const {run_test} = require("../zjsunit/test");
const blueslip = require("../zjsunit/zblueslip");
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 people = zrequire("people");

View File

@ -6,7 +6,7 @@ const {mock_esm, zrequire} = require("../zjsunit/namespace");
const {run_test} = require("../zjsunit/test");
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,
});

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_group = $.create("fake-rendered-group");
mock_esm("../../static/js/typeahead_helper", {
mock_esm("../../web/src/typeahead_helper", {
render_person() {
return $fake_rendered_person;
},

View File

@ -5,9 +5,9 @@ const {strict: assert} = require("assert");
const {mock_esm, zrequire} = require("../zjsunit/namespace");
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: () => ({
emoji_code: 20,
}),

View File

@ -7,7 +7,7 @@ const {run_test} = require("../zjsunit/test");
const blueslip = require("../zjsunit/zblueslip");
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");

View File

@ -15,21 +15,21 @@ class Clipboard {
}
mock_cjs("clipboard", Clipboard);
const rows = mock_esm("../../static/js/rows");
mock_esm("../../static/js/emoji_picker", {
const rows = mock_esm("../../web/src/rows");
mock_esm("../../web/src/emoji_picker", {
hide_emoji_popover: noop,
});
mock_esm("../../static/js/giphy", {
mock_esm("../../web/src/giphy", {
hide_giphy_popover: noop,
});
const message_lists = mock_esm("../../static/js/message_lists", {
const message_lists = mock_esm("../../web/src/message_lists", {
current: {
view: {
message_containers: {},
},
},
});
mock_esm("../../static/js/stream_popover", {
mock_esm("../../web/src/stream_popover", {
hide_stream_popover: noop,
hide_topic_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 {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,
});

View File

@ -38,13 +38,13 @@ const sample_message = {
],
};
const channel = mock_esm("../../static/js/channel");
const emoji_picker = mock_esm("../../static/js/emoji_picker", {
const channel = mock_esm("../../web/src/channel");
const emoji_picker = mock_esm("../../web/src/emoji_picker", {
hide_emoji_popover() {},
});
const message_lists = mock_esm("../../static/js/message_lists");
const message_store = mock_esm("../../static/js/message_store");
const spectators = mock_esm("../../static/js/spectators", {
const message_lists = mock_esm("../../web/src/message_lists");
const message_store = mock_esm("../../web/src/message_store");
const spectators = mock_esm("../../web/src/spectators", {
login_to_access() {},
});
@ -59,7 +59,7 @@ message_lists.current = {
set_global("document", "document-stub");
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 reactions = zrequire("reactions");

View File

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

View File

@ -39,7 +39,7 @@ const topic10 = "topic-10";
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,
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,
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_topic_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 {},
});
mock_esm("../../static/js/message_store", {
mock_esm("../../web/src/message_store", {
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,
});
mock_esm("../../static/js/user_topics", {
mock_esm("../../web/src/user_topics", {
is_topic_muted(stream_id, topic) {
if (stream_id === stream1 && topic === topic7) {
return true;
@ -101,33 +101,33 @@ mock_esm("../../static/js/user_topics", {
return false;
},
});
const narrow = mock_esm("../../static/js/narrow", {
const narrow = mock_esm("../../web/src/narrow", {
update_narrow_title: noop,
hide_mark_as_read_turned_off_banner: noop,
handle_middle_pane_transition: noop,
has_shown_message_list_view: true,
});
mock_esm("../../static/js/pm_list", {
mock_esm("../../web/src/pm_list", {
update_private_messages: noop,
handle_narrow_deactivated: noop,
});
mock_esm("../../static/js/recent_senders", {
mock_esm("../../web/src/recent_senders", {
get_topic_recent_senders: () => [2, 1],
});
mock_esm("../../static/js/stream_data", {
mock_esm("../../web/src/stream_data", {
is_muted: () =>
// We only test via muted topics for now.
// TODO: Make muted streams and test them.
false,
});
mock_esm("../../static/js/stream_list", {
mock_esm("../../web/src/stream_list", {
handle_narrow_deactivated: noop,
});
mock_esm("../../static/js/timerender", {
mock_esm("../../web/src/timerender", {
last_seen_status_from_date: () => "Just now",
get_full_datetime: () => "date at time",
});
mock_esm("../../static/js/sub_store", {
mock_esm("../../web/src/sub_store", {
get(stream) {
if (stream === stream5) {
// 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,
});
mock_esm("../../static/js/unread", {
mock_esm("../../web/src/unread", {
num_unread_for_topic(stream_id, topic) {
if (stream_id === 1 && topic === "topic-1") {
return 0;

View File

@ -17,7 +17,7 @@ class 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";
const rm = zrequire("rendered_markdown");

View File

@ -5,7 +5,7 @@ const {strict: assert} = require("assert");
const {zrequire} = require("../zjsunit/namespace");
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 resolved_name = "✔ " + topic_name;

View File

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

View File

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

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