Add Billing Feature (#238)

* Add Billing Feature
* Update storybook
This commit is contained in:
Alexey Kontsevoy 2021-03-11 13:33:02 -05:00 committed by GitHub
parent f681184bcc
commit d58d2c1fa6
38 changed files with 3054 additions and 2443 deletions

View file

@ -21,11 +21,11 @@ const createConfig = require('@gravitational/build/webpack/webpack.base');
const webpackCfg = createConfig();
// include open source stories
const stories = ['../packages/**/*.story.(js|jsx|ts|tsx)'];
const stories = ['../packages/**/*.story.@(js|jsx|ts|tsx)'];
// include enterprise stories if available (**/* pattern ignores dot dir names)
if (fs.existsSync(path.join(__dirname, '/../packages/webapps.e/'))) {
stories.unshift('../packages/webapps.e/**/*.story.(js|jsx|ts|tsx)');
stories.unshift('../packages/webapps.e/**/*.story@(js|jsx|ts|tsx)');
}
module.exports = {

View file

@ -27,19 +27,15 @@ const ThemeDecorator = storyFn => (
</ThemeProvider>
);
// alphabetically sort stories
function storySort(a, b) {
return a[1].kind === b[1].kind
? 0
: a[1].id.localeCompare(b[1].id, undefined, { numeric: true });
}
addDecorator(ThemeDecorator);
addParameters({
options: {
showPanel: false,
showNav: true,
isToolshown: true,
storySort,
storySort: {
method: 'alphabetical',
order: ['Teleport', 'TeleportE', 'Design', 'Shared', 'Gravity'],
},
},
});

View file

@ -36,15 +36,6 @@ if (!urlObj.host) {
const PROXY_TARGET = urlObj.host;
const ROOT = '/web';
const PORT = '8080';
const WEBPACK_CLIENT_ENTRY =
'webpack-dev-server/client?https://0.0.0.0:' + PORT;
const WEBPACK_SRV_ENTRY = 'webpack/hot/dev-server';
// setup webpack config with hot-reloading
for (var prop in webpackConfig.entry) {
webpackConfig.entry[prop].unshift('react-hot-loader/patch');
webpackConfig.entry[prop].unshift(WEBPACK_CLIENT_ENTRY, WEBPACK_SRV_ENTRY);
}
// init webpack compiler
const compiler = initCompiler({ webpackConfig });
@ -83,6 +74,7 @@ const server = new WebpackDevServer(compiler.webpackCompiler, {
publicPath: ROOT + '/app',
hot: true,
disableHostCheck: true,
serveIndex: false,
https: true,
inline: true,
headers: { 'X-Custom-Header': 'yes' },
@ -126,6 +118,5 @@ function serveIndexHtml() {
};
}
server.app.get(ROOT + '/*', serveIndexHtml());
server.app.get(ROOT, serveIndexHtml());
server.app.get('/*', serveIndexHtml());
server.listen(PORT, '0.0.0.0', function() {});

View file

@ -14,17 +14,17 @@
"g-build": "./bin/g-build.js"
},
"dependencies": {
"@babel/core": "^7.7.2",
"@babel/plugin-proposal-class-properties": "^7.7.0",
"@babel/plugin-proposal-object-rest-spread": "^7.6.2",
"@babel/plugin-syntax-dynamic-import": "^7.2.0",
"@babel/plugin-proposal-optional-chaining": "^7.2.0",
"@babel/plugin-transform-classes": "^7.7.0",
"@babel/preset-env": "^7.7.1",
"@babel/preset-react": "^7.7.0",
"@babel/preset-typescript": "^7.7.2",
"@babel/core": "^7.11.0",
"@babel/plugin-proposal-class-properties": "^7.11.0",
"@babel/plugin-proposal-object-rest-spread": "^7.11.2",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/plugin-proposal-optional-chaining": "^7.11.0",
"@babel/plugin-transform-classes": "^7.11.0",
"@babel/preset-env": "^7.11.1",
"@babel/preset-react": "^7.11.0",
"@babel/preset-typescript": "^7.11.0",
"@hot-loader/react-dom": "^16.11.0",
"@storybook/react": "^5.3.0",
"@storybook/react": "^6.1.0",
"@testing-library/react": "9.4.0",
"@testing-library/jest-dom": "5.1.0",
"@types/jest": "^24.0.13",
@ -72,6 +72,6 @@
"webpack-bundle-analyzer": "^3.3.2",
"clean-webpack-plugin": "3.0.0",
"webpack-cli": "3.3.2",
"webpack-dev-server": "3.1.11"
"webpack-dev-server": "3.10.3"
}
}
}

View file

@ -24,7 +24,7 @@ import Dialog, {
import { ButtonPrimary, Input, LabelInput } from './..';
export default {
title: 'Design/Dialog',
title: 'Design/Dialog/Basic',
};
export const Basic = () => (

View file

@ -24,7 +24,7 @@ import DialogConfirmation, {
import { ButtonPrimary } from './../Button';
export default {
title: 'Design/Dialog',
title: 'Design/Dialog/Confirmation',
};
export const Confirmation = () => (

View file

@ -22,7 +22,7 @@ import { Flex, Box } from '..';
import { getContrastText } from './theme';
export default {
title: 'Design/Theme',
title: 'Design/Theme/Palette',
};
export const Palette = () => <Color />;

View file

@ -19,7 +19,7 @@ import { Flex, Box, Text } from '..';
import theme from './theme';
export default {
title: 'Design/Theme',
title: 'Design/Theme/Colors',
};
export const Colors = () => {

View file

@ -19,7 +19,7 @@ import typography from './typography';
import { Text, Box } from './../';
export default {
title: 'Design/Theme',
title: 'Design/Theme/Typography',
};
export const Typography = () => (

File diff suppressed because one or more lines are too long

View file

@ -14,52 +14,58 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React from 'react'
import React from 'react';
import $ from 'jQuery';
import { storiesOf } from '@storybook/react'
import { storiesOf } from '@storybook/react';
import { StepProgress } from './StepProgress';
storiesOf('GravityInstaller', module)
storiesOf('Gravity/Installer', module)
.add('StepProgress', () => {
const props = {
...defaultProps,
}
};
return (
<StepProgress height="300px" {...props}
logProvider={ <MockLogProvider /> }
<StepProgress
height="300px"
{...props}
logProvider={<MockLogProvider />}
/>
)}
)
);
})
.add('StepProgress-Completed', () => {
const props = {
...defaultProps,
progress: {
...defaultProps.progress,
isCompleted: true
}
}
isCompleted: true,
},
};
return (
<StepProgress height="300px" {...props}
logProvider={ <MockLogProvider /> }
<StepProgress
height="300px"
{...props}
logProvider={<MockLogProvider />}
/>
)}
)
);
})
.add('StepProgress-Failed', () => {
const props = {
...defaultProps,
progress: {
...defaultProps.progress,
isError: true
}
}
isError: true,
},
};
return (
<StepProgress height="300px" {...props}
logProvider={ <MockLogProvider /> }
<StepProgress
height="300px"
{...props}
logProvider={<MockLogProvider />}
/>
)}
);
);
});
const defaultProps = {
onFetch: $.Deferred(),
@ -69,10 +75,10 @@ const defaultProps = {
step: 3,
isError: '',
isCompleted: '',
crashReportUrl: ''
crashReportUrl: '',
},
}
};
const MockLogProvider = () => {
return null;
}
};

View file

@ -31,6 +31,4 @@ export const Button = () => (
</div>
);
Button.story = {
name: 'ButtonSso',
};
Button.storyName = 'ButtonSso';

View file

@ -28,6 +28,7 @@ export default function FieldSelect({
maxMenuHeight,
clearable,
isMulti,
menuPosition,
rule = defaultRule,
isSearchable = false,
isSimpleValue = false,
@ -42,6 +43,7 @@ export default function FieldSelect({
<Box mb="4" {...styles}>
{label && <LabelInput hasError={hasError}>{labelText}</LabelInput>}
<Select
menuPosition={menuPosition}
hasError={hasError}
isSimpleValue={isSimpleValue}
isSearchable={isSearchable}

View file

@ -61,9 +61,7 @@ export function U2f() {
return <FormInvite {...props} />;
}
U2f.story = {
name: 'U2f',
};
U2f.storyName = 'U2f';
export function U2fError() {
const props = {
@ -79,9 +77,7 @@ export function U2fError() {
return <FormInvite {...props} />;
}
U2fError.story = {
name: 'U2fError',
};
U2fError.storyName = 'U2fError';
const userToken = {
user: 'test@gravitational.com',

View file

@ -37,9 +37,7 @@ export function Story({ value }: { value: teleport.Context }) {
);
}
Story.story = {
name: 'Clusters',
};
Story.storyName = 'Clusters';
export function createContext() {
const ctx = new teleport.Context();

View file

@ -24,7 +24,7 @@ import { colors } from './colors';
import ConsoleContext from './consoleContext';
import ConsoleContextProvider from './consoleContextProvider';
storiesOf('TeleportConsole', module).add('Console', () => {
storiesOf('Teleport/Console', module).add('Console', () => {
const ctx = new ConsoleContext();
return (
<TestLayout ctx={ctx}>

View file

@ -20,7 +20,7 @@ import DocumentBlank from './DocumentBlank';
import { TestLayout } from './../Console.story';
export default {
title: 'TeleportConsole/DocumentBlank',
title: 'Teleport/Console/DocumentBlank',
};
export const Blank = () => (

View file

@ -21,7 +21,7 @@ import ClusterSelector from './ClusterSelector';
import ThemeProvider from './../ThemeProvider';
export default {
title: 'TeleportConsole/DocumentNodes/ClusterSelector',
title: 'Teleport/Console/DocumentNodes/ClusterSelector',
};
export const Component = () => {

View file

@ -20,7 +20,7 @@ import ConsoleCtx from './../consoleContext';
import { TestLayout } from './../Console.story';
export default {
title: 'TeleportConsole/DocumentNodes',
title: 'Teleport/Console/DocumentNodes',
excludeStories: ['createContext'],
};

View file

@ -71,7 +71,7 @@ export const ServerError = () => {
};
export default {
title: 'TeleportConsole/DocumentSsh',
title: 'Teleport/Console/DocumentSsh',
};
const doc = {

View file

@ -18,7 +18,7 @@ import React from 'react';
import Component from './ShareSession';
export default {
title: 'TeleportConsole/DocumentSsh',
title: 'Teleport/Console/DocumentSsh/ShareSession',
};
export const ShareSession = () => <Component closeShareSession={() => null} />;

View file

@ -21,7 +21,7 @@ import { Scp } from './scpContext';
import { Uploader, Downloader } from 'teleport/Console/services/fileTransfer';
export default {
title: 'TeleportConsole/FileTransfer',
title: 'Teleport/Console/FileTransfer',
};
const props = {

View file

@ -18,7 +18,7 @@ import React from 'react';
import UploadForm from './UploadForm';
export default {
title: 'TeleportConsole/FileTransfer',
title: 'Teleport/Console/FileTransfer/UploadWithFiles',
};
export const UploadWithFiles = () => {

View file

@ -18,7 +18,7 @@ import React from 'react';
import Component from './JoinedUsers';
export default {
title: 'TeleportConsole',
title: 'Teleport/Console/JoinedUsers',
};
export const JoinedUsers = () => {

View file

@ -19,7 +19,7 @@ import Tabs from './Tabs';
import { TestLayout } from './../Console.story';
export default {
title: 'TeleportConsole',
title: 'Teleport/Console',
};
export const ConsoleTabs = () => (
@ -37,9 +37,7 @@ export const ConsoleTabs = () => (
</TestLayout>
);
ConsoleTabs.story = {
name: 'Tabs',
};
ConsoleTabs.storyName = 'Tabs';
const parties = {
'16': [{ user: 'jiawu@ninu.fo' }, { user: 'gigbu@fe.ac' }],

View file

@ -28,10 +28,6 @@ import { sessions } from 'teleport/Sessions/fixtures';
import { apps } from 'teleport/Apps/fixtures';
import { userContext } from './fixtures';
export default {
title: 'Teleport/Main',
};
export function OSS() {
const state = useMainStory();
return (
@ -45,6 +41,12 @@ export function OSS() {
);
}
OSS.storyName = 'Main';
export default {
title: 'Teleport/Main',
};
function useMainStory() {
const [history] = React.useState(() => {
return createMemoryHistory({

View file

@ -15,7 +15,7 @@ limitations under the License.
*/
import * as RouterDOM from 'react-router-dom';
import React from 'react';
import React, { Suspense } from 'react';
import styled from 'styled-components';
import { Indicator } from 'design';
import { Failed } from 'design/CardError';
@ -55,7 +55,9 @@ export function Main(props: State) {
return (
<Route title={title} key={index} path={path} exact={exact}>
<CatchError>
<Cmpt />
<Suspense fallback={null}>
<Cmpt />
</Suspense>
</CatchError>
</Route>
);

View file

@ -17,14 +17,16 @@ limitations under the License.
import React from 'react';
import DeleteRole from './DeleteRole';
export const DeleteRoleDialog = () => <DeleteRole {...props} />;
DeleteRoleDialog.story = {
name: 'Teleport/Roles/Delete',
export default {
title: 'Teleport/Roles/DeleteRole',
};
export const DeleteRoleDialog = () => <DeleteRole {...props} />;
DeleteRoleDialog.storyName = 'Confirm';
const props = {
name: 'sample-role',
name: 'sample-role3',
onDelete: () => {
return Promise.reject(new Error('server error'));
},

View file

@ -14,6 +14,8 @@
* limitations under the License.
*/
import Support from './Support';
import React from 'react';
const Support = React.lazy(() => import('./Support'));
export default Support;

View file

@ -59,6 +59,4 @@ const defaultProps = {
logout: () => null,
};
Story.story = {
name: 'TopBar',
};
Story.storyName = 'TopBar';

View file

@ -21,13 +21,7 @@ export default {
title: 'Teleport/TrustedClusters/Delete',
};
export const DeleteTrustedClusterDialog = () => (
<DeleteTrustedCluster {...props} />
);
DeleteTrustedClusterDialog.story = {
name: 'DeleteDialog',
};
export const Comfirm = () => <DeleteTrustedCluster {...props} />;
const props = {
name: 'sample-trusted-cluster',

View file

@ -29,6 +29,7 @@ export default function makeAcl(json): Acl {
const appServers = json.appServers || defaultAccess;
const tokens = json.tokens || defaultAccess;
const accessRequests = json.accessRequests || defaultAccess;
const billing = json.billing || defaultAccess;
return {
logins,
@ -41,6 +42,7 @@ export default function makeAcl(json): Acl {
appServers,
tokens,
accessRequests,
billing,
};
}

View file

@ -51,6 +51,7 @@ export interface Acl {
tokens: Access;
appServers: Access;
accessRequests: Access;
billing: Access;
}
export interface User {

View file

@ -63,6 +63,7 @@ test('fetch user context, null response gives proper default values', async () =
appServers: defaultAccess,
tokens: defaultAccess,
accessRequests: defaultAccess,
billing: defaultAccess,
});
expect(response.accessStrategy).toStrictEqual(defaultStrategy);

View file

@ -65,6 +65,10 @@ export default class StoreUserContext extends Store<UserContext> {
return this.state.acl.accessRequests;
}
getBillingAccess() {
return this.state.acl.billing;
}
getAccessStrategy() {
return this.state.accessStrategy;
}

View file

@ -60,6 +60,7 @@ class TeleportContext implements types.Context {
trustedClusters: userContext.getTrustedClusterAccess().list,
users: userContext.getUserAccess().list,
applications: userContext.getAppServerAccess().list,
billing: userContext.getBillingAccess().list,
};
}
}

@ -1 +1 @@
Subproject commit 4aa311d97d1770fb461238592e36235c40621cca
Subproject commit 91a38dc487871504224bc490f8c762206e29b243

File diff suppressed because it is too large Load diff