Move Storybook back into web (#13219)

GitOrigin-RevId: 61b69b5fd178dd4f5ab26858c434f959dfc410bc
This commit is contained in:
Alf Eaton 2023-12-14 09:41:03 +00:00 committed by Copybot
parent b228c9016e
commit 76d195cd39
11 changed files with 7034 additions and 1466 deletions

8153
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -49,7 +49,6 @@
"services/third-party-datastore",
"services/third-party-references",
"services/tpdsworker",
"services/web",
"tools/storybook"
"services/web"
]
}

View file

@ -0,0 +1,62 @@
import type { StorybookConfig } from '@storybook/react-webpack5'
import path from 'node:path'
const rootDir = path.resolve(__dirname, '..')
// NOTE: must be set before webpack config is imported
process.env.SHARELATEX_CONFIG = path.join(rootDir, 'config/settings.webpack.js')
const config: StorybookConfig = {
core: {
disableTelemetry: true,
},
staticDirs: [path.join(rootDir, 'public')],
stories: [
path.join(rootDir, 'frontend/stories/**/*.stories.{js,jsx,ts,tsx}'),
path.join(rootDir, 'modules/**/stories/**/*.stories.{js,jsx,ts,tsx}'),
],
addons: [
'@storybook/addon-links',
'@storybook/addon-essentials',
'@storybook/addon-interactions',
'@storybook/addon-a11y',
],
framework: {
name: '@storybook/react-webpack5',
options: {},
},
docs: {
autodocs: 'tag',
},
babel: options => {
return {
...options,
plugins: [
// ensure that TSX files are transformed before other plugins run
['@babel/plugin-transform-typescript', { isTSX: true }],
...(options.plugins ?? []),
],
}
},
webpackFinal: storybookConfig => {
return {
...storybookConfig,
resolve: {
...storybookConfig.resolve,
fallback: {
...storybookConfig.resolve?.fallback,
fs: false,
os: false,
module: false,
},
extensions: ['.js', '.jsx', '.mjs', '.ts', '.tsx', '.json'],
alias: {
...storybookConfig.resolve?.alias,
// custom prefixes for import paths
'@': path.join(rootDir, 'frontend/js/'),
},
},
}
},
}
export default config

View file

@ -0,0 +1,3 @@
.sidebar-container a[title='Overleaf'] {
max-width: 100px;
}

View file

@ -0,0 +1,15 @@
import { addons } from '@storybook/addons'
import { create } from '@storybook/theming'
import './manager.css'
import brandImage from '../public/img/ol-brand/overleaf.svg'
const theme = create({
base: 'light',
brandTitle: 'Overleaf',
brandUrl: 'https://www.overleaf.com',
brandImage,
})
addons.setConfig({ theme })

View file

@ -0,0 +1,101 @@
import type { Preview } from '@storybook/react'
// Storybook does not (currently) support async loading of "stories". Therefore
// the strategy in frontend/js/i18n.js does not work (because we cannot wait on
// the promise to resolve).
// Therefore we have to use the synchronous method for configuring
// react-i18next. Because this, we can only hard-code a single language.
import i18n from 'i18next'
import { initReactI18next } from 'react-i18next'
// @ts-ignore
import en from '../../../services/web/locales/en.json'
import { ExposedSettings } from '../types/exposed-settings'
import { User } from '../types/user'
window.i18n = window.i18n || {}
window.i18n.currentLangCode = window.i18n.currentLangCode || 'en'
i18n.use(initReactI18next).init({
lng: 'en',
// still using the v3 plural suffixes
compatibilityJSON: 'v3',
resources: {
en: { translation: en },
},
react: {
useSuspense: false,
transSupportBasicHtmlNodes: false,
},
interpolation: {
prefix: '__',
suffix: '__',
unescapeSuffix: 'HTML',
skipOnVariables: true,
escapeValue: false,
defaultVariables: {
appName: 'Overleaf',
},
},
})
// avoid some errors by creating these objects in advance
window.user = {} as User
window.ExposedSettings = {} as ExposedSettings
const preview: Preview = {
parameters: {
// Automatically mark prop-types like onClick, onToggle, etc as Storybook
// "actions", so that they are logged in the Actions pane at the bottom of the
// viewer
actions: { argTypesRegex: '^on.*' },
docs: {
// render stories in iframes, to isolate modals
inlineStories: false,
},
},
globalTypes: {
theme: {
name: 'Theme',
description: 'Editor theme',
defaultValue: 'main-',
toolbar: {
icon: 'circlehollow',
items: [
{ value: 'main-', title: 'Default' },
{ value: 'main-light-', title: 'Light' },
{ value: 'main-ieee-', title: 'IEEE' },
],
},
},
},
loaders: [
async ({ globals }) => {
const { theme } = globals
return {
// NOTE: this uses `${theme}style.less` rather than `${theme}.less`
// so that webpack only bundles files ending with "style.less"
activeStyle: await import(
`!!to-string-loader!css-loader!less-loader!../../../services/web/frontend/stylesheets/${theme}style.less`
),
}
},
],
decorators: [
(Story, context) => {
const { activeStyle } = context.loaded
return (
<>
{activeStyle && <style>{activeStyle.default}</style>}
<Story {...context} />
</>
)
},
],
}
export default preview

View file

@ -552,6 +552,15 @@ tar:
COMPOSE_PROJECT_NAME=tar_$(BUILD_DIR_NAME) $(DOCKER_COMPOSE) run --rm tar
COMPOSE_PROJECT_NAME=tar_$(BUILD_DIR_NAME) $(DOCKER_COMPOSE) down -v -t 0
build_storybook:
npm run build-storybook
if [[ -n "$(BRANCH_NAME)" ]]; then \
echo "Renaming storybook-static -> $(BRANCH_NAME)."; \
d=$$(dirname "$(BRANCH_NAME)"); \
mkdir -p "storybook-output/$$d"; \
mv storybook-static "storybook-output/$$d/$$(basename "$(BRANCH_NAME)")/"; \
fi
MODULE_TARGETS = \
$(TEST_ACCEPTANCE_MODULES_SAAS) \
$(TEST_ACCEPTANCE_MODULES_SERVER_CE) \

View file

@ -0,0 +1,78 @@
divert(`-1')
define(`foreach', `pushdef(`$1')_foreach($@)popdef(`$1')')
define(`_arg1', `$1')
define(`_foreach', `ifelse(`$2', `()', `',
`define(`$1', _arg1$2)$3`'$0(`$1', (shift$2), `$3')')')
divert`'dnl
<html lang="en">
<head>
<meta charset="utf-8">
<title>Overleaf Storybook builds</title>
<style>
body {
background-color: #fff;
color: #5d6879;
font-family: Lato,sans-serif;
font-size: 16px;
line-height: 1.5625;
min-height: 100%;
position: relative;
margin: 0px;
}
h1, h2, h3, h4, h5, h6 {
color: rgb(80, 80, 80);
font-family: Merriweather, serif;
font-weight: 500;
line-height: 1.35;
}
h1 {
margin-top: 0px;
padding-top: 100px;
}
.navbar-default {
background-color: #1e2530;
border-color: transparent;
height: 68px;
padding: 15px 10px;
position: absolute;
top: 0;
width: 100%;
box-sizing: border-box;
display: block;
}
.navbar-default .navbar-brand {
background-image: url(https://cdn.overleaf.com/images/overleaf-white-65b70e33f35fccdf6f8d.svg);
background-position: 0;
background-repeat: no-repeat;
background-size: contain;
bottom: 5px;
padding: 0;
position: absolute;
top: 5px;
width: 130px;
}
</style>
</head>
<body>
<nav class="navbar-default">
<a class="navbar-brand" href="https://www.overleaf.com/"></a>
</nav>
<h1>Overleaf Storybook builds</h1>
<h2>Branches:</h2>
<ul>
foreach(DIR, (LIST),
<li>
<a href="DIR/">DIR/</a>
<a href="https://github.com/overleaf/internal/tree/DIR">
<img src="https://github.com/favicon.ico" alt="GitHub" width="15em">
</a>
</li>
)
</ul>
<small>
Last updated on syscmd(date)dnl
for ifdef(`BRANCH_NAME',<a href="BRANCH_NAME/">BRANCH_NAME</a>,unknown branch)
(<a href="https://console.cloud.google.com/cloud-build/builds?project=overleaf-dev&pageState=(%22builds%22:(%22f%22:%22%255B%257B_22k_22_3A_22Trigger%2520Name_22_2C_22t_22_3A10_2C_22v_22_3A_22_5C_22storybook-pr-trigger_5C_22_22_2C_22s_22_3Atrue_2C_22i_22_3A_22triggerName_22%257D_2C%257B_22k_22_3A_22_22_2C_22t_22_3A10_2C_22v_22_3A_22_5C_22OR_5C_22_22_2C_22o_22_3Atrue_2C_22s_22_3Atrue%257D_2C%257B_22k_22_3A_22Trigger%2520Name_22_2C_22t_22_3A10_2C_22v_22_3A_22_5C_22storybook-push-trigger_5C_22_22_2C_22s_22_3Atrue_2C_22i_22_3A_22triggerName_22%257D%255D%22))">build history</a>).
</small>
</body>
</html>

View file

@ -0,0 +1,63 @@
steps:
- id: build-storybook
name: 'node:18.18.2'
env:
- 'BRANCH_NAME=$BRANCH_NAME'
- 'BUILD_ID=$BUILD_ID'
script: |
#!/bin/bash
set -e
make -C services/web BRANCH_NAME="${BRANCH_NAME:-$BUILD_ID}" build_storybook
- id: deploy-storybook
name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
env:
- 'BRANCH_NAME=$BRANCH_NAME'
- 'BUILD_ID=$BUILD_ID'
- 'BUCKET=gs://overleaf-dev-storybook'
dir: services/web
script: |
#!/bin/bash
: ${BRANCH_NAME:=$BUILD_ID}
[[ "$BRANCH_NAME" ]] || {
echo 1>&2 "ERROR: BRANCH_NAME not set"
exit 2
}
gsutil -m copy -r storybook-output/* "${BUCKET}/"
waitFor:
- build-storybook
- id: read-storybook-bucket
name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
dir: services/web
env:
- 'BUCKET=gs://overleaf-dev-storybook'
script: |
#!/bin/bash
set -ex
gsutil ls "${BUCKET}/" \
| sed -E "s@^${BUCKET}/([^/]+)/@\1@" \
> storybook-bucket-listing.txt
waitFor:
- deploy-storybook
- id: create-storybook-index
name: 'node:18.18.2'
dir: services/web
env:
- 'BRANCH_NAME=$BRANCH_NAME'
script: |
#!/bin/bash
set -ex
LIST=$(tr '\n' , < storybook-bucket-listing.txt)
m4 -DLIST="$LIST" -DBRANCH_NAME="$BRANCH_NAME" cloudbuild-storybook-index.html.m4 > storybook-index.html
waitFor:
- read-storybook-bucket
- id: update-storybook-index
name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
dir: services/web
entrypoint: 'gsutil'
args: [ "copy", "storybook-index.html", "gs://overleaf-dev-storybook/index.html" ]
waitFor:
- create-storybook-index

View file

@ -39,6 +39,8 @@
"lezer-latex:benchmark": "node scripts/lezer-latex/benchmark.mjs",
"lezer-latex:benchmark-incremental": "node scripts/lezer-latex/test-incremental-parser.mjs",
"routes": "bin/routes",
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build",
"local:nodemon": "set -a;. ../../config/dev-environment.env;. ./docker-compose.common.env;. ../../config/local-dev.env;. ./local-dev.env;. ../../config/local.env; set +a; echo $SHARELATEX_CONFIG; WEB_PORT=13000 LISTEN_ADDRESS=0.0.0.0 npm run nodemon",
"local:webpack": "set -a;. ../../config/dev-environment.env;. ./docker-compose.common.env;. ../../config/local-dev.env;. ./local-dev.env;. ../../config/local.env; set +a; PORT=13808 SHARELATEX_CONFIG=$(pwd)/config/settings.webpack.js npm run webpack",
"local:test:acceptance:run_dir": "set -a;. $(pwd)/docker-compose.common.env;. $(pwd)/local-test.env; set +a; npm run test:acceptance:run_dir",
@ -211,6 +213,15 @@
"@replit/codemirror-indentation-markers": "overleaf/codemirror-indentation-markers#1b1f93c0bcd04293aea6986aa2275185b2c56803",
"@replit/codemirror-vim": "overleaf/codemirror-vim#07f1b50f4b2e703792da75a29e9e1e479b6b7067",
"@sentry/browser": "^7.8.1",
"@storybook/addon-a11y": "^7.5.1",
"@storybook/addon-essentials": "^7.5.1",
"@storybook/addon-interactions": "^7.5.1",
"@storybook/addon-links": "^7.5.1",
"@storybook/addons": "^7.5.1",
"@storybook/blocks": "^7.5.1",
"@storybook/react": "^7.5.1",
"@storybook/react-webpack5": "^7.5.1",
"@storybook/testing-library": "^0.2.2",
"@testing-library/cypress": "^10.0.1",
"@testing-library/dom": "^9.3.0",
"@testing-library/react": "^12.1.5",
@ -332,6 +343,7 @@
"sinon-chai": "^3.7.0",
"sinon-mongoose": "^2.3.0",
"socket.io-mock": "^1.3.1",
"storybook": "^7.4.0",
"strict-event-emitter": "^0.5.1",
"terser-webpack-plugin": "^5.3.9",
"thread-loader": "^4.0.2",

View file

@ -23,6 +23,7 @@
"modules/**/test/frontend/**/*.*",
"frontend/stories/**/*.*",
"modules/**/stories/**/*.*",
".storybook/*.*",
"cypress",
"types"
],