Skip to content

Commit

Permalink
fix: doc updates for modes and minor file reorg
Browse files Browse the repository at this point in the history
* chore(config): move test and dev configs to hosted

* chore(project): fix time mock for live channels tests

* chore(project): fix time mock for live channels tests, fix config query param

* chore(project): fix live and seo tests

* chore(project): fix live channel test to support GMT

* chore: remove console statements

* chore(project): move fixture files out of src

* chore(project): only include epg channel data when env variable set

* feat(config): add dialog when no config ID found

* feat(config): finish dialog for missing config

* fix(config): run demo in production env

* chore: clean test logs and fix skipped tests

* chore: fill in remaining skipped tests

* chore: update vulnerable dependency and fix password tests

* feat(config): add local settings file for config sources

* chore: change from settings.json to .webapp.ini for local param files

* chore: fix all test-ids to use helper function

* docs: added docs for types and build

* docs: fix missing mode and directory details

* docs: rename .images to _images

* Update docs/build-from-source.md

Co-authored-by: Carina Dragan  <92930790+CarinaDraganJW@users.noreply.github.com>

* Update docs/build-from-source.md

Co-authored-by: Carina Dragan  <92930790+CarinaDraganJW@users.noreply.github.com>

* Update docs/developer-guidelines.md

Co-authored-by: Carina Dragan  <92930790+CarinaDraganJW@users.noreply.github.com>

* Update docs/build-from-source.md

Co-authored-by: Carina Dragan  <92930790+CarinaDraganJW@users.noreply.github.com>

* Update docs/developer-guidelines.md

Co-authored-by: Carina Dragan  <92930790+CarinaDraganJW@users.noreply.github.com>

Co-authored-by: Carina Dragan  <92930790+CarinaDraganJW@users.noreply.github.com>
  • Loading branch information
dbudzins and CarinaDraganJW authored Jan 18, 2023
1 parent 3da1910 commit d9c7e8f
Show file tree
Hide file tree
Showing 46 changed files with 117 additions and 52 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
![JW OTT Webapp](./images/homepage-screenshot.png)
![JW OTT Webapp](docs/_images/homepage-screenshot.png)

The JW OTT Webapp is an open-source, dynamically generated video website built around JW Player and JW Platform services. It enables you to easily publish your JW Player-hosted video content with no coding and minimal configuration.

Expand All @@ -10,15 +10,15 @@ To see an example of JW OTT Webapp in action, see [https://app-preview.jwplayer.
<tr>
<td>
<p>Symphony <br/> (<a href="https://symphony.live/">symphony.live</a>)</p>
<img src="./images/symphony.png" alt="Symphony" height="200">
<img src="docs/_images/symphony.png" alt="Symphony" height="200">
</td>
<td>
<p>FansChoice.tv <br/> (<a href="https://www.fanschoice.tv/">fanschoice.tv</a>)</p>
<img src="./images/fanschoice.png" alt="FansChoice" height="200">
<img src="docs/_images/fanschoice.png" alt="FansChoice" height="200">
</td>
<td>
<p>Trinity Broadcasting Network <br/> (<a href="https://watch.tbn.org/">watch.tbn.org</a>)</p>
<img src="./images/tbn.png" alt="TBN" height="200">
<img src="docs/_images/tbn.png" alt="TBN" height="200">
</td>
</tr>
</table>
Expand Down
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
32 changes: 30 additions & 2 deletions docs/build-from-source.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,46 @@ $ yarn --ignore-optional

> **NOTE**: Some of the [easy deployments](easy-deployments.md) instructions require installing these optional dependencies. Use the `yarn` command to install all dependencies. The `yarn` command can be run even if `yarn --ignore-optional` has been previously run.
3. Start the local development server.
3. Create or update the .ini files in `/ini` for the modes you will be running in (probably dev and prod.)
You can copy the ini file from `/ini/templates` into `/ini`. The files in `/ini` are git-ignored, so you do not need to worry about account values in source control, but you will need to recreate the ini files each time you make a fresh checkout of the repository.

The .ini files provide startup values to the application such as which app config to load by default. See [initialization-file](initialization-file.md) for more details.


4. Start the local development server.

```shell
$ yarn start
```

If you encounter any errors, make sure you have correctly set the `defaultConfigSource` in `/ini/.webapp.dev.ini` to point to a valid app config from your JWP account.
> **NOTE:** Only use the development server for development purposes. The development server is not optimized for production usage.
4. Build a deployable version of the JW OTT Webapp source code.<br /><br />This command creates a new folder in the projects root folder named **build**. This folder can be uploaded to any hosting provider.
5. Build a deployable version of the JW OTT Webapp source code.<br /><br />This command creates a new folder in the projects root folder named **build**.
The `public` folder from the build directory can be uploaded to any static hosting provider to run the web app from that host.

```shell
$ yarn build
```

If you have not made any changes to the JW OTT Webapp configuration or source code, changes can now be made. Be sure to run the `yarn build` command after making any changes.

If you encounter any errors, first check to make sure you've properly updated `/ini/.webapp.prod.ini` to point `defaultConfigSource` to your production app config from your JWP account.

## Modes

We make use of [Vite's 'mode' concept](https://vitejs.dev/guide/env-and-mode.html#modes) to cleanly separate different deployments.
For most cases, you will want to use `dev`, `test`, or `prod` modes. The supported modes are described below.

Please keep in mind that there is a nuanced difference between vite `mode` and whether you are running a development or production build as determined by [`NODE_ENV`](https://nodejs.dev/en/learn/nodejs-the-difference-between-development-and-production/).
Mode can be whatever different deployment environments that our application can be run in, while the build type will always be either `development` or `production`.
Typically when you run the development server using `yarn start`, it will be a `development` build and you build the code with `yarn build` and then host it from static hosting, you will be running a production build.

Production builds optimize code and minimize debug information, while development builds are made for developers to dig into.

* **dev** - used for developers to locally develop, test, and debug code. Has the most debug information, including a config selector to help developers quickly switch between app configs. Will allow any app config to be loaded.
* **test** - used when running unit and e2e tests. Should typically be run as a production build. Will only load a select list of test app configs
* **prod** - default used when running `yarn build` to create compiled code for production hosting. You should make sure to update the prod .ini file to only allow app configs from your account.
* **demo** - used for the [JWP preview site](https://app-preview.jwplayer.com/) and includes a dialog to switch between app configs. Will allow any app-config to be loaded and does not have a default config.
* **preview** - used for github PR previews. Behaves like a hybrid between dev and demo.
* **jwdev** - this mode is for running code on JW's internal dev environment. It will only work for JW employees on the internal network.
42 changes: 35 additions & 7 deletions docs/developer-guidelines.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,19 +97,47 @@ The footer should contain any information about **Breaking Changes** and is also
## Project Structure

```
/src
/.github - Templates and action workflows for Github
/.husky - Husky scripts for running checks on git triggers
/build* - Directory where the code is compiled by `yarn build`
/coverage* - Location of the C8 coverage report
/docs - Documentation
/_images - Images used in the docs and README
/features - Docs coverage specific product use cases
/ini - Directory to group different initialization files
/templates - Template .ini files per mode
/node_modules* - Yarn generated dependencies
/public - Static files to be hosted with the application
/scripts - Dev helper scripts for i18n, deployment, etc.
/src - Source code for the application
/assets - Static assets (image, svg, etc.)
/components - (Reusable) components
/components - Reusable, side-effect free UI components
/containers - UI Containers
/hooks - Custom React hooks
/i18n - Internationalization tools
/locales - Languages specific folders with translation json files
/icons - SVG icons wrapped in React Components
/providers - React context
/screens - Screens (essentially containers, but only used directly in the router)
/pages - Main application layout containers per route
/ScreenRouting- Mappings from media_type to layout container for medias
/services - Services which connects external data sources to the application
/stores - Pullstate store files
/stores - Zustand stores and controllers
/styles - Global SCSS rules, theming and variables
/utils - Utility functions
/App.tsx - The main React component which renders the app
/index.ts - The entrypoint
/index.tsx - The entrypoint
/registerSer... - Script or SPA functionality
/test - Data and scrips for unit and e2e testing
/test-e2e - End to end tests and scripts
/types - Global type definitions
/.env<.mode> - Environment variables for different Vite modes
/CHANGELOG.md - Auto-generated changelog
/firebase.json - Config for firebase static hosting
/index.html - Main html file entrypoint for the application
/package.json - Yarn file for dependencies and scripts
/vite.config.ts - Vite build and test configuration file
* = Generated directories, not in source control
Note: Some system and util files are not shown above for brevity.
You probably won't need to mess with anything not shown here.
```
2 changes: 1 addition & 1 deletion docs/features/live-channels-with-epg.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
If you want to list one or more 24x7 livestream channels, it is possible to enable a custom page with an EPG view. Of
course, you would need to have EPG data available for this to work.

<img title="" src="img/live-channels-epg.png" alt="Series" width="580">
<img title="" src="../_images/live-channels-epg.png" alt="Series" width="580">

Below are the steps to enable the live channels page in your OTT Webapp.

Expand Down
2 changes: 1 addition & 1 deletion docs/features/related-videos.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Related Videos

![Related Videos](img/related-videos.jpg)
![Related Videos](../_images/related-videos.jpg)

Related videos are a shelf in the [video detail screen](video-detail.md) showing content with similar metadata.

Expand Down
2 changes: 1 addition & 1 deletion docs/features/search.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Search

![Search](img/search.jpg)
![Search](../_images/search.jpg)

Search is essentially a [library](shelves-and-libraries.md) screen that reacts to a search term. A search queries the media `title` and `description` fields.

Expand Down
6 changes: 3 additions & 3 deletions docs/features/series.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

Series enables customers to bundle episodic content such as TV shows and learning courses or non-episodic content like sports leagues events. By organizing content into a series, viewers are guided through the content. Series have a predefined sequence of episodes and can be split in seasons.

<img title="" src="img/series.jpg" alt="Series" width="580">
<img title="" src="../_images/series.jpg" alt="Series" width="580">

Series are tagged with `Series` in [shelves and libraries](shelves-and-libraries.md):

<img title="" src="img/series-in-library.jpg" alt="Series in library" width="581">
<img title="" src="../_images/series-in-library.jpg" alt="Series in library" width="581">

Series are defined through 'series playlist'. This is handled in the first piece of this article.

Expand Down Expand Up @@ -193,4 +193,4 @@ Customer are advised to exclude series episodes from the search playlists by usi

## Coming soon

We will add full Favorites and Continue Watching support
We will add full Favorites and Continue Watching support
4 changes: 2 additions & 2 deletions docs/features/shelves-and-libraries.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Video Shelves and Libraries

<img title="" src="./img/shelves.jpg" alt="Shelves" width="316"> <img src="./img/library.jpg" title="" alt="Libraries" width="317">
<img title="" src="./../_images/shelves.jpg" alt="Shelves" width="316"> <img src="./../_images/library.jpg" title="" alt="Libraries" width="317">

## Shelves

Expand Down Expand Up @@ -34,7 +34,7 @@ Videos are published to shelves and libraries using playlists:
- For dynamic playlist items are added based on tags and sorted on most viewed, most recently published or alphabetically
- Playlists apply geoblocking: only the video available in the viewer's country are returned. It uses the IP address to determine the country.

<img src="./img/playlist-shelf-lib.jpg" title="" alt="Shelves" width="600">
<img src="./../_images/playlist-shelf-lib.jpg" title="" alt="Shelves" width="600">

## Images

Expand Down
4 changes: 2 additions & 2 deletions docs/features/user-watchlists.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# User watchlists

<img title="" src="./img/watchlist.jpg" alt="continue-watchting" width="542">
<img title="" src="./../_images/watchlist.jpg" alt="continue-watchting" width="542">

######

Expand Down Expand Up @@ -123,4 +123,4 @@ Cleeng customer `externalData` attribute has maxsize of 5000 symbols.

The length of one stringified object of History equals to 52 symbols, one Favorites object equals to 22 symbols. Taking into account only History objects, we get 5000 / 52 = ~96, so 48 for Favorites and 48 for History. We also leave some extra space for possible further updates.

We rotate the oldest continue watching object to the first item position after its progress property gets a new value.
We rotate the oldest continue watching object to the first item position after its progress property gets a new value.
2 changes: 1 addition & 1 deletion docs/features/video-detail.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

A video detail page is where a viewer evaluates a published video, before deciding to play the video.

![Video detail](./img/video-detail.jpg)
![Video detail](./../_images/video-detail.jpg)

This page displays attributes that are common to all videos, such as:

Expand Down
4 changes: 2 additions & 2 deletions docs/features/video-sharing.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Share URLs

![Share video](img/share-video.jpg)
![Share video](../_images/share-video.jpg)

Viewers can share a video:
- On the desktop this will copy the URL to the clipboard
Expand All @@ -14,7 +14,7 @@ Sharing can be enabled/disabled in the [app config](/docs/configuration.md)

The player also has a share button. It is advised that customers disable this in the [the JW Player Config](https://support.jwplayer.com/articles/how-to-implement-social-sharing) that is linked to the web-app config.

![Disable sharing in player](img/share-player.jpg)
![Disable sharing in player](../_images/share-player.jpg)

## Deeplink to devices

Expand Down
4 changes: 2 additions & 2 deletions docs/initialization-file.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# Initialization (ini) File

The JW OTT Web App loads a small initialization (.ini) file at startup. This file provides a mechanism to set key parameters without modifying the source code.
The JW OTT Web App loads a small initialization (.ini) file at startup. This file provides a mechanism to set key startup parameters without modifying the source code.
Template ini files are included in the repo and with the pre-compiled production release builds ([.webapp.prod.ini](/ini/templates/.webapp.prod.ini)).
Make sure you include a copy of the ini file edited to include your account data at `/public/.webapp.ini` for the application to load correctly.

For all manual builds (`yarn start` or `yarn build`), the ini file is copied from `/ini/.webapp.<mode>.ini` to `build/public/.webapp.ini`, which the application fetches and parses at startup.
If a file doesn't exist in /ini/.webapp.<mode>.ini, then the template file will first be copied from [`/ini/templates`](/ini/templates).
All of the .ini files inside of /ini are ignored in git, so you can create your own files locally to run the application with your account parameters without creating conflicts with committed code or leaking your details into source control.
All of the .ini files directly inside of `/ini` are ignored in git, so you can create your own files locally to run the application with your account parameters without creating conflicts with committed code or leaking your details into source control.

## Ini Parameters

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -138,4 +138,4 @@
"codeceptjs/**/ansi-regex": "^4.1.1",
"codeceptjs/**/minimatch": "^3.0.5"
}
}
}
2 changes: 1 addition & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useEffect, useState } from 'react';
import { BrowserRouter, HashRouter } from 'react-router-dom';

import QueryProvider from '#src/providers/QueryProvider';
import QueryProvider from '#src/containers/QueryProvider/QueryProvider';
import '#src/screenMapping';
import '#src/styles/main.scss';
import initI18n from '#src/i18n/config';
Expand Down
2 changes: 1 addition & 1 deletion src/components/Favorites/Favorites.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';

import Favorites from './Favorites';

import { PersonalShelf } from '#src/enum/PersonalShelf';
import { PersonalShelf } from '#src/stores/ConfigStore';
import PlaylistContainer from '#src/containers/PlaylistContainer/PlaylistContainer';
import { renderWithRouter } from '#test/testUtils';

Expand Down
6 changes: 6 additions & 0 deletions src/components/Root/Root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { cleanupQueryParams, getConfigSource } from '#src/utils/configOverride';
import { loadAndValidateConfig } from '#src/utils/configLoad';
import { initSettings } from '#src/stores/SettingsController';
import AppRoutes from '#src/containers/AppRoutes/AppRoutes';
import registerCustomScreens from '#src/screenMapping';

const Root: FC = () => {
const { t } = useTranslation('error');
Expand Down Expand Up @@ -40,6 +41,11 @@ const Root: FC = () => {
refetchInterval: false,
});

// Register custom screen mappings
useEffect(() => {
registerCustomScreens();
}, []);

const IS_DEMO_OR_PREVIEW = IS_DEMO_MODE || IS_PREVIEW_MODE;

// Show the spinner while loading except in demo mode (the demo config shows its own loading status)
Expand Down
2 changes: 1 addition & 1 deletion src/containers/PlaylistContainer/PlaylistContainer.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useEffect } from 'react';

import { PersonalShelf, PersonalShelves } from '#src/enum/PersonalShelf';
import { PersonalShelf, PersonalShelves } from '#src/stores/ConfigStore';
import usePlaylist from '#src/hooks/usePlaylist';
import { useWatchHistoryStore } from '#src/stores/WatchHistoryStore';
import { useFavoritesStore } from '#src/stores/FavoritesStore';
Expand Down
File renamed without changes.
3 changes: 1 addition & 2 deletions src/containers/ShelfList/ShelfList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ import styles from './ShelfList.module.scss';

import PlaylistContainer from '#src/containers/PlaylistContainer/PlaylistContainer';
import { useAccountStore } from '#src/stores/AccountStore';
import { useConfigStore } from '#src/stores/ConfigStore';
import { PersonalShelf } from '#src/enum/PersonalShelf';
import { PersonalShelf, useConfigStore } from '#src/stores/ConfigStore';
import ShelfComponent from '#components/Shelf/Shelf';
import { mediaURL, slugify } from '#src/utils/formatting';
import type { Content } from '#types/Config';
Expand Down
5 changes: 0 additions & 5 deletions src/enum/PersonalShelf.ts

This file was deleted.

2 changes: 1 addition & 1 deletion src/hooks/usePlaylist.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import useContentProtection from '#src/hooks/useContentProtection';
import { generatePlaylistPlaceholder } from '#src/utils/collection';
import type { GetPlaylistParams } from '#types/playlist';
import { getPlaylistById } from '#src/services/api.service';
import { queryClient } from '#src/providers/QueryProvider';
import { queryClient } from '#src/containers/QueryProvider/QueryProvider';

const placeholderData = generatePlaylistPlaceholder(30);

Expand Down
3 changes: 1 addition & 2 deletions src/pages/User/User.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,13 @@ import shallow from 'zustand/shallow';
import styles from './User.module.scss';

import PlaylistContainer from '#src/containers/PlaylistContainer/PlaylistContainer';
import { PersonalShelf } from '#src/enum/PersonalShelf';
import { mediaURL } from '#src/utils/formatting';
import AccountCircle from '#src/icons/AccountCircle';
import Favorite from '#src/icons/Favorite';
import BalanceWallet from '#src/icons/BalanceWallet';
import Exit from '#src/icons/Exit';
import { useAccountStore } from '#src/stores/AccountStore';
import { useConfigStore } from '#src/stores/ConfigStore';
import { PersonalShelf, useConfigStore } from '#src/stores/ConfigStore';
import useBreakpoint, { Breakpoint } from '#src/hooks/useBreakpoint';
import LoadingOverlay from '#components/LoadingOverlay/LoadingOverlay';
import ConfirmationDialog from '#components/ConfirmationDialog/ConfirmationDialog';
Expand Down
8 changes: 5 additions & 3 deletions src/screenMapping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,10 @@ import MediaHub from '#src/pages/ScreenRouting/mediaScreens/MediaHub/MediaHub';
* mediaScreenMap.register(CustomMediaScreen, () => true);
*
* The same methods can be used for the `playlistScreenMap` that is exported from
* {@link pages/ScreenRouting/PlaylistScreenRouter.tsx}
* {@link /src/pages/ScreenRouting/PlaylistScreenRouter.tsx}
*/

// Hub is an example screen for the media router
mediaScreenMap.registerByContentType(MediaHub, 'hub');
export default function registerCustomScreens() {
// Hub is an example screen for the media router
mediaScreenMap.registerByContentType(MediaHub, 'hub');
}
2 changes: 1 addition & 1 deletion src/stores/AccountController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { useAccountStore } from '#src/stores/AccountStore';
import { restoreWatchHistory, serializeWatchHistory } from '#src/stores/WatchHistoryController';
import { restoreFavorites, serializeFavorites } from '#src/stores/FavoritesController';
import { getMediaByWatchlist } from '#src/services/api.service';
import { queryClient } from '#src/providers/QueryProvider';
import { queryClient } from '#src/containers/QueryProvider/QueryProvider';
import type { AccessModel, Config } from '#types/Config';

const PERSIST_KEY_ACCOUNT = 'auth';
Expand Down
7 changes: 7 additions & 0 deletions src/stores/ConfigStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@ import { createStore } from './utils';

import type { AccessModel, Config } from '#types/Config';

export enum PersonalShelf {
ContinueWatching = 'continue_watching',
Favorites = 'favorites',
}

export const PersonalShelves = [PersonalShelf.Favorites, PersonalShelf.ContinueWatching];

type CleengData = {
cleengId: string | null | undefined;
cleengSandbox: boolean;
Expand Down
Loading

0 comments on commit d9c7e8f

Please sign in to comment.