Leszek Wiesner преди 4 години
родител
ревизия
03bd123c9a
променени са 89 файла, в които са добавени 801 реда и са изтрити 573 реда
  1. 3 1
      package.json
  2. 0 1
      pioneer/.eslintignore
  3. 3 0
      pioneer/packages/apps-routing/src/index.ts
  4. 15 0
      pioneer/packages/apps-routing/src/joy-media.ts
  5. 0 0
      pioneer/packages/apps/public/images/default-thumbnail.png
  6. 1 0
      pioneer/packages/apps/public/locales/en/index.json
  7. 4 1
      pioneer/packages/apps/public/locales/en/joy-utils.json
  8. 0 1
      pioneer/packages/apps/src/Content/index.tsx
  9. 3 0
      pioneer/packages/apps/webpack.base.config.js
  10. 0 0
      pioneer/packages/joy-media/.skip-build
  11. 2 0
      pioneer/packages/joy-media/aplayer.d.ts
  12. 2 0
      pioneer/packages/joy-media/dplayer.d.ts
  13. 4 4
      pioneer/packages/joy-media/package.json
  14. 1 1
      pioneer/packages/joy-media/src/DiscoveryProvider.tsx
  15. 8 4
      pioneer/packages/joy-media/src/MediaView.tsx
  16. 25 11
      pioneer/packages/joy-media/src/Upload.tsx
  17. 1 1
      pioneer/packages/joy-media/src/channels/ChannelAvatar.tsx
  18. 4 4
      pioneer/packages/joy-media/src/channels/ChannelPreview.tsx
  19. 4 3
      pioneer/packages/joy-media/src/channels/ChannelsByOwner.view.tsx
  20. 23 17
      pioneer/packages/joy-media/src/channels/CurationPanel.tsx
  21. 23 25
      pioneer/packages/joy-media/src/channels/EditChannel.tsx
  22. 4 3
      pioneer/packages/joy-media/src/channels/EditChannel.view.tsx
  23. 1 1
      pioneer/packages/joy-media/src/channels/ViewChannel.tsx
  24. 4 3
      pioneer/packages/joy-media/src/channels/ViewChannel.view.tsx
  25. 1 1
      pioneer/packages/joy-media/src/channels/ViewMusicChannel.tsx
  26. 1 1
      pioneer/packages/joy-media/src/channels/ViewVideoChannel.tsx
  27. 2 2
      pioneer/packages/joy-media/src/common/MediaForms.tsx
  28. 3 3
      pioneer/packages/joy-media/src/common/MediaPlayerView.tsx
  29. 5 22
      pioneer/packages/joy-media/src/common/MediaPlayerWithResolver.tsx
  30. 4 3
      pioneer/packages/joy-media/src/common/TypeHelpers.ts
  31. 2 0
      pioneer/packages/joy-media/src/common/images.tsx
  32. 0 0
      pioneer/packages/joy-media/src/common/index.scss
  33. 1 1
      pioneer/packages/joy-media/src/explore/AllChannels.tsx
  34. 1 1
      pioneer/packages/joy-media/src/explore/AllVideos.tsx
  35. 1 1
      pioneer/packages/joy-media/src/explore/ExploreContent.tsx
  36. 1 1
      pioneer/packages/joy-media/src/explore/PlayContent.tsx
  37. 5 3
      pioneer/packages/joy-media/src/index.scss
  38. 6 5
      pioneer/packages/joy-media/src/index.tsx
  39. 2 3
      pioneer/packages/joy-media/src/music/EditMusicAlbum.tsx
  40. 1 1
      pioneer/packages/joy-media/src/music/MusicAlbumPreview.tsx
  41. 1 1
      pioneer/packages/joy-media/src/music/MusicAlbumTracks.tsx
  42. 2 2
      pioneer/packages/joy-media/src/music/MyMusicTracks.tsx
  43. 14 14
      pioneer/packages/joy-media/src/schemas/channel/Channel.ts
  44. 1 1
      pioneer/packages/joy-media/src/stories/ExploreContent.stories.tsx
  45. 3 3
      pioneer/packages/joy-media/src/stories/MusicAlbumTracks.stories.tsx
  46. 1 1
      pioneer/packages/joy-media/src/stories/MusicChannel.stories.tsx
  47. 4 5
      pioneer/packages/joy-media/src/stories/MyChannels.stories.tsx
  48. 1 1
      pioneer/packages/joy-media/src/stories/MyMusicAlbums.stories.tsx
  49. 3 3
      pioneer/packages/joy-media/src/stories/Playback.stories.tsx
  50. 3 3
      pioneer/packages/joy-media/src/stories/UploadAudio.stories.tsx
  51. 3 3
      pioneer/packages/joy-media/src/stories/UploadVideo.stories.tsx
  52. 4 4
      pioneer/packages/joy-media/src/stories/data/AccountIdSamples.ts
  53. 7 9
      pioneer/packages/joy-media/src/stories/data/ChannelSamples.ts
  54. 15 14
      pioneer/packages/joy-media/src/transport.mock.ts
  55. 10 13
      pioneer/packages/joy-media/src/transport.substrate.ts
  56. 6 6
      pioneer/packages/joy-media/src/transport.ts
  57. 6 5
      pioneer/packages/joy-media/src/upload/EditVideo.view.tsx
  58. 2 3
      pioneer/packages/joy-media/src/upload/UploadAudio.tsx
  59. 26 24
      pioneer/packages/joy-media/src/upload/UploadVideo.tsx
  60. 4 2
      pioneer/packages/joy-media/src/video/PlayVideo.tsx
  61. 6 6
      pioneer/packages/joy-media/src/video/PlayVideo.view.tsx
  62. 2 2
      pioneer/packages/joy-media/src/video/VideoPreview.tsx
  63. 4 4
      pioneer/packages/joy-utils/src/react/components/InputFileAsync.tsx
  64. 1 1
      pioneer/packages/joy-utils/src/react/components/JoyStatus.tsx
  65. 0 0
      pioneer/packages/joy-utils/src/react/components/Pluralize.tsx
  66. 4 1
      pioneer/packages/joy-utils/src/react/components/index.tsx
  67. 111 6
      pioneer/packages/joy-utils/src/react/hocs/accounts.tsx
  68. 1 30
      pioneer/packages/joy-utils/src/react/hocs/guards.tsx
  69. 1 1
      pioneer/packages/joy-utils/src/react/hooks/proposals/useProposalSubscription.tsx
  70. 4 1
      pioneer/packages/joy-utils/src/transport/SimpleCache.ts
  71. 16 14
      pioneer/packages/joy-utils/src/transport/base.ts
  72. 14 12
      pioneer/packages/joy-utils/src/transport/mock/base.ts
  73. 4 0
      pioneer/packages/joy-utils/src/transport/workingGroups.ts
  74. 0 0
      pioneer/packages/joy-utils/src/types/ValidationConstraint.ts
  75. 0 17
      pioneer/packages/old-apps/apps-routing/src/joy-media.ts
  76. 0 1
      pioneer/packages/old-apps/apps/src/aplayer.d.ts
  77. 0 1
      pioneer/packages/old-apps/apps/src/dplayer.d.ts
  78. 5 0
      pioneer/packages/react-components/src/styles/joystream.ts
  79. 4 1
      pioneer/tsconfig.json
  80. 26 26
      types/augment-codec/augment-types.ts
  81. 20 20
      types/augment/all/defs.json
  82. 20 20
      types/augment/all/types.ts
  83. 0 50
      types/augment/augment-api-consts.ts
  84. 4 29
      types/augment/augment-api-query.ts
  85. 2 47
      types/augment/augment-api-tx.ts
  86. 6 6
      types/src/content-working-group/index.ts
  87. 1 1
      types/src/index.ts
  88. 2 2
      types/src/versioned-store/index.ts
  89. 256 28
      yarn.lock

+ 3 - 1
package.json

@@ -29,6 +29,7 @@
     "pioneer/packages/joy-election",
     "pioneer/packages/joy-proposals",
     "pioneer/packages/joy-roles",
+    "pioneer/packages/joy-media",
     "utils/api-examples"
   ],
   "resolutions": {
@@ -40,7 +41,8 @@
     "@polkadot/util-crypto": "3.0.1",
     "@polkadot/wasm-crypto": "1.2.1",
     "babel-core": "^7.0.0-bridge.0",
-    "typescript": "^3.9.7"
+    "typescript": "^3.9.7",
+    "bn.js": "^5.1.2"
   },
   "devDependencies": {
     "husky": "^4.2.5",

+ 0 - 1
pioneer/.eslintignore

@@ -4,7 +4,6 @@
 packages/old-apps/*
 packages/joy-forum/*
 packages/joy-help/*
-packages/joy-media/*
 packages/joy-settings/*
 packages/joy-utils-old/*
 .eslintrc.js

+ 3 - 0
pioneer/packages/apps-routing/src/index.ts

@@ -23,10 +23,12 @@ import { terms, privacyPolicy } from './joy-pages';
 import election from './joy-election';
 import proposals from './joy-proposals';
 import roles from './joy-roles';
+import media from './joy-media';
 
 export default function create (t: <T = string> (key: string, text: string, options: { ns: string }) => T): Routes {
   return appSettings.uiMode === 'light'
     ? [
+      media(t),
       members(t),
       roles(t),
       election(t),
@@ -37,6 +39,7 @@ export default function create (t: <T = string> (key: string, text: string, opti
       settings(t)
     ]
     : [
+      media(t),
       members(t),
       roles(t),
       election(t),

+ 15 - 0
pioneer/packages/apps-routing/src/joy-media.ts

@@ -0,0 +1,15 @@
+import Media from '@polkadot/joy-media/index';
+
+import { Route } from './types';
+
+export default function create (t: <T = string> (key: string, text: string, options: { ns: string }) => T): Route {
+  return {
+    Component: Media,
+    display: {
+      needsApi: ['query.storageWorkingGroup.workerById', 'query.dataObjectStorageRegistry.relationshipsByContentId']
+    },
+    text: t<string>('nav.media', 'Media', { ns: 'apps-routing' }),
+    icon: 'play-circle',
+    name: 'media'
+  };
+}

+ 0 - 0
pioneer/packages/old-apps/apps/public/images/default-thumbnail.png → pioneer/packages/apps/public/images/default-thumbnail.png


+ 1 - 0
pioneer/packages/apps/public/locales/en/index.json

@@ -25,6 +25,7 @@
   "joy-media.json",
   "joy-members.json",
   "joy-roles.json",
+  "joy-utils.json",
   "react-components.json",
   "react-params.json",
   "react-query.json",

+ 4 - 1
pioneer/packages/apps/public/locales/en/joy-utils.json

@@ -1 +1,4 @@
-{}
+{
+  "click to select or drag and drop the file here": "click to select or drag and drop the file here",
+  "{{name}} ({{size}} bytes)": "{{name}} ({{size}} bytes)"
+}

+ 0 - 1
pioneer/packages/apps/src/Content/index.tsx

@@ -97,7 +97,6 @@ function Content ({ className }: Props): React.ReactElement<Props> {
 }
 
 export default React.memo(styled(Content)`
-  background: rgba(250, 250, 250);
   padding: 0 1.5rem;
   position: relative;
   width: 100%;

+ 3 - 0
pioneer/packages/apps/webpack.base.config.js

@@ -48,6 +48,9 @@ function createWebpack (ENV, context) {
     return alias;
   }, {});
 
+  // Add @joystream/types as alias to automatically process any changes:
+  alias['@joystream/types'] = path.resolve(context, `../../../types/src`);
+
   return {
     context,
     entry: ['@babel/polyfill', './src/index.tsx'],

+ 0 - 0
pioneer/packages/joy-media/.skip-build


+ 2 - 0
pioneer/packages/joy-media/aplayer.d.ts

@@ -0,0 +1,2 @@
+// No offical definitions available
+declare module 'react-aplayer';

+ 2 - 0
pioneer/packages/joy-media/dplayer.d.ts

@@ -0,0 +1,2 @@
+// No offical definitions available
+declare module 'react-dplayer';

+ 4 - 4
pioneer/packages/joy-media/package.json

@@ -7,14 +7,14 @@
   "author": "Joystream contributors",
   "maintainers": [],
   "dependencies": {
-    "@babel/runtime": "^7.7.1",
+    "@babel/runtime": "^7.10.5",
     "@polkadot/joy-utils": "^0.1.1",
-    "@polkadot/react-components": "0.37.0-beta.63",
-    "@polkadot/react-query": "0.37.0-beta.63",
+    "@polkadot/react-components": "0.51.1",
+    "@polkadot/react-query": "0.51.1",
     "@types/mime-types": "^2.1.0",
     "@types/react-beautiful-dnd": "^11.0.3",
     "aplayer": "^1.10.1",
-    "dplayer": "^1.25.0",
+    "dplayer": "1.25.0",
     "ipfs-only-hash": "^1.0.2",
     "iso-639-1": "^2.1.0",
     "lodash": "^4.17.11",

+ 1 - 1
pioneer/packages/joy-media/src/DiscoveryProvider.tsx

@@ -7,7 +7,7 @@ import { Vec } from '@polkadot/types';
 import { Url } from '@joystream/types/discovery';
 import ApiContext from '@polkadot/react-api/ApiContext';
 import { ApiProps } from '@polkadot/react-api/types';
-import { JoyInfo } from '@polkadot/joy-utils/JoyStatus';
+import { JoyInfo } from '@polkadot/joy-utils/react/components';
 import { componentName } from '@polkadot/joy-utils/react/helpers';
 
 export type BootstrapNodes = {

+ 8 - 4
pioneer/packages/joy-media/src/MediaView.tsx

@@ -1,9 +1,11 @@
 import React, { useState, useEffect } from 'react';
 import { MediaTransport } from './transport';
 import { MemberId } from '@joystream/types/members';
-import { useMyMembership } from '@polkadot/joy-utils/MyMembershipContext';
+import { useMyMembership } from '@polkadot/joy-utils/react/hooks';
 import { useTransportContext } from './TransportContext';
-import { withMembershipRequired } from '@polkadot/joy-utils/MyAccount';
+import { withMembershipRequired } from '@polkadot/joy-utils/react/hocs/guards';
+import { useApi } from '@polkadot/react-hooks';
+import { ApiPromise } from '@polkadot/api';
 
 type InitialPropsWithMembership<A> = A & {
   myAddress?: string;
@@ -12,6 +14,7 @@ type InitialPropsWithMembership<A> = A & {
 
 type ResolverProps<A> = InitialPropsWithMembership<A> & {
   transport: MediaTransport;
+  api: ApiPromise;
 }
 
 type BaseProps<A, B> = {
@@ -39,13 +42,14 @@ function serializeTrigger (val: any): any {
   }
 }
 
-export function MediaView<A = {}, B = {}> (baseProps: BaseProps<A, B>) {
+export function MediaView<A extends Record<string, unknown> = Record<string, unknown>, B extends Record<string, unknown> = Record<string, unknown>> (baseProps: BaseProps<A, B>) {
   function InnerView (initialProps: A & B) {
     const { component: Component, resolveProps, triggers = [], unresolvedView = null } = baseProps;
 
     const transport = useTransportContext();
     const { myAddress, myMemberId } = useMyMembership();
-    const resolverProps = { ...initialProps, transport, myAddress, myMemberId };
+    const { api } = useApi();
+    const resolverProps = { ...initialProps, transport, api, myAddress, myMemberId };
 
     const [resolvedProps, setResolvedProps] = useState({} as B);
     const [propsResolved, setPropsResolved] = useState(false);

+ 25 - 11
pioneer/packages/joy-media/src/Upload.tsx

@@ -4,7 +4,8 @@ import axios, { CancelTokenSource } from 'axios';
 import { History } from 'history';
 import { Progress, Message } from 'semantic-ui-react';
 
-import { InputFileAsync } from '@polkadot/react-components/index';
+import { mockRegistry } from '@joystream/types';
+import { InputFileAsync } from '@polkadot/joy-utils/react/components';
 import { ApiProps } from '@polkadot/react-api/types';
 import { I18nProps } from '@polkadot/react-components/types';
 import { SubmittableResult } from '@polkadot/api';
@@ -15,15 +16,17 @@ import { formatNumber } from '@polkadot/util';
 import translate from './translate';
 import { fileNameWoExt } from './utils';
 import { ContentId, DataObject } from '@joystream/types/media';
-import { withOnlyMembers, MyAccountProps } from '@polkadot/joy-utils/MyAccount';
+import { MyAccountProps } from '@polkadot/joy-utils/react/hocs/accounts';
+import { withOnlyMembers } from '@polkadot/joy-utils/react/hocs/guards';
 import { DiscoveryProviderProps, withDiscoveryProvider } from './DiscoveryProvider';
-import TxButton from '@polkadot/joy-utils/TxButton';
+import { TxButton } from '@polkadot/joy-utils/react/components';
 import IpfsHash from 'ipfs-only-hash';
 import { ChannelId } from '@joystream/types/content-working-group';
 import { EditVideoView } from './upload/EditVideo.view';
-import { JoyInfo } from '@polkadot/joy-utils/JoyStatus';
+import { JoyInfo } from '@polkadot/joy-utils/react/components';
 import { IterableFile } from './IterableFile';
 import { StorageProviderId } from '@joystream/types/working-group';
+import { Loading } from '@polkadot/joy-utils/react/components';
 
 const MAX_FILE_SIZE_MB = 500;
 const MAX_FILE_SIZE_BYTES = MAX_FILE_SIZE_MB * 1024 * 1024;
@@ -46,6 +49,7 @@ type State = {
   newContentId: ContentId;
   discovering: boolean;
   uploading: boolean;
+  sendingTx: boolean;
   progress: number;
   cancelSource: CancelTokenSource;
 };
@@ -55,9 +59,10 @@ const defaultState = (): State => ({
   file: undefined,
   computingHash: false,
   ipfs_cid: undefined,
-  newContentId: ContentId.generate(),
+  newContentId: ContentId.generate(mockRegistry),
   discovering: false,
   uploading: false,
+  sendingTx: false,
   progress: 0,
   cancelSource: axios.CancelToken.source()
 });
@@ -84,12 +89,13 @@ class Upload extends React.PureComponent<Props, State> {
   }
 
   private renderContent () {
-    const { error, uploading, discovering, computingHash } = this.state;
+    const { error, uploading, discovering, computingHash, sendingTx } = this.state;
 
     if (error) return this.renderError();
     else if (discovering) return this.renderDiscovering();
     else if (uploading) return this.renderUploading();
     else if (computingHash) return this.renderComputingHash();
+    else if (sendingTx) return this.renderSendingTx();
     else return this.renderFileInput();
   }
 
@@ -117,13 +123,13 @@ class Upload extends React.PureComponent<Props, State> {
     if (!file || !file.name) return <JoyInfo title='Loading...' />;
 
     const success = !error && progress >= 100;
-    const { history, match: { params: { channelId } } } = this.props;
+    const { history, match: { params: { channelId } }, api } = this.props;
 
     return <div style={{ width: '100%' }}>
       {this.renderProgress()}
       {success &&
         <EditVideoView
-          channelId={new ChannelId(channelId)}
+          channelId={api.createType('ChannelId', channelId)}
           contentId={newContentId}
           fileName={fileNameWoExt(file.name)}
           history={history}
@@ -132,6 +138,10 @@ class Upload extends React.PureComponent<Props, State> {
     </div>;
   }
 
+  private renderSendingTx () {
+    return <JoyInfo title="Please wait..."><Loading text="Waiting for the transaction confirmation..." /></JoyInfo>
+  }
+
   private renderDiscovering () {
     return <JoyInfo title={'Please wait...'}>Contacting storage provider.</JoyInfo>;
   }
@@ -184,12 +194,16 @@ class Upload extends React.PureComponent<Props, State> {
       />
       {file_name && <div className='UploadButtonBox'>
         <TxButton
-          size='large'
           label={'Upload'}
           isDisabled={!file_name}
           tx={'dataDirectory.addContent'}
           params={this.buildTxParams()}
-          txSuccessCb={this.onDataObjectCreated}
+          onClick={(sendTx) => {
+            this.setState({ sendingTx: true });
+            sendTx();
+          }}
+          txSuccessCb={ this.onDataObjectCreated }
+          txFailedCb={() => { this.setState({ sendingTx: false }) }}
         />
       </div>}
     </div>;
@@ -253,7 +267,7 @@ class Upload extends React.PureComponent<Props, State> {
   }
 
   private onDataObjectCreated = async (_txResult: SubmittableResult) => {
-    this.setState({ discovering: true });
+    this.setState({ sendingTx: false, discovering: true });
 
     const { api } = this.props;
     const { newContentId } = this.state;

+ 1 - 1
pioneer/packages/joy-media/src/channels/ChannelAvatar.tsx

@@ -2,7 +2,7 @@ import React from 'react';
 import { Link } from 'react-router-dom';
 import { ChannelEntity } from '../entities/ChannelEntity';
 import { BgImg } from '../common/BgImg';
-import { DEFAULT_THUMBNAIL_URL } from '@polkadot/joy-utils/images';
+import { DEFAULT_THUMBNAIL_URL } from '../common/images';
 
 const defaultSizePx = 75;
 

+ 4 - 4
pioneer/packages/joy-media/src/channels/ChannelPreview.tsx

@@ -6,8 +6,8 @@ import { ChannelEntity } from '../entities/ChannelEntity';
 import { ChannelAvatar, ChannelAvatarSize } from './ChannelAvatar';
 import { isPublicChannel, isMusicChannel, isVideoChannel, isAccountAChannelOwner, isVerifiedChannel } from './ChannelHelpers';
 
-import { useMyMembership } from '@polkadot/joy-utils/MyMembershipContext';
-import { nonEmptyStr } from '@polkadot/joy-utils/index';
+import { useMyMembership } from '@polkadot/joy-utils/react/hooks';
+import { nonEmptyStr } from '@polkadot/joy-utils/functions/misc';
 import { CurationPanel } from './CurationPanel';
 import { ChannelNameAsLink } from './ChannelNameAsLink';
 
@@ -52,8 +52,6 @@ export const ChannelPreview = (props: ChannelPreviewProps) => {
         <h3 className='ChannelTitle' style={{ display: 'block' }}>
           <ChannelNameAsLink channel={channel} style={{ marginRight: '1rem' }} />
 
-          <CurationPanel channel={channel} />
-
           {isAccountAChannelOwner(channel, myAccountId) &&
             <div style={{ float: 'right' }}>
 
@@ -101,6 +99,8 @@ export const ChannelPreview = (props: ChannelPreviewProps) => {
           }
         </div>
 
+        <CurationPanel channel={channel} />
+
         {withDescription && nonEmptyStr(channel.description) &&
           <ReactMarkdown className='JoyMemo--full ChannelDesc' source={channel.description} linkTarget='_blank' />
         }

+ 4 - 3
pioneer/packages/joy-media/src/channels/ChannelsByOwner.view.tsx

@@ -1,10 +1,10 @@
 import React from 'react';
 import { RouteComponentProps } from 'react-router';
 
-import { GenericAccountId } from '@polkadot/types';
 import { MediaView } from '../MediaView';
 import { ChannelsByOwnerProps, ChannelsByOwner } from './ChannelsByOwner';
-import { JoyError } from '@polkadot/joy-utils/JoyStatus';
+import { JoyError } from '@polkadot/joy-utils/react/components';
+import { useApi } from '@polkadot/react-hooks';
 
 type Props = ChannelsByOwnerProps;
 
@@ -19,10 +19,11 @@ export const ChannelsByOwnerView = MediaView<Props>({
 
 export const ChannelsByOwnerWithRouter = (props: Props & RouteComponentProps<any>) => {
   const { match: { params: { account } } } = props;
+  const { api } = useApi();
 
   if (account) {
     try {
-      return <ChannelsByOwnerView {...props} accountId={new GenericAccountId(account)} />;
+      return <ChannelsByOwnerView {...props} accountId={api.createType('AccountId', account)} />;
     } catch (err) {
       console.log('ChannelsByOwnerWithRouter failed:', err);
     }

+ 23 - 17
pioneer/packages/joy-media/src/channels/CurationPanel.tsx

@@ -1,16 +1,18 @@
 import React from 'react';
 import { ChannelEntity } from '../entities/ChannelEntity';
 import { isVerifiedChannel, isCensoredChannel } from './ChannelHelpers';
-import { useMyMembership } from '@polkadot/joy-utils/MyMembershipContext';
-import TxButton from '@polkadot/joy-utils/TxButton';
-import { ChannelCurationStatus } from '@joystream/types/content-working-group';
+import { useMyMembership } from '@polkadot/joy-utils/react/hooks';
+import { SemanticTxButton } from '@polkadot/joy-utils/react/components/TxButton';
 import { AccountId } from '@polkadot/types/interfaces';
+import { useApi } from '@polkadot/react-hooks';
+import { Icon } from 'semantic-ui-react';
 
 type ChannelCurationPanelProps = {
   channel: ChannelEntity;
 };
 
 export const CurationPanel = (props: ChannelCurationPanelProps) => {
+  const { api } = useApi();
   const { curationActor, allAccounts } = useMyMembership();
   const { channel } = props;
 
@@ -34,17 +36,16 @@ export const CurationPanel = (props: ChannelCurationPanelProps) => {
 
     const isCensored = isCensoredChannel(channel);
 
-    const new_curation_status = new ChannelCurationStatus(
+    const new_curation_status = api.createType('ChannelCurationStatus',
       isCensored ? 'Normal' : 'Censored'
     );
 
-    return <TxButton
+    return <SemanticTxButton
       accountId={role_account.toString()}
       type='submit'
-      size='medium'
-      icon={isCensored ? 'x' : 'warning'}
-      isDisabled={!accountAvailable}
-      label={isCensored ? 'Un-Censor' : 'Censor'}
+      size='small'
+      color={isCensored ? undefined : 'red'}
+      disabled={!accountAvailable}
       params={[
         curation_actor,
         channel.id,
@@ -52,7 +53,10 @@ export const CurationPanel = (props: ChannelCurationPanelProps) => {
         new_curation_status // toggled curation status
       ]}
       tx={'contentWorkingGroup.updateChannelAsCurationActor'}
-    />;
+    >
+      <Icon name={isCensored ? 'x' : 'warning'}/>
+      { isCensored ? 'Un-Censor' : 'Censor' }
+    </SemanticTxButton>;
   };
 
   const renderToggleVerifiedButton = () => {
@@ -62,13 +66,12 @@ export const CurationPanel = (props: ChannelCurationPanelProps) => {
     const accountAvailable = canUseAccount(role_account);
     const isVerified = isVerifiedChannel(channel);
 
-    return <TxButton
+    return <SemanticTxButton
       accountId={role_account.toString()}
       type='submit'
-      size='medium'
-      icon={isVerified ? 'x' : 'checkmark'}
-      isDisabled={!accountAvailable}
-      label={isVerified ? 'Remove Verification' : 'Verify'}
+      size='small'
+      color={isVerified ? undefined : 'green'}
+      disabled={!accountAvailable}
       params={[
         curation_actor,
         channel.id,
@@ -76,11 +79,14 @@ export const CurationPanel = (props: ChannelCurationPanelProps) => {
         null // not changing curation status
       ]}
       tx={'contentWorkingGroup.updateChannelAsCurationActor'}
-    />;
+    >
+      <Icon name={isVerified ? 'x' : 'checkmark'}/>
+      { isVerified ? 'Remove Verification' : 'Verify' }
+    </SemanticTxButton>;
   };
 
   return <>
-    <div style={{ float: 'right' }}>
+    <div style={{ display: 'flex', float: 'right', margin: '0.5em', marginRight: 0 }}>
       {renderToggleCensorshipButton()}
       {renderToggleVerifiedButton()}
     </div>

+ 23 - 25
pioneer/packages/joy-media/src/channels/EditChannel.tsx

@@ -3,21 +3,22 @@ import { Button } from 'semantic-ui-react';
 import { Form, withFormik } from 'formik';
 import { History } from 'history';
 
-import { Text, Option } from '@polkadot/types';
-import TxButton from '@polkadot/joy-utils/TxButton';
-import { onImageError } from '@polkadot/joy-utils/images';
+import { Option } from '@polkadot/types';
+import { TxButton } from '@polkadot/joy-utils/react/components';
+import { onImageError } from '../common/images';
 import { withMediaForm, MediaFormProps } from '../common/MediaForms';
 import { ChannelType, ChannelClass as Fields, buildChannelValidationSchema, ChannelFormValues, ChannelToFormValues, ChannelGenericProp } from '../schemas/channel/Channel';
 import { MediaDropdownOptions } from '../common/MediaDropdownOptions';
-import { ChannelId, ChannelContentType, ChannelPublicationStatus, OptionalText } from '@joystream/types/content-working-group';
-import { newOptionalText, findFirstParamOfSubstrateEvent } from '@polkadot/joy-utils/index';
-import { useMyMembership } from '@polkadot/joy-utils/MyMembershipContext';
+import { ChannelId, OptionalText } from '@joystream/types/content-working-group';
+import { findFirstParamOfSubstrateEvent } from '@polkadot/joy-utils/functions/misc';
+import { useMyMembership } from '@polkadot/joy-utils/react/hooks';
 import { ChannelPublicationStatusDropdownOptions, isAccountAChannelOwner } from './ChannelHelpers';
 import { TxCallback } from '@polkadot/react-components/Status/types';
 import { SubmittableResult } from '@polkadot/api';
 import { ChannelValidationConstraints } from '../transport';
-import { JoyError } from '@polkadot/joy-utils/JoyStatus';
-import Section from '@polkadot/joy-utils/Section';
+import { JoyError } from '@polkadot/joy-utils/react/components';
+import { Section } from '@polkadot/joy-utils/react/components';
+import { useApi } from '@polkadot/react-hooks';
 
 export type OuterProps = {
   history?: History;
@@ -56,6 +57,7 @@ const InnerForm = (props: MediaFormProps<OuterProps, FormValues>) => {
   } = props;
 
   const { myAccountId, myMemberId } = useMyMembership();
+  const { api } = useApi();
 
   if (entity && !isAccountAChannelOwner(entity, myAccountId)) {
     return <JoyError title={'Only owner can edit channel'} />;
@@ -83,52 +85,49 @@ const InnerForm = (props: MediaFormProps<OuterProps, FormValues>) => {
   const buildTxParams = () => {
     if (!isValid) return [];
 
-    // TODO get value from the form:
-    const publicationStatus = new ChannelPublicationStatus('Public');
-
     if (!entity) {
       // Create a new channel
 
       const channelOwner = myMemberId;
       const roleAccount = myAccountId;
-      const contentType = new ChannelContentType(values.content);
+      const contentType = api.createType('ChannelContentType', values.content);
 
       return [
         channelOwner,
         roleAccount,
         contentType,
-        new Text(values.handle),
-        newOptionalText(values.title),
-        newOptionalText(values.description),
-        newOptionalText(values.avatar),
-        newOptionalText(values.banner),
-        publicationStatus
+        values.handle,
+        values.title || null,
+        values.description || null,
+        values.avatar || null,
+        values.banner || null,
+        values.publicationStatus
       ];
     } else {
       // Update an existing channel
 
       const updOptText = (field: ChannelGenericProp): Option<OptionalText> => {
-        return new Option(OptionalText,
+        return api.createType('Option<OptionalText>',
           isFieldChanged(field)
-            ? newOptionalText(values[field.id])
+            ? api.createType('Option<Text>', values[field.id])
             : null
         );
       };
 
-      const updHandle = new Option(Text,
+      const updHandle = api.createType('Option<Text>',
         isFieldChanged(Fields.handle)
           ? values[Fields.handle.id]
           : null
       );
 
-      const updPublicationStatus = new Option(ChannelPublicationStatus,
+      const updPublicationStatus = api.createType('Option<ChannelPublicationStatus>',
         isFieldChanged(Fields.publicationStatus)
-          ? new ChannelPublicationStatus(values[Fields.publicationStatus.id] as any)
+          ? api.createType('ChannelPublicationStatus', values[Fields.publicationStatus.id])
           : null
       );
 
       return [
-        new ChannelId(entity.id),
+        entity.id,
         updHandle,
         updOptText(Fields.title),
         updOptText(Fields.description),
@@ -156,7 +155,6 @@ const InnerForm = (props: MediaFormProps<OuterProps, FormValues>) => {
   const renderMainButton = () =>
     <TxButton
       type='submit'
-      size='large'
       isDisabled={!dirty || isSubmitting}
       label={isNew
         ? 'Create channel'

+ 4 - 3
pioneer/packages/joy-media/src/channels/EditChannel.view.tsx

@@ -2,8 +2,8 @@ import React from 'react';
 import { RouteComponentProps } from 'react-router';
 import { MediaView } from '../MediaView';
 import { OuterProps, EditForm } from './EditChannel';
-import { ChannelId } from '@joystream/types/content-working-group';
-import { JoyError } from '@polkadot/joy-utils/JoyStatus';
+import { JoyError } from '@polkadot/joy-utils/react/components';
+import { useApi } from '@polkadot/react-hooks';
 
 type Props = OuterProps;
 
@@ -23,10 +23,11 @@ type WithRouterProps = Props & RouteComponentProps<any>
 
 export const EditChannelWithRouter = (props: WithRouterProps) => {
   const { match: { params: { id } } } = props;
+  const { api } = useApi();
 
   if (id) {
     try {
-      return <EditChannelView {...props} id={new ChannelId(id)} />;
+      return <EditChannelView {...props} id={api.createType('ChannelId', id)} />;
     } catch (err) {
       console.log('EditChannelWithRouter failed:', err);
     }

+ 1 - 1
pioneer/packages/joy-media/src/channels/ViewChannel.tsx

@@ -8,7 +8,7 @@ import { ViewVideoChannel } from './ViewVideoChannel';
 import { ViewMusicChannel } from './ViewMusicChannel';
 import { toVideoPreviews } from '../video/VideoPreview';
 import { isVideoChannel, isMusicChannel } from './ChannelHelpers';
-import { JoyError } from '@polkadot/joy-utils/JoyStatus';
+import { JoyError } from '@polkadot/joy-utils/react/components';
 
 export type ViewChannelProps = {
   id: ChannelId;

+ 4 - 3
pioneer/packages/joy-media/src/channels/ViewChannel.view.tsx

@@ -2,8 +2,8 @@ import React from 'react';
 import { RouteComponentProps } from 'react-router';
 import { MediaView } from '../MediaView';
 import { ViewChannelProps, ViewChannel } from './ViewChannel';
-import { ChannelId } from '@joystream/types/content-working-group';
-import { JoyError } from '@polkadot/joy-utils/JoyStatus';
+import { JoyError } from '@polkadot/joy-utils/react/components';
+import { useApi } from '@polkadot/react-hooks';
 
 type Props = ViewChannelProps;
 
@@ -20,10 +20,11 @@ export const ViewChannelView = MediaView<Props>({
 
 export const ViewChannelWithRouter = (props: Props & RouteComponentProps<any>) => {
   const { match: { params: { id } } } = props;
+  const { api } = useApi();
 
   if (id) {
     try {
-      return <ViewChannelView {...props} id={new ChannelId(id)} />;
+      return <ViewChannelView {...props} id={api.createType('ChannelId', id)} />;
     } catch (err) {
       console.log('ViewChannelWithRouter failed:', err);
     }

+ 1 - 1
pioneer/packages/joy-media/src/channels/ViewMusicChannel.tsx

@@ -1,6 +1,6 @@
 import React from 'react';
 import { ChannelEntity } from '../entities/ChannelEntity';
-import Section from '@polkadot/joy-utils/Section';
+import { Section } from '@polkadot/joy-utils/react/components';
 import { ChannelHeader } from './ChannelHeader';
 import { MusicAlbumPreviewProps, MusicAlbumPreview } from '../music/MusicAlbumPreview';
 import { MusicTrackReaderPreview, MusicTrackReaderPreviewProps } from '../music/MusicTrackReaderPreview';

+ 1 - 1
pioneer/packages/joy-media/src/channels/ViewVideoChannel.tsx

@@ -1,5 +1,5 @@
 import React from 'react';
-import Section from '@polkadot/joy-utils/Section';
+import { Section } from '@polkadot/joy-utils/react/components';
 import { ChannelEntity } from '../entities/ChannelEntity';
 import { ChannelHeader } from './ChannelHeader';
 import { VideoPreview, VideoPreviewProps } from '../video/VideoPreview';

+ 2 - 2
pioneer/packages/joy-media/src/common/MediaForms.tsx

@@ -1,11 +1,11 @@
 import React from 'react';
 import { Dropdown, DropdownItemProps, DropdownProps } from 'semantic-ui-react';
 import { FormikProps, Field } from 'formik';
-import * as JoyForms from '@polkadot/joy-utils/forms';
+import * as JoyForms from '@polkadot/joy-utils/react/components/forms';
 import { SubmittableResult } from '@polkadot/api';
 import { TxFailedCallback, TxCallback } from '@polkadot/react-components/Status/types';
 import { MediaDropdownOptions } from './MediaDropdownOptions';
-import { OnTxButtonClick } from '@polkadot/joy-utils/TxButton';
+import { OnTxButtonClick } from '@polkadot/joy-utils/react/components/TxButton';
 import isEqual from 'lodash/isEqual';
 import { componentName } from '@polkadot/joy-utils/react/helpers';
 

+ 3 - 3
pioneer/packages/joy-media/src/common/MediaPlayerView.tsx

@@ -5,7 +5,7 @@ import APlayer from 'react-aplayer';
 
 import { ApiProps } from '@polkadot/react-api/types';
 import { I18nProps } from '@polkadot/react-components/types';
-import { withCalls, withMulti } from '@polkadot/react-api/with';
+import { withCalls, withMulti } from '@polkadot/react-api/hoc';
 import { Option } from '@polkadot/types/codec';
 
 import translate from '../translate';
@@ -14,8 +14,8 @@ import { DataObject, ContentId } from '@joystream/types/media';
 import { VideoType } from '../schemas/video/Video';
 import { isAccountAChannelOwner } from '../channels/ChannelHelpers';
 import { ChannelEntity } from '../entities/ChannelEntity';
-import { useMyMembership } from '@polkadot/joy-utils/MyMembershipContext';
-import { JoyError } from '@polkadot/joy-utils/JoyStatus';
+import { useMyMembership } from '@polkadot/joy-utils/react/hooks';
+import { JoyError } from '@polkadot/joy-utils/react/components';
 
 const PLAYER_COMMON_PARAMS = {
   lang: 'en',

+ 5 - 22
pioneer/packages/joy-media/src/common/MediaPlayerWithResolver.tsx

@@ -4,17 +4,16 @@ import _ from 'lodash';
 
 import { ApiProps } from '@polkadot/react-api/types';
 import { I18nProps } from '@polkadot/react-components/types';
-import { withMulti } from '@polkadot/react-api/with';
+import { withMulti } from '@polkadot/react-api/hoc';
 import { Option } from '@polkadot/types/codec';
-import { StorageProviderId, Worker } from '@joystream/types/working-group';
 
 import translate from '../translate';
 import { DiscoveryProviderProps, withDiscoveryProvider } from '../DiscoveryProvider';
 import { DataObjectStorageRelationshipId, DataObjectStorageRelationship } from '@joystream/types/media';
 import { Message } from 'semantic-ui-react';
 import { MediaPlayerView, RequiredMediaPlayerProps } from './MediaPlayerView';
-import { JoyInfo } from '@polkadot/joy-utils/JoyStatus';
-import { MultipleLinkedMapEntry } from '@polkadot/joy-utils/index';
+import { JoyInfo } from '@polkadot/joy-utils/react/components';
+import { useTransport } from '@polkadot/joy-utils/react/hooks';
 
 type Props = ApiProps & I18nProps & DiscoveryProviderProps & RequiredMediaPlayerProps;
 
@@ -24,29 +23,13 @@ function newCancelSource (): CancelTokenSource {
 
 function InnerComponent (props: Props) {
   const { contentId, api, discoveryProvider } = props;
+  const transport = useTransport();
 
   const [error, setError] = useState<Error>();
   const [resolvedAssetUrl, setResolvedAssetUrl] = useState<string>();
   const [contentType, setContentType] = useState<string>();
   const [cancelSource, setCancelSource] = useState<CancelTokenSource>(newCancelSource());
 
-  const getActiveStorageProviderIds = async (): Promise<StorageProviderId[]> => {
-    const nextId = await api.query.storageWorkingGroup.nextWorkerId() as StorageProviderId;
-    // This is chain specfic, but if next id is still 0, it means no workers have been added,
-    // so the workerById is empty
-    if (nextId.eq(0)) {
-      return [];
-    }
-
-    const workers = new MultipleLinkedMapEntry<StorageProviderId, Worker>(
-      StorageProviderId,
-      Worker,
-      await api.query.storageWorkingGroup.workerById()
-    );
-
-    return workers.linked_keys;
-  };
-
   const resolveAsset = async () => {
     setError(undefined);
     setCancelSource(newCancelSource());
@@ -68,9 +51,9 @@ function InnerComponent (props: Props) {
       return;
     }
 
+    const activeProviders = (await transport.workingGroups.allWorkers('Storage')).map(([id]) => id);
     // filter out providers no longer active - relationships of providers that have left
     // are not pruned onchain.
-    const activeProviders = await getActiveStorageProviderIds();
     readyProviders = _.intersectionBy(activeProviders, readyProviders, provider => provider.toString());
 
     console.log(`Found ${readyProviders.length} providers ready to serve content: ${readyProviders}`);

+ 4 - 3
pioneer/packages/joy-media/src/common/TypeHelpers.ts

@@ -1,4 +1,5 @@
 import BN from 'bn.js';
+import { createMock } from '@joystream/types';
 import { ChannelId } from '@joystream/types/content-working-group';
 import { EntityId, ClassId } from '@joystream/types/versioned-store';
 
@@ -16,7 +17,7 @@ export function asChannelId (id: AnyChannelId): ChannelId {
   if (id instanceof ChannelId) {
     return id;
   } else if (canBeId(id)) {
-    return new ChannelId(id);
+    return createMock('ChannelId', id);
   } else {
     throw new Error(`Not supported format for Channel id: ${id}`);
   }
@@ -26,7 +27,7 @@ export function asEntityId (id: AnyEntityId): EntityId {
   if (id instanceof EntityId) {
     return id;
   } else if (canBeId(id)) {
-    return new EntityId(id);
+    return createMock('EntityId', id);
   } else {
     throw new Error(`Not supported format for Entity id: ${id}`);
   }
@@ -36,7 +37,7 @@ export function asClassId (id: AnyClassId): ClassId {
   if (id instanceof ClassId) {
     return id;
   } else if (canBeId(id)) {
-    return new ClassId(id);
+    return createMock('ClassId', id);
   } else {
     throw new Error(`Not supported format for Class id: ${id}`);
   }

+ 2 - 0
pioneer/packages/joy-utils-old/src/images.ts → pioneer/packages/joy-media/src/common/images.tsx

@@ -1,3 +1,5 @@
+import React from 'react';
+
 export const DEFAULT_THUMBNAIL_URL = 'images/default-thumbnail.png';
 
 // This is a hack to just satisfy TypeScript compiler.

+ 0 - 0
pioneer/packages/joy-media/src/common/index.css → pioneer/packages/joy-media/src/common/index.scss


+ 1 - 1
pioneer/packages/joy-media/src/explore/AllChannels.tsx

@@ -1,5 +1,5 @@
 import React from 'react';
-import Section from '@polkadot/joy-utils/Section';
+import { Section } from '@polkadot/joy-utils/react/components';
 import { MediaView } from '../MediaView';
 import { ChannelEntity } from '../entities/ChannelEntity';
 import { ChannelPreview } from '../channels/ChannelPreview';

+ 1 - 1
pioneer/packages/joy-media/src/explore/AllVideos.tsx

@@ -1,5 +1,5 @@
 import React from 'react';
-import Section from '@polkadot/joy-utils/Section';
+import { Section } from '@polkadot/joy-utils/react/components';
 import { VideoPreviewProps, VideoPreview } from '../video/VideoPreview';
 import { MediaView } from '../MediaView';
 

+ 1 - 1
pioneer/packages/joy-media/src/explore/ExploreContent.tsx

@@ -1,6 +1,6 @@
 import React from 'react';
 import { Link } from 'react-router-dom';
-import Section from '@polkadot/joy-utils/Section';
+import { Section } from '@polkadot/joy-utils/react/components';
 import { VideoPreviewProps, VideoPreview } from '../video/VideoPreview';
 import { ChannelEntity } from '../entities/ChannelEntity';
 import { ChannelPreview } from '../channels/ChannelPreview';

+ 1 - 1
pioneer/packages/joy-media/src/explore/PlayContent.tsx

@@ -1,7 +1,7 @@
 import React, { useState } from 'react';
 import { MusicAlbumPreviewProps, MusicAlbumPreview } from '../music/MusicAlbumPreview';
 import { MusicTrackReaderPreviewProps, MusicTrackReaderPreview } from '../music/MusicTrackReaderPreview';
-import { Pluralize } from '@polkadot/joy-utils/Pluralize';
+import { Pluralize } from '@polkadot/joy-utils/react/components';
 import { Table } from 'semantic-ui-react';
 import { ChannelEntity } from '../entities/ChannelEntity';
 import { ChannelPreview } from '../channels/ChannelPreview';

+ 5 - 3
pioneer/packages/joy-media/src/index.css → pioneer/packages/joy-media/src/index.scss

@@ -41,6 +41,11 @@
     width: 100%;
     max-width: 600px;
   }
+
+  .EditMetaForm {
+    flex-grow: 1;
+    max-width: 600px;
+  }
 }
 
 .PlayBox {
@@ -72,9 +77,6 @@
   .MediaCell {
     width: 25%;
 
-    &.MyContent {
-      /* background-color: #fff8e1; */
-    }
     &:hover {
       background-color: #deeffc;
     }

+ 6 - 5
pioneer/packages/joy-media/src/index.tsx

@@ -3,15 +3,16 @@ import React from 'react';
 import { Route, Switch } from 'react-router';
 
 import { AppProps, I18nProps } from '@polkadot/react-components/types';
-import Tabs, { TabItem } from '@polkadot/react-components/Tabs';
+import Tabs from '@polkadot/react-components/Tabs';
+import { TabItem } from '@polkadot/react-components/Tabs/types';
 import { ApiProps } from '@polkadot/react-api/types';
-import { withMulti } from '@polkadot/react-api/with';
+import { withMulti } from '@polkadot/react-api/hoc';
 
-import './index.css';
-import './common/index.css';
+import './index.scss';
+import './common/index.scss';
 
 import translate from './translate';
-import { useMyAccount } from '@polkadot/joy-utils/MyAccountContext';
+import { useMyAccount } from '@polkadot/joy-utils/react/hooks';
 import { UploadWithRouter } from './Upload';
 import { DiscoveryProviderProps, DiscoveryProviderProvider } from './DiscoveryProvider';
 import { SubstrateTransportProvider } from './TransportContext';

+ 2 - 3
pioneer/packages/joy-media/src/music/EditMusicAlbum.tsx

@@ -3,8 +3,8 @@ import { Button, Tab } from 'semantic-ui-react';
 import { Form, withFormik } from 'formik';
 import { History } from 'history';
 
-import TxButton from '@polkadot/joy-utils/TxButton';
-import { onImageError } from '@polkadot/joy-utils/images';
+import { TxButton } from '@polkadot/joy-utils/react/components';
+import { onImageError } from '../common/images';
 import { ReorderableTracks } from './ReorderableTracks';
 import { MusicAlbumValidationSchema, MusicAlbumType, MusicAlbumClass as Fields, MusicAlbumFormValues, MusicAlbumToFormValues } from '../schemas/music/MusicAlbum';
 import { withMediaForm, MediaFormProps, datePlaceholder } from '../common/MediaForms';
@@ -123,7 +123,6 @@ const InnerForm = (props: MediaFormProps<OuterProps, FormValues>) => {
   const renderMainButton = () =>
     <TxButton
       type='submit'
-      size='large'
       isDisabled={!dirty || isSubmitting}
       label={isNew
         ? 'Publish'

+ 1 - 1
pioneer/packages/joy-media/src/music/MusicAlbumPreview.tsx

@@ -1,6 +1,6 @@
 import React from 'react';
 import { Button } from 'semantic-ui-react';
-import { Pluralize } from '@polkadot/joy-utils/Pluralize';
+import { Pluralize } from '@polkadot/joy-utils/react/components';
 import { BgImg } from '../common/BgImg';
 import { ChannelEntity } from '../entities/ChannelEntity';
 

+ 1 - 1
pioneer/packages/joy-media/src/music/MusicAlbumTracks.tsx

@@ -1,6 +1,6 @@
 import React, { useState } from 'react';
 import { Button, CheckboxProps } from 'semantic-ui-react';
-import { Pluralize } from '@polkadot/joy-utils/Pluralize';
+import { Pluralize } from '@polkadot/joy-utils/react/components';
 import { EditableMusicTrackPreviewProps, MusicTrackPreview } from './MusicTrackPreview';
 import { MusicAlbumPreviewProps, MusicAlbumPreview } from './MusicAlbumPreview';
 

+ 2 - 2
pioneer/packages/joy-media/src/music/MyMusicTracks.tsx

@@ -1,8 +1,8 @@
 import React, { useState } from 'react';
 import { Button, CheckboxProps, Dropdown, Message } from 'semantic-ui-react';
 
-import { Pluralize } from '@polkadot/joy-utils/Pluralize';
-import Section from '@polkadot/joy-utils/Section';
+import { Pluralize } from '@polkadot/joy-utils/react/components';
+import { Section } from '@polkadot/joy-utils/react/components';
 import { EditableMusicTrackPreviewProps, MusicTrackPreview } from './MusicTrackPreview';
 import { ReorderableTracks } from './ReorderableTracks';
 import { MusicAlbumPreviewProps } from './MusicAlbumPreview';

+ 14 - 14
pioneer/packages/joy-media/src/schemas/channel/Channel.ts

@@ -4,7 +4,7 @@ import { BlockNumber, AccountId } from '@polkadot/types/interfaces';
 import { ChannelContentTypeValue, PrincipalId, Channel, ChannelId, ChannelPublicationStatusValue, ChannelCurationStatusValue } from '@joystream/types/content-working-group';
 import { MemberId } from '@joystream/types/members';
 import { ChannelValidationConstraints } from '@polkadot/joy-media/transport';
-import { ValidationConstraint } from '@polkadot/joy-utils/ValidationConstraint';
+import { ValidationConstraint } from '@polkadot/joy-utils/types/ValidationConstraint';
 
 function textValidation (constraint?: ValidationConstraint) {
   if (!constraint) {
@@ -56,19 +56,19 @@ export class ChannelCodec {
   static fromSubstrate (id: ChannelId, sub: Channel): ChannelType {
     return {
       id: id.toNumber(),
-      verified: sub.getBoolean('verified'),
-      handle: sub.getString('handle'),
-      title: sub.getOptionalString('title'),
-      description: sub.getOptionalString('description'),
-      avatar: sub.getOptionalString('avatar'),
-      banner: sub.getOptionalString('banner'),
-      content: sub.getEnumAsString<ChannelContentTypeValue>('content'),
-      owner: sub.getField('owner'),
-      roleAccount: sub.getField('role_account'),
-      publicationStatus: sub.getEnumAsString<ChannelPublicationStatusValue>('publication_status'),
-      curationStatus: sub.getEnumAsString<ChannelCurationStatusValue>('curation_status'),
-      created: sub.getField('created'),
-      principalId: sub.getField('principal_id')
+      verified: sub.verified.valueOf(),
+      handle: sub.handle.toString(),
+      title: sub.title.unwrapOr(undefined)?.toString(),
+      description: sub.description.unwrapOr(undefined)?.toString(),
+      avatar: sub.avatar.unwrapOr(undefined)?.toString(),
+      banner: sub.banner.unwrapOr(undefined)?.toString(),
+      content: sub.content.type,
+      owner: sub.owner,
+      roleAccount: sub.role_account,
+      publicationStatus: sub.publication_status.type,
+      curationStatus: sub.curation_status.type,
+      created: sub.created,
+      principalId: sub.principal_id
     };
   }
 }

+ 1 - 1
pioneer/packages/joy-media/src/stories/ExploreContent.stories.tsx

@@ -1,5 +1,5 @@
 import React from 'react';
-import '../common/index.css';
+import '../common/index.scss';
 
 import { ExploreContent } from '../explore/ExploreContent';
 import { withMockTransport } from './withMockTransport';

+ 3 - 3
pioneer/packages/joy-media/src/stories/MusicAlbumTracks.stories.tsx

@@ -1,5 +1,5 @@
 import React from 'react';
-import '../common/index.css';
+import '../common/index.scss';
 
 import { EditForm } from '../music/EditMusicAlbum';
 import { MyMusicTracks } from '../music/MyMusicTracks';
@@ -7,7 +7,7 @@ import { MusicAlbumSamples } from './data/MusicAlbumSamples';
 import { albumTracks, AllMusicTrackSamples } from './data/MusicTrackSamples';
 import { withMockTransport } from './withMockTransport';
 import { EditMusicAlbumView } from '../music/EditMusicAlbum.view';
-import EntityId from '@joystream/types/versioned-store/EntityId';
+import { createMock } from '@joystream/types';
 
 export default {
   title: 'Media | My music tracks',
@@ -19,7 +19,7 @@ export const DefaultState = () =>
 
 export const MockEditAlbumView = () =>
   <EditMusicAlbumView
-    id={new EntityId(1)}
+    id={createMock('EntityId', 1)}
     tracks={albumTracks}
   />;
 

+ 1 - 1
pioneer/packages/joy-media/src/stories/MusicChannel.stories.tsx

@@ -1,5 +1,5 @@
 import React from 'react';
-import '../common/index.css';
+import '../common/index.scss';
 
 import { MockMusicChannel } from './data/ChannelSamples';
 import { ViewMusicChannel } from '../channels/ViewMusicChannel';

+ 4 - 5
pioneer/packages/joy-media/src/stories/MyChannels.stories.tsx

@@ -1,14 +1,13 @@
 import React from 'react';
-import '../common/index.css';
+import '../common/index.scss';
 
-import { GenericAccountId } from '@polkadot/types';
 import { ChannelsByOwner } from '../channels/ChannelsByOwner';
 import { AllMockChannels } from './data/ChannelSamples';
 import { withMockTransport } from './withMockTransport';
 import EditForm from '../channels/EditChannel';
 import { EditChannelView } from '../channels/EditChannel.view';
-import { ChannelId } from '@joystream/types/content-working-group';
 import { AccountIdSamples } from './data/AccountIdSamples';
+import { createMock } from '@joystream/types';
 
 export default {
   title: 'Media | My channels',
@@ -16,7 +15,7 @@ export default {
 };
 
 // TODO pass to mocked MyMembershipContext provider via Stories decorators:
-const accountId = new GenericAccountId(AccountIdSamples.Alice);
+const accountId = createMock('AccountId', AccountIdSamples.Alice);
 
 export const DefaultState = () =>
   <ChannelsByOwner accountId={accountId} />;
@@ -31,4 +30,4 @@ export const DefaultEditForm = () =>
   <EditForm />;
 
 export const MockEditFormView = () =>
-  <EditChannelView id={new ChannelId(1)} />;
+  <EditChannelView id={createMock('ChannelId', 1)} />;

+ 1 - 1
pioneer/packages/joy-media/src/stories/MyMusicAlbums.stories.tsx

@@ -1,5 +1,5 @@
 import React from 'react';
-import '../common/index.css';
+import '../common/index.scss';
 
 import { MyMusicAlbums } from '../music/MyMusicAlbums';
 import { MusicAlbumSamples } from './data/MusicAlbumSamples';

+ 3 - 3
pioneer/packages/joy-media/src/stories/Playback.stories.tsx

@@ -1,5 +1,5 @@
 import React from 'react';
-import '../common/index.css';
+import '../common/index.scss';
 
 import { PlayContent } from '../explore/PlayContent';
 import { PlayVideo } from '../video/PlayVideo';
@@ -8,7 +8,7 @@ import { Album1TrackSamples } from './data/MusicTrackSamples';
 import { MockMusicChannel, MockVideoChannel } from './data/ChannelSamples';
 import { withMockTransport } from './withMockTransport';
 import { Video } from '../mocks';
-import { EntityId } from '@joystream/types/versioned-store';
+import { createMock } from '@joystream/types';
 
 export default {
   title: 'Media | Playback',
@@ -17,7 +17,7 @@ export default {
 
 export const PlayVideoStory = () =>
   <PlayVideo
-    id={new EntityId(Video.id)}
+    id={createMock('EntityId', Video.id)}
     video={Video}
     channel={MockVideoChannel}
   />;

+ 3 - 3
pioneer/packages/joy-media/src/stories/UploadAudio.stories.tsx

@@ -3,16 +3,16 @@ import { EditForm } from '../upload/UploadAudio';
 import '../index.css';
 
 import { ContentId } from '@joystream/types/media';
-import EntityId from '@joystream/types/versioned-store/EntityId';
 import { UploadAudioView } from '../upload/UploadAudio.view';
 import { withMockTransport } from './withMockTransport';
+import { mockRegistry, createMock } from '@joystream/types';
 
 export default {
   title: 'Media | Upload audio',
   decorators: [withMockTransport]
 };
 
-const contentId = ContentId.generate();
+const contentId = ContentId.generate(mockRegistry);
 
 export const DefaultState = () =>
   <EditForm
@@ -22,5 +22,5 @@ export const DefaultState = () =>
 export const MockEditFormView = () =>
   <UploadAudioView
     contentId={contentId}
-    id={new EntityId(1)}
+    id={createMock('EntityId', 1)}
   />;

+ 3 - 3
pioneer/packages/joy-media/src/stories/UploadVideo.stories.tsx

@@ -5,14 +5,14 @@ import '../index.css';
 import { ContentId } from '@joystream/types/media';
 import { withMockTransport } from './withMockTransport';
 import EditVideoView from '../upload/EditVideo.view';
-import EntityId from '@joystream/types/versioned-store/EntityId';
+import { createMock, mockRegistry } from '@joystream/types';
 
 export default {
   title: 'Media | Upload video',
   decorators: [withMockTransport]
 };
 
-const contentId = ContentId.generate();
+const contentId = ContentId.generate(mockRegistry);
 
 export const DefaultState = () =>
   <EditForm
@@ -22,5 +22,5 @@ export const DefaultState = () =>
 export const MockEditFormView = () =>
   <EditVideoView
     contentId={contentId}
-    id={new EntityId(1)}
+    id={createMock('EntityId', 1)}
   />;

+ 4 - 4
pioneer/packages/joy-media/src/stories/data/AccountIdSamples.ts

@@ -1,7 +1,7 @@
-import { GenericAccountId } from '@polkadot/types';
+import { createMock } from '@joystream/types';
 
 export const AccountIdSamples = {
-  Alice: new GenericAccountId('5GNJqTPyNqANBkUVMN1LPPrxXnFouWXoe2wNSmmEoLctxiZY'),
-  Bob: new GenericAccountId('5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty'),
-  Charlie: new GenericAccountId('5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y')
+  Alice: createMock('AccountId', '5GNJqTPyNqANBkUVMN1LPPrxXnFouWXoe2wNSmmEoLctxiZY'),
+  Bob: createMock('AccountId', '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty'),
+  Charlie: createMock('AccountId', '5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y')
 };

+ 7 - 9
pioneer/packages/joy-media/src/stories/data/ChannelSamples.ts

@@ -1,9 +1,7 @@
 import BN from 'bn.js';
 import { ChannelEntity } from '@polkadot/joy-media/entities/ChannelEntity';
-import { u32 } from '@polkadot/types';
 import { AccountIdSamples } from './AccountIdSamples';
-import { MemberId } from '@joystream/types/members';
-import { PrincipalId } from '@joystream/types/content-working-group';
+import { createMock } from '@joystream/types';
 
 let id = 0;
 const nextId = () => ++id;
@@ -22,10 +20,10 @@ export const MockMusicChannel: ChannelEntity =
 
   publicationStatus: 'Unlisted',
   curationStatus: 'Censored',
-  owner: new MemberId(1),
+  owner: createMock('MemberId', 1),
   roleAccount: AccountIdSamples.Alice,
-  principalId: new PrincipalId(1),
-  created: new u32(123456),
+  principalId: createMock('PrincipalId', 1),
+  created: createMock('u32', 123456),
 
   rewardEarned: new BN('4587'),
   contentItemsCount: 57
@@ -45,10 +43,10 @@ export const MockVideoChannel: ChannelEntity =
 
   publicationStatus: 'Public',
   curationStatus: 'Normal',
-  owner: new MemberId(1),
+  owner: createMock('MemberId', 1),
   roleAccount: AccountIdSamples.Alice,
-  principalId: new PrincipalId(1),
-  created: new u32(123456),
+  principalId: createMock('PrincipalId', 1),
+  created: createMock('u32', 123456),
 
   rewardEarned: new BN('1820021'),
   contentItemsCount: 1529

+ 15 - 14
pioneer/packages/joy-media/src/transport.mock.ts

@@ -17,6 +17,7 @@ import { PublicationStatusType } from './schemas/general/PublicationStatus';
 import { VideoCategoryType } from './schemas/video/VideoCategory';
 import { ChannelEntity } from './entities/ChannelEntity';
 import { AllMockChannels } from './stories/data/ChannelSamples';
+import { mockPromise } from '@polkadot/joy-utils/transport/mock/base';
 
 export class MockTransport extends MediaTransport {
   constructor () {
@@ -29,7 +30,7 @@ export class MockTransport extends MediaTransport {
   }
 
   allChannels (): Promise<ChannelEntity[]> {
-    return this.promise(AllMockChannels);
+    return mockPromise(AllMockChannels);
   }
 
   channelValidationConstraints (): Promise<ChannelValidationConstraints> {
@@ -45,54 +46,54 @@ export class MockTransport extends MediaTransport {
   }
 
   allVideos (): Promise<VideoType[]> {
-    return this.promise(mocks.AllVideos);
+    return mockPromise(mocks.AllVideos);
   }
 
   allMusicTracks (): Promise<MusicTrackType[]> {
-    return this.promise(mocks.AllMusicTracks);
+    return mockPromise(mocks.AllMusicTracks);
   }
 
   allMusicAlbums (): Promise<MusicAlbumType[]> {
-    return this.promise(mocks.AllMusicAlbums);
+    return mockPromise(mocks.AllMusicAlbums);
   }
 
   featuredContent (): Promise<FeaturedContentType | undefined> {
-    return this.promise(mocks.FeaturedContent);
+    return mockPromise(mocks.FeaturedContent);
   }
 
   allContentLicenses (): Promise<ContentLicenseType[]> {
-    return this.promise(mocks.AllContentLicenses);
+    return mockPromise(mocks.AllContentLicenses);
   }
 
   allCurationStatuses (): Promise<CurationStatusType[]> {
-    return this.promise(mocks.AllCurationStatuses);
+    return mockPromise(mocks.AllCurationStatuses);
   }
 
   allLanguages (): Promise<LanguageType[]> {
-    return this.promise(mocks.AllLanguages);
+    return mockPromise(mocks.AllLanguages);
   }
 
   allMediaObjects (): Promise<MediaObjectType[]> {
-    return this.promise(mocks.AllMediaObjects);
+    return mockPromise(mocks.AllMediaObjects);
   }
 
   allMusicGenres (): Promise<MusicGenreType[]> {
-    return this.promise(mocks.AllMusicGenres);
+    return mockPromise(mocks.AllMusicGenres);
   }
 
   allMusicMoods (): Promise<MusicMoodType[]> {
-    return this.promise(mocks.AllMusicMoods);
+    return mockPromise(mocks.AllMusicMoods);
   }
 
   allMusicThemes (): Promise<MusicThemeType[]> {
-    return this.promise(mocks.AllMusicThemes);
+    return mockPromise(mocks.AllMusicThemes);
   }
 
   allPublicationStatuses (): Promise<PublicationStatusType[]> {
-    return this.promise(mocks.AllPublicationStatuses);
+    return mockPromise(mocks.AllPublicationStatuses);
   }
 
   allVideoCategories (): Promise<VideoCategoryType[]> {
-    return this.promise(mocks.AllVideoCategories);
+    return mockPromise(mocks.AllVideoCategories);
   }
 }

+ 10 - 13
pioneer/packages/joy-media/src/transport.substrate.ts

@@ -19,13 +19,11 @@ import { ChannelEntity } from './entities/ChannelEntity';
 import { ChannelId, Channel } from '@joystream/types/content-working-group';
 import { ApiPromise } from '@polkadot/api/index';
 import { ApiProps } from '@polkadot/react-api/types';
-import { Vec } from '@polkadot/types';
-import { LinkageResult } from '@polkadot/types/codec/Linkage';
 import { ChannelCodec } from './schemas/channel/Channel';
 import { FeaturedContentType } from './schemas/general/FeaturedContent';
-import { AnyChannelId, asChannelId, AnyClassId, AnyEntityId } from './common/TypeHelpers';
-import { SimpleCache } from '@polkadot/joy-utils/SimpleCache';
-import { ValidationConstraint } from '@polkadot/joy-utils/ValidationConstraint';
+import { AnyChannelId, AnyClassId, AnyEntityId, asChannelId } from './common/TypeHelpers';
+import { SimpleCache } from '@polkadot/joy-utils/transport/SimpleCache';
+import { ValidationConstraint } from '@polkadot/joy-utils/types/ValidationConstraint';
 
 const FIRST_CHANNEL_ID = 1;
 const FIRST_CLASS_ID = 1;
@@ -130,17 +128,16 @@ export class SubstrateTransport extends MediaTransport {
 
     const allIds: ChannelId[] = [];
     for (let id = FIRST_CHANNEL_ID; id < nextId; id++) {
-      allIds.push(new ChannelId(id));
+      allIds.push(this.api.createType('ChannelId', id));
     }
 
     return allIds;
   }
 
   async loadChannelsByIds (ids: AnyChannelId[]): Promise<ChannelEntity[]> {
-    const channelTuples = await this.cwgQuery().channelById.multi<LinkageResult>(ids);
+    const channels = await this.cwgQuery().channelById.multi<Channel>(ids);
 
-    return channelTuples.map((tuple, i) => {
-      const channel = tuple[0] as Channel;
+    return channels.map((channel, i) => {
       const id = asChannelId(ids[i]);
       const plain = ChannelCodec.fromSubstrate(id, channel);
 
@@ -200,14 +197,14 @@ export class SubstrateTransport extends MediaTransport {
 
     const allIds: ClassId[] = [];
     for (let id = FIRST_CLASS_ID; id < nextId; id++) {
-      allIds.push(new ClassId(id));
+      allIds.push(this.api.createType('ClassId', id));
     }
 
     return allIds;
   }
 
   async loadClassesByIds (ids: AnyClassId[]): Promise<Class[]> {
-    return await this.vsQuery().classById.multi<Vec<Class>>(ids) as unknown as Class[];
+    return await this.vsQuery().classById.multi<Class>(ids);
   }
 
   async allClasses (): Promise<Class[]> {
@@ -246,7 +243,7 @@ export class SubstrateTransport extends MediaTransport {
 
     const allIds: EntityId[] = [];
     for (let id = FIRST_ENTITY_ID; id < nextId; id++) {
-      allIds.push(new EntityId(id));
+      allIds.push(this.api.createType('EntityId', id));
     }
 
     return allIds;
@@ -255,7 +252,7 @@ export class SubstrateTransport extends MediaTransport {
   private async loadEntitiesByIds (ids: AnyEntityId[]): Promise<Entity[]> {
     if (!ids || ids.length === 0) return [];
 
-    return await this.vsQuery().entityById.multi<Vec<Entity>>(ids) as unknown as Entity[];
+    return await this.vsQuery().entityById.multi<Entity>(ids);
   }
 
   // TODO try to cache this func

+ 6 - 6
pioneer/packages/joy-media/src/transport.ts

@@ -1,4 +1,3 @@
-import { Transport } from '@polkadot/joy-utils/index';
 import { AccountId } from '@polkadot/types/interfaces';
 import { EntityId, Class, ClassName, unifyClassName, ClassIdByNameMap } from '@joystream/types/versioned-store';
 import { MusicTrackType, MusicTrackCodec } from './schemas/music/MusicTrack';
@@ -18,7 +17,8 @@ import { MediaDropdownOptions } from './common/MediaDropdownOptions';
 import { ChannelEntity } from './entities/ChannelEntity';
 import { ChannelId } from '@joystream/types/content-working-group';
 import { isVideoChannel, isPublicChannel } from './channels/ChannelHelpers';
-import { ValidationConstraint } from '@polkadot/joy-utils/ValidationConstraint';
+import { ValidationConstraint } from '@polkadot/joy-utils/types/ValidationConstraint';
+import { createMock } from '@joystream/types';
 
 export interface ChannelValidationConstraints {
   handle: ValidationConstraint;
@@ -60,7 +60,7 @@ function insensitiveEq (text1: string, text2: string): boolean {
   return prepare(text1) === prepare(text2);
 }
 
-export abstract class MediaTransport extends Transport {
+export abstract class MediaTransport {
   protected cachedClassIdByNameMap: ClassIdByNameMap | undefined
 
   protected sessionId = 0
@@ -128,14 +128,14 @@ export abstract class MediaTransport extends Transport {
   async topVideo (): Promise<VideoType | undefined> {
     const content = await this.featuredContent();
     const topVideoId = content?.topVideo as unknown as number | undefined;
-    return !topVideoId ? undefined : await this.videoById(new EntityId(topVideoId));
+    return !topVideoId ? undefined : await this.videoById(createMock('EntityId', topVideoId));
   }
 
   async featuredVideos (): Promise<VideoType[]> {
     const content = await this.featuredContent();
     const videoIds = (content?.featuredVideos || []) as unknown as number[];
     const videos = await Promise.all(videoIds.map((id) =>
-      this.videoById(new EntityId(id))));
+      this.videoById(createMock('EntityId', id))));
     return videos.filter(x => x !== undefined) as VideoType[];
   }
 
@@ -143,7 +143,7 @@ export abstract class MediaTransport extends Transport {
     const content = await this.featuredContent();
     const albumIds = (content?.featuredAlbums || []) as unknown as EntityId[];
     const albums = await Promise.all(albumIds.map((id) =>
-      this.musicAlbumById(new EntityId(id))));
+      this.musicAlbumById(createMock('EntityId', id))));
     return albums.filter(x => x !== undefined) as MusicAlbumType[];
   }
 

+ 6 - 5
pioneer/packages/joy-media/src/upload/EditVideo.view.tsx

@@ -2,9 +2,8 @@ import React from 'react';
 import { RouteComponentProps } from 'react-router';
 import { MediaView } from '../MediaView';
 import { OuterProps, EditForm } from './UploadVideo';
-import EntityId from '@joystream/types/versioned-store/EntityId';
-import { ChannelId } from '@joystream/types/content-working-group';
-import { JoyError } from '@polkadot/joy-utils/JoyStatus';
+import { JoyError } from '@polkadot/joy-utils/react/components';
+import { useApi } from '@polkadot/react-hooks';
 
 type Props = OuterProps;
 
@@ -27,10 +26,11 @@ type WithRouterProps = Props & RouteComponentProps<any>
 
 export const UploadVideoWithRouter = (props: WithRouterProps) => {
   const { match: { params: { channelId } } } = props;
+  const { api } = useApi();
 
   if (channelId) {
     try {
-      return <EditVideoView {...props} channelId={new ChannelId(channelId)} />;
+      return <EditVideoView {...props} channelId={api.createType('ChannelId', channelId)} />;
     } catch (err) {
       console.log('UploadVideoWithRouter failed:', err);
     }
@@ -41,10 +41,11 @@ export const UploadVideoWithRouter = (props: WithRouterProps) => {
 
 export const EditVideoWithRouter = (props: WithRouterProps) => {
   const { match: { params: { id } } } = props;
+  const { api } = useApi();
 
   if (id) {
     try {
-      return <EditVideoView {...props} id={new EntityId(id)} />;
+      return <EditVideoView {...props} id={api.createType('EntityId', id)} />;
     } catch (err) {
       console.log('EditVideoWithRouter failed:', err);
     }

+ 2 - 3
pioneer/packages/joy-media/src/upload/UploadAudio.tsx

@@ -3,9 +3,9 @@ import { Button, Tab } from 'semantic-ui-react';
 import { Form, withFormik } from 'formik';
 import { History } from 'history';
 
-import TxButton from '@polkadot/joy-utils/TxButton';
+import { TxButton } from '@polkadot/joy-utils/react/components';
 import { ContentId } from '@joystream/types/media';
-import { onImageError } from '@polkadot/joy-utils/images';
+import { onImageError } from '../common/images';
 import { MusicTrackValidationSchema, MusicTrackType, MusicTrackClass as Fields, MusicTrackFormValues, MusicTrackToFormValues } from '../schemas/music/MusicTrack';
 import { withMediaForm, MediaFormProps, datePlaceholder } from '../common/MediaForms';
 import EntityId from '@joystream/types/versioned-store/EntityId';
@@ -113,7 +113,6 @@ const InnerForm = (props: MediaFormProps<OuterProps, FormValues>) => {
   const renderMainButton = () =>
     <TxButton
       type='submit'
-      size='large'
       isDisabled={!dirty || isSubmitting}
       label={isNew
         ? 'Publish'

+ 26 - 24
pioneer/packages/joy-media/src/upload/UploadVideo.tsx

@@ -4,9 +4,10 @@ import { Form, withFormik } from 'formik';
 import { History } from 'history';
 import moment from 'moment';
 
-import TxButton, { OnTxButtonClick } from '@polkadot/joy-utils/TxButton';
+import TxButton, { OnTxButtonClick } from '@polkadot/joy-utils/react/components/TxButton';
 import { ContentId } from '@joystream/types/media';
-import { onImageError } from '@polkadot/joy-utils/images';
+import { onImageError } from '../common/images';
+import { nonEmptyStr, filterSubstrateEventsAndExtractData } from '@polkadot/joy-utils/functions/misc';
 import { VideoValidationSchema, VideoType, VideoClass as Fields, VideoFormValues, VideoToFormValues, VideoCodec, VideoPropId } from '../schemas/video/Video';
 import { MediaFormProps, withMediaForm, datePlaceholder } from '../common/MediaForms';
 import EntityId from '@joystream/types/versioned-store/EntityId';
@@ -14,23 +15,20 @@ import { MediaDropdownOptions } from '../common/MediaDropdownOptions';
 import { FormTabs } from '../common/FormTabs';
 import { ChannelId } from '@joystream/types/content-working-group';
 import { ChannelEntity } from '../entities/ChannelEntity';
-import { Credential } from '@joystream/types/common';
 import { Class, VecClassPropertyValue } from '@joystream/types/versioned-store';
 import { TxCallback } from '@polkadot/react-components/Status/types';
 import { SubmittableResult } from '@polkadot/api';
-import { nonEmptyStr, filterSubstrateEventsAndExtractData } from '@polkadot/joy-utils/index';
-import { u16, u32, bool, Option, Vec } from '@polkadot/types';
 import { isInternalProp } from '@joystream/types/versioned-store/EntityCodec';
 import { MediaObjectCodec } from '../schemas/general/MediaObject';
-import { Operation } from '@joystream/types/versioned-store/permissions/batching';
 import { OperationType } from '@joystream/types/versioned-store/permissions/batching/operation-types';
 import { ParametrizedEntity } from '@joystream/types/versioned-store/permissions/batching/parametrized-entity';
 import ParametrizedClassPropertyValue from '@joystream/types/versioned-store/permissions/batching/ParametrizedClassPropertyValue';
 import { ParametrizedPropertyValue } from '@joystream/types/versioned-store/permissions/batching/parametrized-property-value';
 import { ParameterizedClassPropertyValues } from '@joystream/types/versioned-store/permissions/batching/operations';
-import { useMyMembership } from '@polkadot/joy-utils/MyMembershipContext';
+import { useMyMembership } from '@polkadot/joy-utils/react/hooks';
 import { isAccountAChannelOwner } from '../channels/ChannelHelpers';
-import { JoyError } from '@polkadot/joy-utils/JoyStatus';
+import { JoyError } from '@polkadot/joy-utils/react/components';
+import { useApi } from '@polkadot/react-hooks';
 
 /** Example: "2019-01-23" -> 1548201600 */
 function humanDateToUnixTs (humanFriendlyDate: string): number | undefined {
@@ -87,6 +85,7 @@ const InnerForm = (props: MediaFormProps<OuterProps, FormValues>) => {
   } = props;
 
   const { myAccountId } = useMyMembership();
+  const { api } = useApi();
 
   const { thumbnail } = values;
 
@@ -103,9 +102,9 @@ const InnerForm = (props: MediaFormProps<OuterProps, FormValues>) => {
   }
 
   // Next consts are used in tx params:
-  const with_credential = new Option<Credential>(Credential, new Credential(2));
-  const as_entity_maintainer = new bool(false);
-  const schema_id = new u16(0);
+  const with_credential = api.createType('Option<Credential>', 2);
+  const as_entity_maintainer = api.createType('bool', false);
+  const schema_id = api.createType('u16', 0);
 
   const entityCodec = new VideoCodec(entityClass);
   const mediaObjectCodec = new MediaObjectCodec(mediaObjectClass);
@@ -155,15 +154,15 @@ const InnerForm = (props: MediaFormProps<OuterProps, FormValues>) => {
     return res;
   };
 
-  const indexOfCreateMediaObjectOperation = new u32(0);
+  const indexOfCreateMediaObjectOperation = api.createType('u32', 0);
 
-  const indexOfCreateVideoEntityOperation = new u32(2);
+  const indexOfCreateVideoEntityOperation = api.createType('u32', 2);
 
   const referToIdOfCreatedMediaObjectEntity = () =>
-    ParametrizedEntity.InternalEntityJustAdded(indexOfCreateMediaObjectOperation);
+    ParametrizedEntity.InternalEntityJustAdded(api.registry, indexOfCreateMediaObjectOperation);
 
   const referToIdOfCreatedVideoEntity = () =>
-    ParametrizedEntity.InternalEntityJustAdded(indexOfCreateVideoEntityOperation);
+    ParametrizedEntity.InternalEntityJustAdded(api.registry, indexOfCreateVideoEntityOperation);
 
   const newlyCreatedMediaObjectProp = () => {
     const inClassIndexOfMediaObject = entityCodec.inClassIndexOfProp(Fields.object.id);
@@ -171,9 +170,10 @@ const InnerForm = (props: MediaFormProps<OuterProps, FormValues>) => {
       throw new Error('Cannot not find an in-class index of "object" prop on Video entity.');
     }
 
-    return new ParametrizedClassPropertyValue({
-      in_class_index: new u16(inClassIndexOfMediaObject),
+    return api.createType('ParametrizedClassPropertyValue', {
+      in_class_index: inClassIndexOfMediaObject,
       value: ParametrizedPropertyValue.InternalEntityJustAdded(
+        api.registry,
         indexOfCreateMediaObjectOperation
       )
     });
@@ -185,9 +185,9 @@ const InnerForm = (props: MediaFormProps<OuterProps, FormValues>) => {
   ): ParameterizedClassPropertyValues => {
     const parametrizedProps = props.map(p => {
       const { in_class_index, value } = p;
-      return new ParametrizedClassPropertyValue({
+      return api.createType('ParametrizedClassPropertyValue', {
         in_class_index,
-        value: new ParametrizedPropertyValue({ PropertyValue: value })
+        value: api.createType('ParametrizedPropertyValue', { PropertyValue: value })
       });
     });
 
@@ -195,11 +195,11 @@ const InnerForm = (props: MediaFormProps<OuterProps, FormValues>) => {
       extra.forEach(x => parametrizedProps.push(x));
     }
 
-    return new ParameterizedClassPropertyValues(parametrizedProps);
+    return api.createType('Vec<ParametrizedClassPropertyValue>', parametrizedProps);
   };
 
   const newEntityOperation = (operation_type: OperationType) => {
-    return new Operation({
+    return api.createType('Operation', {
       with_credential,
       as_entity_maintainer,
       operation_type
@@ -209,6 +209,7 @@ const InnerForm = (props: MediaFormProps<OuterProps, FormValues>) => {
   const prepareTxParamsForCreateMediaObject = () => {
     return newEntityOperation(
       OperationType.CreateEntity(
+        api.registry,
         mediaObjectClass.id
       )
     );
@@ -224,6 +225,7 @@ const InnerForm = (props: MediaFormProps<OuterProps, FormValues>) => {
 
     return newEntityOperation(
       OperationType.AddSchemaSupportToEntity(
+        api.registry,
         referToIdOfCreatedMediaObjectEntity(),
         schema_id,
         propValues
@@ -234,6 +236,7 @@ const InnerForm = (props: MediaFormProps<OuterProps, FormValues>) => {
   const prepareTxParamsForCreateEntity = () => {
     return newEntityOperation(
       OperationType.CreateEntity(
+        api.registry,
         entityClass.id
       )
     );
@@ -249,6 +252,7 @@ const InnerForm = (props: MediaFormProps<OuterProps, FormValues>) => {
 
     return newEntityOperation(
       OperationType.AddSchemaSupportToEntity(
+        api.registry,
         referToIdOfCreatedVideoEntity(),
         schema_id,
         propValues
@@ -272,7 +276,7 @@ const InnerForm = (props: MediaFormProps<OuterProps, FormValues>) => {
     // Use for debug:
     // console.log('Batch entity operations:', ops)
 
-    return [new Vec(Operation, ops)];
+    return [api.createType('Vec<Operation>', ops)];
   };
 
   const buildUpdateEntityTxParams = () => {
@@ -376,7 +380,6 @@ const InnerForm = (props: MediaFormProps<OuterProps, FormValues>) => {
   const renderTransactionButton = () =>
     <TxButton
       type='submit'
-      size='large'
       isDisabled={!canSubmitTx()}
       label='Publish video'
       tx='versionedStorePermissions.transaction'
@@ -389,7 +392,6 @@ const InnerForm = (props: MediaFormProps<OuterProps, FormValues>) => {
   const renderUpdateEntityButton = () =>
     <TxButton
       type='submit'
-      size='large'
       isDisabled={!canSubmitTx()}
       label='Update video'
       tx='versionedStorePermissions.updateEntityPropertyValues'

+ 4 - 2
pioneer/packages/joy-media/src/video/PlayVideo.tsx

@@ -12,7 +12,8 @@ import { printExplicit, printReleaseDate, printLanguage } from '../entities/Enti
 import { MediaObjectType } from '../schemas/general/MediaObject';
 import { MediaPlayerWithResolver } from '../common/MediaPlayerWithResolver';
 import { ContentId } from '@joystream/types/media';
-import { JoyError } from '@polkadot/joy-utils/JoyStatus';
+import { JoyError } from '@polkadot/joy-utils/react/components';
+import { useApi } from '@polkadot/react-hooks';
 
 export type PlayVideoProps = {
   channel?: ChannelEntity;
@@ -36,6 +37,7 @@ function VertialListOfVideoPreviews (props: ListOfVideoPreviewProps) {
 
 export function PlayVideo (props: PlayVideoProps) {
   const { channel, mediaObject, video, moreChannelVideos = [], featuredVideos = [] } = props;
+  const { api } = useApi();
 
   if (!mediaObject || !video) {
     return <JoyError title={'Video was not found'} />;
@@ -80,7 +82,7 @@ export function PlayVideo (props: PlayVideoProps) {
   // TODO show video only to its owner, if the video is not public.
   // see isPublicVideo() function.
 
-  const contentId = ContentId.decode(mediaObject.value);
+  const contentId = ContentId.decode(api.registry, mediaObject.value);
 
   // console.log('PlayVideo: props', props)
 

+ 6 - 6
pioneer/packages/joy-media/src/video/PlayVideo.view.tsx

@@ -2,9 +2,8 @@ import React from 'react';
 import { RouteComponentProps } from 'react-router';
 import { MediaView } from '../MediaView';
 import { PlayVideoProps, PlayVideo } from './PlayVideo';
-import { ChannelId } from '@joystream/types/content-working-group';
-import { EntityId } from '@joystream/types/versioned-store';
-import { JoyError } from '@polkadot/joy-utils/JoyStatus';
+import { JoyError } from '@polkadot/joy-utils/react/components';
+import { useApi } from '@polkadot/react-hooks';
 
 type Props = PlayVideoProps;
 
@@ -12,12 +11,12 @@ export const PlayVideoView = MediaView<Props>({
   component: PlayVideo,
   triggers: ['id'],
   resolveProps: async (props) => {
-    const { transport, id } = props;
+    const { transport, api, id } = props;
 
     const video = await transport.videoById(id);
     if (!video) return {};
 
-    const channelId = new ChannelId(video.channelId);
+    const channelId = api.createType('ChannelId', video.channelId);
     const channel = await transport.channelById(channelId);
     const moreChannelVideos = (await transport.videosByChannelId(channelId, 5, x => x.id !== video.id));
     const featuredVideos = await transport.featuredVideos();
@@ -29,10 +28,11 @@ export const PlayVideoView = MediaView<Props>({
 
 export const PlayVideoWithRouter = (props: Props & RouteComponentProps<any>) => {
   const { match: { params: { id } } } = props;
+  const { api } = useApi();
 
   if (id) {
     try {
-      return <PlayVideoView {...props} id={new EntityId(id)} />;
+      return <PlayVideoView {...props} id={api.createType('EntityId', id)} />;
     } catch (err) {
       console.log('PlayVideoWithRouter failed:', err);
     }

+ 2 - 2
pioneer/packages/joy-media/src/video/VideoPreview.tsx

@@ -2,7 +2,7 @@ import React, { CSSProperties } from 'react';
 import { Link } from 'react-router-dom';
 import { BgImg } from '../common/BgImg';
 import { VideoType } from '../schemas/video/Video';
-import { useMyMembership } from '@polkadot/joy-utils/MyMembershipContext';
+import { useMyMembership } from '@polkadot/joy-utils/react/hooks';
 import { ChannelEntity } from '../entities/ChannelEntity';
 import { isAccountAChannelOwner } from '../channels/ChannelHelpers';
 import { ChannelAvatarAndName } from '../channels/ChannelAvatarAndName';
@@ -64,7 +64,7 @@ export function VideoPreview (props: VideoPreviewProps) {
         }
 
         {iAmOwner &&
-          <div>
+          <div style={{ marginTop: '0.5em' }}>
             <Link to={`/media/videos/${id}/edit`} className='ui button basic small'>
               <i className='icon pencil' />
               Edit

+ 4 - 4
pioneer/packages/old-apps/react-components/src/InputFileAsync.tsx → pioneer/packages/joy-utils/src/react/components/InputFileAsync.tsx

@@ -3,16 +3,16 @@
 // of the Apache-2.0 license. See the LICENSE file for details.
 
 import { WithTranslation } from 'react-i18next';
-import { BareProps } from './types';
+import { BareProps } from '@polkadot/react-components/types';
 
 import React, { useState, createRef } from 'react';
 import Dropzone, { DropzoneRef } from 'react-dropzone';
 import styled from 'styled-components';
 import { formatNumber } from '@polkadot/util';
 
-import { classes } from './util';
-import Labelled from './Labelled';
-import translate from './translate';
+import { classes } from '@polkadot/react-components/util';
+import Labelled from '@polkadot/react-components/Labelled';
+import translate from '@polkadot/react-components/translate';
 
 interface Props extends BareProps, WithTranslation {
   // Reference Example Usage: https://github.com/react-dropzone/react-dropzone/tree/master/examples/Accept

+ 1 - 1
pioneer/packages/joy-utils-old/src/JoyStatus.tsx → pioneer/packages/joy-utils/src/react/components/JoyStatus.tsx

@@ -1,6 +1,6 @@
 import React from 'react';
 import { Message } from 'semantic-ui-react';
-import { nonEmptyStr } from '.';
+import { nonEmptyStr } from '../../functions/misc';
 
 type BaseProps = {
   title?: React.ReactNode;

+ 0 - 0
pioneer/packages/joy-utils-old/src/Pluralize.tsx → pioneer/packages/joy-utils/src/react/components/Pluralize.tsx


+ 4 - 1
pioneer/packages/joy-utils/src/react/components/index.tsx

@@ -2,10 +2,13 @@ export { default as Section } from './Section';
 export { default as TxButton } from './TxButton';
 export { MutedSpan, MutedDiv } from './MutedText';
 export { FlexCenter } from './FlexCenter';
-export { default as PromiseComponent } from './PromiseComponent';
+export { default as PromiseComponent, Error, Loading } from './PromiseComponent';
 export { default as MemberByAccountPreview } from './MemberByAccountPreview';
 export { default as MemberProfilePreview } from './MemberProfilePreview';
 export { default as MembersDropdown } from './MembersDropdown';
 export { default as InputStake } from './InputStake';
 export { ApplicationsDetails, ApplicationsDetailsByIds } from './working-groups/ApplicationDetails';
 export { LeadInfo, LeadInfoFromId } from './working-groups/LeadInfo';
+export { JoyStatus, JoyError, JoyInfo, JoySuccess, JoyWarn } from './JoyStatus';
+export { Pluralize } from './Pluralize';
+export { default as InputFileAsync } from './InputFileAsync';

+ 111 - 6
pioneer/packages/joy-utils/src/react/hocs/accounts.tsx

@@ -7,11 +7,17 @@ import { withCalls, withMulti, withObservable, ApiContext } from '@polkadot/reac
 import { SubjectInfo } from '@polkadot/ui-keyring/observable/types';
 
 import { MemberId, Membership } from '@joystream/types/members';
-import { LeadId } from '@joystream/types/content-working-group';
+import { LeadId, Lead } from '@joystream/types/content-working-group';
 
 import { queryMembershipToProp } from '@polkadot/joy-members/utils';
 import useMyAccount from '../hooks/useMyAccount';
 import { componentName } from '../helpers';
+import { queryToProp } from '@polkadot/joy-utils/functions/misc';
+import { entriesByIds } from '@polkadot/joy-utils/transport/base';
+import { CuratorId, Curator } from '@joystream/types/content-working-group';
+import { useApi } from '@polkadot/react-hooks';
+import usePromise from '../hooks/usePromise';
+import { Error } from '../components/PromiseComponent';
 
 export type MyAddressProps = {
   myAddress?: string;
@@ -27,10 +33,9 @@ export type MyAccountProps = MyAddressProps & {
   myMembership?: Membership | null;
 
   // Content Working Group
-  curatorEntries?: any; // entire linked_map: CuratorId => Curator
   isLeadSet?: Option<LeadId>;
   contentLeadId?: LeadId;
-  contentLeadEntry?: any; // linked_map value
+  contentLead?: Lead; // linked_map value
 
   curationActor?: any;
   allAccounts?: SubjectInfo;
@@ -103,6 +108,106 @@ function resolveMyProfile<P extends { myMembership?: Membership | null }> (Compo
   return ResultComponent;
 }
 
+/* Content Working Group */
+function resolveLead<P extends MyAccountProps> (Component: React.ComponentType<P>) {
+  const ResultComponent: React.FunctionComponent<P> = (props: P) => {
+    const { isLeadSet } = props;
+
+    const newProps = {
+      contentLeadId: isLeadSet?.unwrapOr(undefined)
+    };
+
+    return <Component {...props} {...newProps} />;
+  };
+  ResultComponent.displayName = `resolveLead(${componentName(Component)})`;
+  return ResultComponent;
+}
+
+const resolveLeadEntry = withCalls<MyAccountProps>(
+  queryToProp('query.contentWorkingGroup.leadById', { propName: 'contentLead', paramName: 'contentLeadId' })
+);
+
+const withContentWorkingGroupDetails = withCalls<MyAccountProps>(
+  queryToProp('query.contentWorkingGroup.currentLeadId', { propName: 'isLeadSet' })
+);
+
+const withContentWorkingGroup = <P extends MyAccountProps>(Component: React.ComponentType<P>) =>
+  withMulti(Component, withContentWorkingGroupDetails, resolveLead, resolveLeadEntry);
+
+
+function withCurationActor<P extends MyAccountProps> (Component: React.ComponentType<P>) {
+  const ResultComponent: React.FunctionComponent<P> = (props: P) => {
+    const {
+      myAccountId,
+      isLeadSet,
+      contentLead,
+      allAccounts
+    } = props;
+    const { isApiReady, api } = useApi();
+    const [ curatorEntries, curatorsError, curatorsLoading ] = usePromise<[CuratorId, Curator][]>(
+      () => isApiReady
+        ? entriesByIds<CuratorId, Curator>(api.query.contentWorkingGroup.curatorById)
+        : new Promise(resolve => resolve([])),
+      [],
+      [isApiReady]
+    );
+
+    if (curatorsError) {
+      return <Error error={curatorsError} />;
+    }
+
+    if (!isApiReady || curatorsLoading || !myAccountId || !isLeadSet || !allAccounts) {
+      return <Component {...props} />;
+    }
+
+    const lead = isLeadSet.isSome && contentLead?.stage.isOfType('Active') ? contentLead : null;
+
+    const curationActorByAccount = (accountId: AccountId | string) => {
+      if (lead && lead.role_account.toString() === accountId.toString()) {
+        return api.createType('CurationActor', { Lead: null });
+      }
+
+      const matchingCuratorEntry = curatorEntries.find(([id, curator]) =>
+        curator.is_active && accountId.toString() === curator.role_account.toString()
+      );
+
+      return matchingCuratorEntry
+        ? api.createType('CurationActor', {
+          Curator: matchingCuratorEntry[0]
+        })
+        : null;
+    };
+
+    // First priority - currently selected account
+    let actor = curationActorByAccount(myAccountId);
+    let actorKey: AccountId | null = myAccountId;
+    // Second priority - check other keys and find best role
+    // TODO: Prioritize current member?
+    // TODO: Perhaps just don't do that at all and force the user to select the correct key to avoid confision?
+    if (!actor) {
+      const allActorsWithKeys = Object.keys(allAccounts).map(accKey => ({
+        actor: curationActorByAccount(allAccounts[accKey].json.address),
+        key: api.createType('AccountId', allAccounts[accKey].json.address)
+      }));
+      let actorWithKey = allActorsWithKeys.find(({ actor }) => actor?.isOfType('Lead'));
+      if (!actorWithKey) {
+        actorWithKey = allActorsWithKeys.find(({ actor }) => actor?.isOfType('Curator'));
+      }
+      actor = actorWithKey?.actor || null;
+      actorKey = actorWithKey?.key || null;
+    }
+
+    if (actor && actorKey) {
+      return <Component {...props} curationActor={[actor, actorKey]} />;
+    } else {
+      // we don't have any key that can fulfill a curation action
+      return <Component {...props} />;
+    }
+  };
+  ResultComponent.displayName = `withCurationActor(${componentName(Component)})`;
+  return ResultComponent;
+}
+
 const withMyProfileCall = withCalls<MyAccountProps>(queryMembershipToProp('membershipById', {
   paramName: 'myMemberId',
   propName: 'myMembership'
@@ -118,7 +223,7 @@ export const withMyAccount = <P extends MyAccountProps>(Component: React.Compone
     withMyAddress,
     withMyMemberIds,
     withMyMembership,
-    withMyProfile
-    // withContentWorkingGroup,
-    // withCurationActor
+    withMyProfile,
+    withContentWorkingGroup,
+    withCurationActor
   );

+ 1 - 30
pioneer/packages/joy-utils/src/react/hocs/guards.tsx

@@ -2,39 +2,10 @@ import React from 'react';
 import { Message } from 'semantic-ui-react';
 import { Link } from 'react-router-dom';
 
-import { AccountId } from '@polkadot/types/interfaces';
-import { Vec, Option } from '@polkadot/types';
 import { withMulti } from '@polkadot/react-api/index';
-import { SubjectInfo } from '@polkadot/ui-keyring/observable/types';
-
-import { MemberId, Membership } from '@joystream/types/members';
-import { LeadId } from '@joystream/types/content-working-group';
 import { useMyMembership } from '../hooks';
 import { componentName } from '../helpers';
-import { withMyAccount } from './accounts';
-
-export type MyAddressProps = {
-  myAddress?: string;
-};
-
-export type MyAccountProps = MyAddressProps & {
-  myAccountId?: AccountId;
-  myMemberId?: MemberId;
-  memberIdsByRootAccountId?: Vec<MemberId>;
-  memberIdsByControllerAccountId?: Vec<MemberId>;
-  myMemberIdChecked?: boolean;
-  iAmMember?: boolean;
-  myMembership?: Membership | null;
-
-  // Content Working Group
-  curatorEntries?: any; // entire linked_map: CuratorId => Curator
-  isLeadSet?: Option<LeadId>;
-  contentLeadId?: LeadId;
-  contentLeadEntry?: any; // linked_map value
-
-  curationActor?: any;
-  allAccounts?: SubjectInfo;
-};
+import { withMyAccount, MyAccountProps } from './accounts';
 
 export function MembershipRequired<P extends Record<string, unknown>> (Component: React.ComponentType<P>): React.ComponentType<P> {
   const ResultComponent: React.FunctionComponent<P> = (props: P) => {

+ 1 - 1
pioneer/packages/joy-utils/src/react/hooks/proposals/useProposalSubscription.tsx

@@ -1,5 +1,5 @@
 import { useState, useEffect } from 'react';
-import { useTransport } from '../';
+import useTransport from '../useTransport';
 import { ProposalId } from '@joystream/types/proposals';
 import { ParsedProposal } from '@polkadot/joy-utils/types/proposals';
 import { normalizeError } from '@polkadot/joy-utils/functions/misc';

+ 4 - 1
pioneer/packages/joy-utils-old/src/SimpleCache.ts → pioneer/packages/joy-utils/src/transport/SimpleCache.ts

@@ -1,5 +1,8 @@
 import BN from 'bn.js';
-import { IdLike, HasId } from './IdLike';
+
+export type IdLike = { toString: () => string } | number
+export type HasId = { id: IdLike }
+export type MayHaveId = { id?: IdLike }
 
 type LoadObjectsByIdsFn<Id extends IdLike, Obj extends HasId> =
   (ids: Id[]) => Promise<Obj[]>

+ 16 - 14
pioneer/packages/joy-utils/src/transport/base.ts

@@ -4,7 +4,21 @@ import { Codec, CodecArg } from '@polkadot/types/types';
 import { QueryableStorageEntry } from '@polkadot/api/types/storage';
 import { APIQueryCache } from './APIQueryCache';
 
-export default abstract class BaseTransport {
+export async function entriesByIds<IDType extends UInt, ValueType extends Codec> (
+  apiMethod: QueryableStorageEntry<'promise'>,
+  firstKey?: CodecArg // First key in case of double maps
+): Promise<[IDType, ValueType][]> {
+  const entries: [IDType, ValueType][] = (await apiMethod.entries<ValueType>(firstKey))
+    .map(([storageKey, value]) => ([
+      // If double-map (first key is provided), we map entries by second key
+      storageKey.args[firstKey !== undefined ? 1 : 0] as IDType,
+      value
+    ]));
+
+  return entries.sort((a, b) => a[0].toNumber() - b[0].toNumber());
+}
+
+export default class BaseTransport {
   protected api: ApiPromise;
   protected cacheApi: APIQueryCache;
 
@@ -67,17 +81,5 @@ export default abstract class BaseTransport {
     return this.api.query[module][method];
   }
 
-  protected async entriesByIds<IDType extends UInt, ValueType extends Codec> (
-    apiMethod: QueryableStorageEntry<'promise'>,
-    firstKey?: CodecArg // First key in case of double maps
-  ): Promise<[IDType, ValueType][]> {
-    const entries: [IDType, ValueType][] = (await apiMethod.entries<ValueType>(firstKey))
-      .map(([storageKey, value]) => ([
-        // If double-map (first key is provided), we map entries by second key
-        storageKey.args[firstKey !== undefined ? 1 : 0] as IDType,
-        value
-      ]));
-
-    return entries.sort((a, b) => a[0].toNumber() - b[0].toNumber());
-  }
+  protected entriesByIds = entriesByIds
 }

+ 14 - 12
pioneer/packages/joy-utils/src/transport/mock/base.ts

@@ -1,15 +1,17 @@
-export default abstract class BaseTransport {
-  protected promise<T> (value: T, timeout?: number): Promise<T> {
-    return new Promise<T>((resolve, reject) => {
-      if (timeout) {
-        (new Promise((resolve) => setTimeout(resolve, timeout)))
-          .then(() => resolve(value))
-          .catch((e) => { throw e; });
-      } else {
-        resolve(value);
-      }
-    });
-  }
+export function mockPromise<T> (value: T, timeout?: number): Promise<T> {
+  return new Promise<T>((resolve, reject) => {
+    if (timeout) {
+      (new Promise((resolve) => setTimeout(resolve, timeout)))
+        .then(() => resolve(value))
+        .catch((e) => { throw e; });
+    } else {
+      resolve(value);
+    }
+  });
+}
+
+export default class BaseTransport {
+  protected promise = mockPromise
 
   protected simulateApiResponse<T> (value: T): Promise<T> {
     return this.promise<T>(value, this.randomTimeout());

+ 4 - 0
pioneer/packages/joy-utils/src/transport/workingGroups.ts

@@ -153,4 +153,8 @@ export default class WorkingGroupsTransport extends BaseTransport {
     return (await this.openingApplications(group, wgOpeningId))
       .filter((a) => a.stage.isOfType('Active'));
   }
+
+  async allWorkers (group: WorkingGroupKey) {
+    return this.entriesByIds<WorkerId, Worker>(this.apiQueryByGroup(group).workerById);
+  }
 }

+ 0 - 0
pioneer/packages/joy-utils-old/src/ValidationConstraint.ts → pioneer/packages/joy-utils/src/types/ValidationConstraint.ts


+ 0 - 17
pioneer/packages/old-apps/apps-routing/src/joy-media.ts

@@ -1,17 +0,0 @@
-import { Routes } from './types';
-
-import Media from '@polkadot/joy-media/index';
-
-export default ([
-  {
-    Component: Media,
-    display: {
-      needsApi: []
-    },
-    i18n: {
-      defaultValue: 'Media'
-    },
-    icon: 'play circle outline',
-    name: 'media'
-  }
-] as Routes);

+ 0 - 1
pioneer/packages/old-apps/apps/src/aplayer.d.ts

@@ -1 +0,0 @@
-declare module 'react-aplayer';

+ 0 - 1
pioneer/packages/old-apps/apps/src/dplayer.d.ts

@@ -1 +0,0 @@
-declare module 'react-dplayer';

+ 5 - 0
pioneer/packages/react-components/src/styles/joystream.ts

@@ -131,6 +131,11 @@ export default css`
     color: #3b83c0;
   }
 
+  /* Main apps bg */
+  .apps-Main {
+    background: rgba(250,250,250);
+  }
+
   /* Remove IdentityIcon border (not working well for members list) */
   .ui--IdentityIcon {
     border: none !important;

+ 4 - 1
pioneer/tsconfig.json

@@ -6,7 +6,6 @@
     "packages/old-apps/**",
     "packages/joy-forum/**/*",
     "packages/joy-help/**/*",
-    "packages/joy-media/**/*",
     "packages/joy-settings/**/*",
     "packages/joy-utils-old/**/*"
   ],
@@ -17,6 +16,8 @@
     "resolveJsonModule": true,
     "baseUrl": ".",
     "paths": {
+      "@joystream/types/": [ "../types/src/" ],
+      "@joystream/types/*": [ "../types/src/*" ],
       "@polkadot/types/augment": [ "../types/augment-codec/augment-types.ts" ],
       "@polkadot/joy-election/": [ "packages/joy-election/src/" ],
       "@polkadot/joy-election/*": [ "packages/joy-election/src/*" ],
@@ -30,6 +31,8 @@
       "@polkadot/joy-roles/*": [ "packages/joy-roles/src/*" ],
       "@polkadot/joy-utils/": [ "packages/joy-utils/src/" ],
       "@polkadot/joy-utils/*": [ "packages/joy-utils/src/*" ],
+      "@polkadot/joy-media/": [ "packages/joy-media/src/" ],
+      "@polkadot/joy-media/*": [ "packages/joy-media/src/*" ],
       "@polkadot/apps/*": ["packages/apps/src/*"],
       "@polkadot/apps": ["packages/apps/src"],
       "@polkadot/apps-config/*": [ "packages/apps-config/src/*" ],

+ 26 - 26
types/augment-codec/augment-types.ts

@@ -11,9 +11,9 @@ import { Stake as Stake, StakingStatus as StakingStatus, Staked as Staked, Stake
 import { Mint as Mint, NextAdjustment as NextAdjustment, AdjustOnInterval as AdjustOnInterval, AdjustCapacityBy as AdjustCapacityBy } from '../mint'
 import { Recipient as Recipient, RewardRelationship as RewardRelationship } from '../recurring-rewards'
 import { Application as Application, ApplicationStage as ApplicationStage, ActivateOpeningAt as ActivateOpeningAt, ApplicationRationingPolicy as ApplicationRationingPolicy, OpeningStage as OpeningStage, StakingPolicy as StakingPolicy, Opening as Opening, WaitingToBeingOpeningStageVariant as WaitingToBeingOpeningStageVariant, ActiveOpeningStageVariant as ActiveOpeningStageVariant, ActiveOpeningStage as ActiveOpeningStage, AcceptingApplications as AcceptingApplications, ReviewPeriod as ReviewPeriod, Deactivated as Deactivated, OpeningDeactivationCause as OpeningDeactivationCause, InactiveApplicationStage as InactiveApplicationStage, UnstakingApplicationStage as UnstakingApplicationStage, ApplicationDeactivationCause as ApplicationDeactivationCause, StakingAmountLimitMode as StakingAmountLimitMode } from '../hiring'
-import { Class as Class, Entity as Entity, ClassSchema as ClassSchema, Property as Property, PropertyType as PropertyType, PropertyValue as PropertyValue, ClassPropertyValue as ClassPropertyValue } from '../versioned-store'
+import { ClassId as ClassId, EntityId as EntityId, Class as Class, Entity as Entity, ClassSchema as ClassSchema, Property as Property, PropertyType as PropertyType, PropertyValue as PropertyValue, ClassPropertyValue as ClassPropertyValue } from '../versioned-store'
 import { EntityPermissions as EntityPermissions, ReferenceConstraint as ReferenceConstraint, ClassPermissionsType as ClassPermissionsType, Operation as Operation, OperationType as OperationType, CreateEntity as CreateEntity, UpdatePropertyValues as UpdatePropertyValues, AddSchemaSupportToEntity as AddSchemaSupportToEntity, ParametrizedEntity as ParametrizedEntity, ParametrizedClassPropertyValue as ParametrizedClassPropertyValue, ParametrizedPropertyValue as ParametrizedPropertyValue, PropertyOfClass as PropertyOfClass } from '../versioned-store/permissions'
-import { OptionalText as OptionalText, Channel as Channel, ChannelContentType as ChannelContentType, ChannelCurationStatus as ChannelCurationStatus, ChannelPublicationStatus as ChannelPublicationStatus, CurationActor as CurationActor, Curator as Curator, CuratorApplication as CuratorApplication, CuratorOpening as CuratorOpening, Lead as Lead, OpeningPolicyCommitment as OpeningPolicyCommitment, Principal as Principal, WorkingGroupUnstaker as WorkingGroupUnstaker, CuratorApplicationIdToCuratorIdMap as CuratorApplicationIdToCuratorIdMap, CuratorApplicationIdSet as CuratorApplicationIdSet, CuratorRoleStakeProfile as CuratorRoleStakeProfile, CuratorRoleStage as CuratorRoleStage, CuratorExitSummary as CuratorExitSummary, CuratorExitInitiationOrigin as CuratorExitInitiationOrigin, LeadRoleState as LeadRoleState, ExitedLeadRole as ExitedLeadRole, CuratorInduction as CuratorInduction } from '../content-working-group'
+import { ChannelId as ChannelId, CuratorId as CuratorId, CuratorOpeningId as CuratorOpeningId, CuratorApplicationId as CuratorApplicationId, LeadId as LeadId, PrincipalId as PrincipalId, OptionalText as OptionalText, Channel as Channel, ChannelContentType as ChannelContentType, ChannelCurationStatus as ChannelCurationStatus, ChannelPublicationStatus as ChannelPublicationStatus, CurationActor as CurationActor, Curator as Curator, CuratorApplication as CuratorApplication, CuratorOpening as CuratorOpening, Lead as Lead, OpeningPolicyCommitment as OpeningPolicyCommitment, Principal as Principal, WorkingGroupUnstaker as WorkingGroupUnstaker, CuratorApplicationIdToCuratorIdMap as CuratorApplicationIdToCuratorIdMap, CuratorApplicationIdSet as CuratorApplicationIdSet, CuratorRoleStakeProfile as CuratorRoleStakeProfile, CuratorRoleStage as CuratorRoleStage, CuratorExitSummary as CuratorExitSummary, CuratorExitInitiationOrigin as CuratorExitInitiationOrigin, LeadRoleState as LeadRoleState, ExitedLeadRole as ExitedLeadRole, CuratorInduction as CuratorInduction } from '../content-working-group'
 import { RationaleText as RationaleText, Application as ApplicationOf, ApplicationIdSet as ApplicationIdSet, ApplicationIdToWorkerIdMap as ApplicationIdToWorkerIdMap, WorkerId as WorkerId, Worker as WorkerOf, Opening as OpeningOf, StorageProviderId as StorageProviderId, OpeningType as OpeningType, ApplicationId as HiringApplicationId, RewardPolicy as RewardPolicy, WorkingGroupOpeningPolicyCommitment as WorkingGroupOpeningPolicyCommitment, RoleStakeProfile as RoleStakeProfile } from '../working-group'
 import { Url as Url, IPNSIdentity as IPNSIdentity, ServiceProviderRecord as ServiceProviderRecord } from '../discovery'
 import { ContentId as ContentId, LiaisonJudgement as LiaisonJudgement, DataObject as DataObject, DataObjectStorageRelationshipId as DataObjectStorageRelationshipId, DataObjectStorageRelationship as DataObjectStorageRelationship, DataObjectTypeId as DataObjectTypeId, DataObjectType as DataObjectType, DataObjectsMap as DataObjectsMap } from '../media'
@@ -286,12 +286,12 @@ declare module '@polkadot/types/types/registry' {
     "StakingAmountLimitMode": StakingAmountLimitMode;
     "Option<StakingAmountLimitMode>": Option<StakingAmountLimitMode>;
     "Vec<StakingAmountLimitMode>": Vec<StakingAmountLimitMode>;
-    "ClassId": u64;
-    "Option<ClassId>": Option<u64>;
-    "Vec<ClassId>": Vec<u64>;
-    "EntityId": u64;
-    "Option<EntityId>": Option<u64>;
-    "Vec<EntityId>": Vec<u64>;
+    "ClassId": ClassId;
+    "Option<ClassId>": Option<ClassId>;
+    "Vec<ClassId>": Vec<ClassId>;
+    "EntityId": EntityId;
+    "Option<EntityId>": Option<EntityId>;
+    "Vec<EntityId>": Vec<EntityId>;
     "Class": Class;
     "Option<Class>": Option<Class>;
     "Vec<Class>": Vec<Class>;
@@ -349,24 +349,24 @@ declare module '@polkadot/types/types/registry' {
     "PropertyOfClass": PropertyOfClass;
     "Option<PropertyOfClass>": Option<PropertyOfClass>;
     "Vec<PropertyOfClass>": Vec<PropertyOfClass>;
-    "ChannelId": u64;
-    "Option<ChannelId>": Option<u64>;
-    "Vec<ChannelId>": Vec<u64>;
-    "CuratorId": u64;
-    "Option<CuratorId>": Option<u64>;
-    "Vec<CuratorId>": Vec<u64>;
-    "CuratorOpeningId": u64;
-    "Option<CuratorOpeningId>": Option<u64>;
-    "Vec<CuratorOpeningId>": Vec<u64>;
-    "CuratorApplicationId": u64;
-    "Option<CuratorApplicationId>": Option<u64>;
-    "Vec<CuratorApplicationId>": Vec<u64>;
-    "LeadId": u64;
-    "Option<LeadId>": Option<u64>;
-    "Vec<LeadId>": Vec<u64>;
-    "PrincipalId": u64;
-    "Option<PrincipalId>": Option<u64>;
-    "Vec<PrincipalId>": Vec<u64>;
+    "ChannelId": ChannelId;
+    "Option<ChannelId>": Option<ChannelId>;
+    "Vec<ChannelId>": Vec<ChannelId>;
+    "CuratorId": CuratorId;
+    "Option<CuratorId>": Option<CuratorId>;
+    "Vec<CuratorId>": Vec<CuratorId>;
+    "CuratorOpeningId": CuratorOpeningId;
+    "Option<CuratorOpeningId>": Option<CuratorOpeningId>;
+    "Vec<CuratorOpeningId>": Vec<CuratorOpeningId>;
+    "CuratorApplicationId": CuratorApplicationId;
+    "Option<CuratorApplicationId>": Option<CuratorApplicationId>;
+    "Vec<CuratorApplicationId>": Vec<CuratorApplicationId>;
+    "LeadId": LeadId;
+    "Option<LeadId>": Option<LeadId>;
+    "Vec<LeadId>": Vec<LeadId>;
+    "PrincipalId": PrincipalId;
+    "Option<PrincipalId>": Option<PrincipalId>;
+    "Vec<PrincipalId>": Vec<PrincipalId>;
     "OptionalText": OptionalText;
     "Option<OptionalText>": Option<OptionalText>;
     "Vec<OptionalText>": Vec<OptionalText>;

+ 20 - 20
types/augment/all/defs.json

@@ -353,15 +353,15 @@
     "ClassId": "u64",
     "EntityId": "u64",
     "Class": {
-        "id": "u64",
+        "id": "ClassId",
         "properties": "Vec<Property>",
         "schemas": "Vec<ClassSchema>",
         "name": "Text",
         "description": "Text"
     },
     "Entity": {
-        "id": "u64",
-        "class_id": "u64",
+        "id": "EntityId",
+        "class_id": "ClassId",
         "in_class_schema_indexes": "Vec<u16>"
     },
     "ClassSchema": {
@@ -393,7 +393,7 @@
             "Int32Vec": "u16",
             "Int64Vec": "u16",
             "TextVec": "(u16,u16)",
-            "InternalVec": "(u16,u64)"
+            "InternalVec": "(u16,ClassId)"
         }
     },
     "PropertyValue": {
@@ -416,7 +416,7 @@
             "Int32Vec": "Vec<i32>",
             "Int64Vec": "Vec<i64>",
             "TextVec": "Vec<Text>",
-            "InternalVec": "Vec<u64>"
+            "InternalVec": "Vec<EntityId>"
         }
     },
     "ClassPropertyValue": {
@@ -456,7 +456,7 @@
         }
     },
     "CreateEntity": {
-        "class_id": "u64"
+        "class_id": "ClassId"
     },
     "UpdatePropertyValues": {
         "entity_id": "ParametrizedEntity",
@@ -485,7 +485,7 @@
         }
     },
     "PropertyOfClass": {
-        "class_id": "u64",
+        "class_id": "ClassId",
         "property_index": "u16"
     },
     "ChannelId": "u64",
@@ -508,7 +508,7 @@
         "publication_status": "ChannelPublicationStatus",
         "curation_status": "ChannelCurationStatus",
         "created": "u32",
-        "principal_id": "u64"
+        "principal_id": "PrincipalId"
     },
     "ChannelContentType": {
         "_enum": [
@@ -532,7 +532,7 @@
     "CurationActor": {
         "_enum": {
             "Lead": "Null",
-            "Curator": "u64"
+            "Curator": "CuratorId"
         }
     },
     "Curator": {
@@ -541,17 +541,17 @@
         "role_stake_profile": "Option<CuratorRoleStakeProfile>",
         "stage": "CuratorRoleStage",
         "induction": "CuratorInduction",
-        "principal_id": "u64"
+        "principal_id": "PrincipalId"
     },
     "CuratorApplication": {
         "role_account": "GenericAccountId",
-        "curator_opening_id": "u64",
+        "curator_opening_id": "CuratorOpeningId",
         "member_id": "MemberId",
         "application_id": "HiringApplicationId"
     },
     "CuratorOpening": {
         "opening_id": "u64",
-        "curator_applications": "Vec<u64>",
+        "curator_applications": "Vec<CuratorApplicationId>",
         "policy_commitment": "OpeningPolicyCommitment"
     },
     "Lead": {
@@ -578,18 +578,18 @@
     "Principal": {
         "_enum": {
             "Lead": "Null",
-            "Curator": "u64",
-            "ChannelOwner": "u64"
+            "Curator": "CuratorId",
+            "ChannelOwner": "ChannelId"
         }
     },
     "WorkingGroupUnstaker": {
         "_enum": {
-            "Lead": "u64",
-            "Curator": "u64"
+            "Lead": "LeadId",
+            "Curator": "CuratorId"
         }
     },
-    "CuratorApplicationIdToCuratorIdMap": "BTreeMap<HiringApplicationId,u64>",
-    "CuratorApplicationIdSet": "Vec<u64>",
+    "CuratorApplicationIdToCuratorIdMap": "BTreeMap<HiringApplicationId,CuratorId>",
+    "CuratorApplicationIdSet": "Vec<CuratorApplicationId>",
     "CuratorRoleStakeProfile": {
         "stake_id": "u64",
         "termination_unstaking_period": "Option<u32>",
@@ -623,8 +623,8 @@
         "initiated_at_block_number": "u32"
     },
     "CuratorInduction": {
-        "lead": "u64",
-        "curator_application_id": "u64",
+        "lead": "LeadId",
+        "curator_application_id": "CuratorApplicationId",
         "at_block": "u32"
     },
     "RationaleText": "Bytes",

+ 20 - 20
types/augment/all/types.ts

@@ -192,7 +192,7 @@ export interface Channel extends Struct {
   readonly publication_status: ChannelPublicationStatus;
   readonly curation_status: ChannelCurationStatus;
   readonly created: u32;
-  readonly principal_id: u64;
+  readonly principal_id: PrincipalId;
 }
 
 /** @name ChannelContentType */
@@ -225,7 +225,7 @@ export interface ChildPositionInParentCategory extends Struct {
 
 /** @name Class */
 export interface Class extends Struct {
-  readonly id: u64;
+  readonly id: ClassId;
   readonly properties: Vec<Property>;
   readonly schemas: Vec<ClassSchema>;
   readonly name: Text;
@@ -262,7 +262,7 @@ export interface ContentId extends U8aFixed {}
 
 /** @name CreateEntity */
 export interface CreateEntity extends Struct {
-  readonly class_id: u64;
+  readonly class_id: ClassId;
 }
 
 /** @name Credential */
@@ -275,7 +275,7 @@ export interface CredentialSet extends Vec<Credential> {}
 export interface CurationActor extends Enum {
   readonly isLead: boolean;
   readonly isCurator: boolean;
-  readonly asCurator: u64;
+  readonly asCurator: CuratorId;
 }
 
 /** @name Curator */
@@ -285,13 +285,13 @@ export interface Curator extends Struct {
   readonly role_stake_profile: Option<CuratorRoleStakeProfile>;
   readonly stage: CuratorRoleStage;
   readonly induction: CuratorInduction;
-  readonly principal_id: u64;
+  readonly principal_id: PrincipalId;
 }
 
 /** @name CuratorApplication */
 export interface CuratorApplication extends Struct {
   readonly role_account: GenericAccountId;
-  readonly curator_opening_id: u64;
+  readonly curator_opening_id: CuratorOpeningId;
   readonly member_id: MemberId;
   readonly application_id: HiringApplicationId;
 }
@@ -300,10 +300,10 @@ export interface CuratorApplication extends Struct {
 export interface CuratorApplicationId extends u64 {}
 
 /** @name CuratorApplicationIdSet */
-export interface CuratorApplicationIdSet extends Vec<u64> {}
+export interface CuratorApplicationIdSet extends Vec<CuratorApplicationId> {}
 
 /** @name CuratorApplicationIdToCuratorIdMap */
-export interface CuratorApplicationIdToCuratorIdMap extends BTreeMap<HiringApplicationId, u64> {}
+export interface CuratorApplicationIdToCuratorIdMap extends BTreeMap<HiringApplicationId, CuratorId> {}
 
 /** @name CuratorExitInitiationOrigin */
 export interface CuratorExitInitiationOrigin extends Enum {
@@ -323,15 +323,15 @@ export interface CuratorId extends u64 {}
 
 /** @name CuratorInduction */
 export interface CuratorInduction extends Struct {
-  readonly lead: u64;
-  readonly curator_application_id: u64;
+  readonly lead: LeadId;
+  readonly curator_application_id: CuratorApplicationId;
   readonly at_block: u32;
 }
 
 /** @name CuratorOpening */
 export interface CuratorOpening extends Struct {
   readonly opening_id: u64;
-  readonly curator_applications: Vec<u64>;
+  readonly curator_applications: Vec<CuratorApplicationId>;
   readonly policy_commitment: OpeningPolicyCommitment;
 }
 
@@ -441,8 +441,8 @@ export interface ElectionStake extends Struct {
 
 /** @name Entity */
 export interface Entity extends Struct {
-  readonly id: u64;
-  readonly class_id: u64;
+  readonly id: EntityId;
+  readonly class_id: ClassId;
   readonly in_class_schema_indexes: Vec<u16>;
 }
 
@@ -724,9 +724,9 @@ export interface PostTextChange extends Struct {
 export interface Principal extends Enum {
   readonly isLead: boolean;
   readonly isCurator: boolean;
-  readonly asCurator: u64;
+  readonly asCurator: CuratorId;
   readonly isChannelOwner: boolean;
-  readonly asChannelOwner: u64;
+  readonly asChannelOwner: ChannelId;
 }
 
 /** @name PrincipalId */
@@ -742,7 +742,7 @@ export interface Property extends Struct {
 
 /** @name PropertyOfClass */
 export interface PropertyOfClass extends Struct {
-  readonly class_id: u64;
+  readonly class_id: ClassId;
   readonly property_index: u16;
 }
 
@@ -777,7 +777,7 @@ export interface PropertyType extends Enum {
   readonly isTextVec: boolean;
   readonly asTextVec: ITuple<[u16, u16]>;
   readonly isInternalVec: boolean;
-  readonly asInternalVec: ITuple<[u16, u64]>;
+  readonly asInternalVec: ITuple<[u16, ClassId]>;
 }
 
 /** @name PropertyValue */
@@ -818,7 +818,7 @@ export interface PropertyValue extends Enum {
   readonly isTextVec: boolean;
   readonly asTextVec: Vec<Text>;
   readonly isInternalVec: boolean;
-  readonly asInternalVec: Vec<u64>;
+  readonly asInternalVec: Vec<EntityId>;
 }
 
 /** @name ProposalDecisionStatus */
@@ -1234,9 +1234,9 @@ export interface WorkingGroupOpeningPolicyCommitment extends Struct {
 /** @name WorkingGroupUnstaker */
 export interface WorkingGroupUnstaker extends Enum {
   readonly isLead: boolean;
-  readonly asLead: u64;
+  readonly asLead: LeadId;
   readonly isCurator: boolean;
-  readonly asCurator: u64;
+  readonly asCurator: CuratorId;
 }
 
 export type PHANTOM_ALL = 'all';

+ 0 - 50
types/augment/augment-api-consts.ts

@@ -31,56 +31,6 @@ declare module '@polkadot/metadata/Decorated/consts/types' {
        **/
       existentialDeposit: AugmentedConst<Balance>;
     };
-    contracts: {
-      /**
-       * The maximum nesting level of a call/instantiate stack. A reasonable default
-       * value is 100.
-       **/
-      maxDepth: AugmentedConst<u32>;
-      /**
-       * The maximum size of a storage value in bytes. A reasonable default is 16 KiB.
-       **/
-      maxValueSize: AugmentedConst<u32>;
-      /**
-       * Price of a byte of storage per one block interval. Should be greater than 0.
-       **/
-      rentByteFee: AugmentedConst<BalanceOf>;
-      /**
-       * The amount of funds a contract should deposit in order to offset
-       * the cost of one byte.
-       * 
-       * Let's suppose the deposit is 1,000 BU (balance units)/byte and the rent is 1 BU/byte/day,
-       * then a contract with 1,000,000 BU that uses 1,000 bytes of storage would pay no rent.
-       * But if the balance reduced to 500,000 BU and the storage stayed the same at 1,000,
-       * then it would pay 500 BU/day.
-       **/
-      rentDepositOffset: AugmentedConst<BalanceOf>;
-      /**
-       * Number of block delay an extrinsic claim surcharge has.
-       * 
-       * When claim surcharge is called by an extrinsic the rent is checked
-       * for current_block - delay
-       **/
-      signedClaimHandicap: AugmentedConst<BlockNumber>;
-      /**
-       * A size offset for an contract. A just created account with untouched storage will have that
-       * much of storage from the perspective of the state rent.
-       * 
-       * This is a simple way to ensure that contracts with empty storage eventually get deleted
-       * by making them pay rent. This creates an incentive to remove them early in order to save
-       * rent.
-       **/
-      storageSizeOffset: AugmentedConst<u32>;
-      /**
-       * Reward that is received by the party whose touch has led
-       * to removal of a contract.
-       **/
-      surchargeReward: AugmentedConst<BalanceOf>;
-      /**
-       * The minimum amount required to generate a tombstone.
-       **/
-      tombstoneDeposit: AugmentedConst<BalanceOf>;
-    };
     dataDirectory: {
       /**
        * Maximum objects allowed per inject_data_objects() transaction

+ 4 - 29
types/augment/augment-api-query.ts

@@ -4,12 +4,11 @@
 import { AnyNumber, ITuple, Observable } from '@polkadot/types/types';
 import { Option, Vec } from '@polkadot/types/codec';
 import { Bytes, bool, u32, u64 } from '@polkadot/types/primitive';
-import { Application, ApplicationId, ApplicationOf, Category, CategoryId, Channel, ChannelId, Class, ClassId, ClassPermissionsType, ContentId, Credential, Curator, CuratorApplication, CuratorApplicationId, CuratorId, CuratorOpening, CuratorOpeningId, DataObject, DataObjectStorageRelationship, DataObjectStorageRelationshipId, DataObjectType, DataObjectTypeId, DiscussionPost, DiscussionThread, ElectionStage, ElectionStake, Entity, EntityId, HiringApplicationId, InputValidationLengthConstraint, Lead, LeadId, MemberId, Membership, MemoText, Mint, MintId, Opening, OpeningId, OpeningOf, PaidMembershipTerms, PaidTermId, Post, PostId, Principal, PrincipalId, ProposalDetailsOf, ProposalId, ProposalOf, Recipient, RecipientId, RewardRelationship, RewardRelationshipId, SealedVote, Seats, Stake, StakeId, StorageProviderId, Thread, ThreadCounter, ThreadId, TransferableStake, Url, VoteKind, WorkerId, WorkerOf, WorkingGroupUnstaker } from './all';
+import { Application, ApplicationId, ApplicationOf, Category, CategoryId, Channel, ChannelId, Class, ClassId, ClassPermissionsType, ContentId, Credential, Curator, CuratorApplication, CuratorApplicationId, CuratorId, CuratorOpening, CuratorOpeningId, DataObject, DataObjectStorageRelationship, DataObjectStorageRelationshipId, DataObjectType, DataObjectTypeId, DiscussionPost, DiscussionThread, ElectionStage, ElectionStake, Entity, EntityId, HiringApplicationId, InputValidationLengthConstraint, Lead, LeadId, MemberId, Membership, MemoText, Mint, MintId, Opening, OpeningId, OpeningOf, PaidMembershipTerms, PaidTermId, Post, PostId, Principal, PrincipalId, ProposalDetailsOf, ProposalId, ProposalOf, Recipient, RecipientId, RewardRelationship, RewardRelationshipId, SealedVote, Seats, ServiceProviderRecord, Stake, StakeId, StorageProviderId, Thread, ThreadCounter, ThreadId, TransferableStake, Url, VoteKind, WorkerId, WorkerOf, WorkingGroupUnstaker } from './all';
 import { UncleEntryItem } from '@polkadot/types/interfaces/authorship';
 import { BabeAuthorityWeight, MaybeRandomness, NextConfigDescriptor, Randomness } from '@polkadot/types/interfaces/babe';
 import { AccountData, BalanceLock } from '@polkadot/types/interfaces/balances';
 import { AuthorityId } from '@polkadot/types/interfaces/consensus';
-import { CodeHash, ContractInfo, PrefabWasmModule, Schedule } from '@polkadot/types/interfaces/contracts';
 import { SetId, StoredPendingChange, StoredState } from '@polkadot/types/interfaces/grandpa';
 import { AuthIndex } from '@polkadot/types/interfaces/imOnline';
 import { DeferredOffenceOf, Kind, OffenceDetails, OpaqueTimeSlot, ReportIdOf } from '@polkadot/types/interfaces/offences';
@@ -208,30 +207,6 @@ declare module '@polkadot/api/types/storage' {
        **/
       unstakerByStakeId: AugmentedQuery<ApiType, (arg: StakeId | AnyNumber | Uint8Array) => Observable<WorkingGroupUnstaker>>;
     };
-    contracts: {
-      /**
-       * The subtrie counter.
-       **/
-      accountCounter: AugmentedQuery<ApiType, () => Observable<u64>>;
-      /**
-       * A mapping between an original code hash and instrumented wasm code, ready for execution.
-       **/
-      codeStorage: AugmentedQuery<ApiType, (arg: CodeHash | string | Uint8Array) => Observable<Option<PrefabWasmModule>>>;
-      /**
-       * The code associated with a given account.
-       * 
-       * TWOX-NOTE: SAFE since `AccountId` is a secure hash.
-       **/
-      contractInfoOf: AugmentedQuery<ApiType, (arg: AccountId | string | Uint8Array) => Observable<Option<ContractInfo>>>;
-      /**
-       * Current cost schedule for contracts.
-       **/
-      currentSchedule: AugmentedQuery<ApiType, () => Observable<Schedule>>;
-      /**
-       * A mapping from an original code hash to the original code, untouched by instrumentation.
-       **/
-      pristineCode: AugmentedQuery<ApiType, (arg: CodeHash | string | Uint8Array) => Observable<Option<Bytes>>>;
-    };
     council: {
       activeCouncil: AugmentedQuery<ApiType, () => Observable<Seats>>;
       /**
@@ -323,15 +298,15 @@ declare module '@polkadot/api/types/storage' {
     };
     discovery: {
       /**
-       * Mapping of service providers' storage provider id to their AccountInfo
+       * Mapping of service providers' storage provider id to their ServiceProviderRecord
        **/
-      accountInfoByStorageProviderId: AugmentedQuery<ApiType, (arg: StorageProviderId | AnyNumber | Uint8Array) => Observable<AccountInfo>>;
+      accountInfoByStorageProviderId: AugmentedQuery<ApiType, (arg: StorageProviderId | AnyNumber | Uint8Array) => Observable<ServiceProviderRecord>>;
       /**
        * Bootstrap endpoints maintained by root
        **/
       bootstrapEndpoints: AugmentedQuery<ApiType, () => Observable<Vec<Url>>>;
       /**
-       * Lifetime of an AccountInfo record in AccountInfoByAccountId map
+       * Lifetime of an ServiceProviderRecord record in AccountInfoByAccountId map
        **/
       defaultLifetime: AugmentedQuery<ApiType, () => Observable<BlockNumber>>;
     };

+ 2 - 47
types/augment/augment-api-tx.ts

@@ -5,7 +5,6 @@ import { AnyNumber, ITuple } from '@polkadot/types/types';
 import { Compact, Option, Vec } from '@polkadot/types/codec';
 import { Bytes, bool, u16, u32, u64 } from '@polkadot/types/primitive';
 import { ActivateOpeningAt, AddOpeningParameters, ApplicationId, ApplicationIdSet, BalanceOfMint, CategoryId, ChannelContentType, ChannelCurationStatus, ChannelId, ChannelPublicationStatus, ClassId, ClassPermissionsType, ClassPropertyValue, ContentId, Credential, CredentialSet, CurationActor, CuratorApplicationId, CuratorApplicationIdSet, CuratorId, CuratorOpeningId, DataObjectStorageRelationshipId, DataObjectType, DataObjectTypeId, DataObjectsMap, ElectionParameters, EntityId, EntityPermissions, FillOpeningParameters, MemberId, MemoText, OpeningId, OpeningPolicyCommitment, OpeningType, Operation, OptionalText, PaidTermId, PostId, Property, ProposalId, ReferenceConstraint, RewardPolicy, StorageProviderId, TerminateRoleParameters, ThreadId, Url, VoteKind, WorkerId, WorkingGroup } from './all';
-import { CodeHash, Gas, Schedule } from '@polkadot/types/interfaces/contracts';
 import { Extrinsic, Signature } from '@polkadot/types/interfaces/extrinsics';
 import { GrandpaEquivocationProof, KeyOwnerProof } from '@polkadot/types/interfaces/grandpa';
 import { Heartbeat } from '@polkadot/types/interfaces/imOnline';
@@ -186,50 +185,6 @@ declare module '@polkadot/api/types/submittable' {
       updateCuratorRoleAccount: AugmentedSubmittable<(memberId: MemberId | AnyNumber | Uint8Array, curatorId: CuratorId | AnyNumber | Uint8Array, newRoleAccount: AccountId | string | Uint8Array) => SubmittableExtrinsic<ApiType>>;
       withdrawCuratorApplication: AugmentedSubmittable<(curatorApplicationId: CuratorApplicationId | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>>;
     };
-    contracts: {
-      /**
-       * Makes a call to an account, optionally transferring some balance.
-       * 
-       * * If the account is a smart-contract account, the associated code will be
-       * executed and any value will be transferred.
-       * * If the account is a regular account, any value will be transferred.
-       * * If no account exists and the call value is not less than `existential_deposit`,
-       * a regular account will be created and any value will be transferred.
-       **/
-      call: AugmentedSubmittable<(dest: LookupSource | string | Uint8Array, value: Compact<BalanceOf> | AnyNumber | Uint8Array, gasLimit: Compact<Gas> | AnyNumber | Uint8Array, data: Bytes | string | Uint8Array) => SubmittableExtrinsic<ApiType>>;
-      /**
-       * Allows block producers to claim a small reward for evicting a contract. If a block producer
-       * fails to do so, a regular users will be allowed to claim the reward.
-       * 
-       * If contract is not evicted as a result of this call, no actions are taken and
-       * the sender is not eligible for the reward.
-       **/
-      claimSurcharge: AugmentedSubmittable<(dest: AccountId | string | Uint8Array, auxSender: Option<AccountId> | null | object | string | Uint8Array) => SubmittableExtrinsic<ApiType>>;
-      /**
-       * Instantiates a new contract from the `codehash` generated by `put_code`, optionally transferring some balance.
-       * 
-       * Instantiation is executed as follows:
-       * 
-       * - The destination address is computed based on the sender and hash of the code.
-       * - The smart-contract account is created at the computed address.
-       * - The `ctor_code` is executed in the context of the newly-created account. Buffer returned
-       * after the execution is saved as the `code` of the account. That code will be invoked
-       * upon any call received by this account.
-       * - The contract is initialized.
-       **/
-      instantiate: AugmentedSubmittable<(endowment: Compact<BalanceOf> | AnyNumber | Uint8Array, gasLimit: Compact<Gas> | AnyNumber | Uint8Array, codeHash: CodeHash | string | Uint8Array, data: Bytes | string | Uint8Array) => SubmittableExtrinsic<ApiType>>;
-      /**
-       * Stores the given binary Wasm code into the chain's storage and returns its `codehash`.
-       * You can instantiate contracts only with stored code.
-       **/
-      putCode: AugmentedSubmittable<(code: Bytes | string | Uint8Array) => SubmittableExtrinsic<ApiType>>;
-      /**
-       * Updates the schedule for metering contracts.
-       * 
-       * The schedule must have a greater version than the stored schedule.
-       **/
-      updateSchedule: AugmentedSubmittable<(schedule: Schedule | { version?: any; putCodePerByteCost?: any; growMemCost?: any; regularOpCost?: any; returnDataPerByteCost?: any; eventDataPerByteCost?: any; eventPerTopicCost?: any; eventBaseCost?: any; sandboxDataReadCost?: any; sandboxDataWriteCost?: any; transferCost?: any; maxEventTopics?: any; maxStackHeight?: any; maxMemoryPages?: any; enablePrintln?: any; maxSubjectLen?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>>;
-    };
     council: {
       /**
        * Adds a zero staked council member. A member added in this way does not get a recurring reward.
@@ -357,12 +312,12 @@ declare module '@polkadot/api/types/submittable' {
        **/
       setDefaultLifetime: AugmentedSubmittable<(lifetime: BlockNumber | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>>;
       /**
-       * Creates the AccountInfo to save an IPNS identity for the storage provider.
+       * Creates the ServiceProviderRecord to save an IPNS identity for the storage provider.
        * Requires signed storage provider credentials.
        **/
       setIpnsId: AugmentedSubmittable<(storageProviderId: StorageProviderId | AnyNumber | Uint8Array, id: Bytes | string | Uint8Array) => SubmittableExtrinsic<ApiType>>;
       /**
-       * Deletes the AccountInfo with the IPNS identity for the storage provider.
+       * Deletes the ServiceProviderRecord with the IPNS identity for the storage provider.
        * Requires signed storage provider credentials.
        **/
       unsetIpnsId: AugmentedSubmittable<(storageProviderId: StorageProviderId | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>>;

+ 6 - 6
types/src/content-working-group/index.ts

@@ -300,12 +300,12 @@ export class CuratorApplicationIdToCuratorIdMap extends BTreeMap.with(Applicatio
 export class CuratorApplicationIdSet extends Vec.with(CuratorApplicationId) {}
 
 export const contentWorkingGroupTypes = {
-  ChannelId: 'u64',
-  CuratorId: 'u64',
-  CuratorOpeningId: 'u64',
-  CuratorApplicationId: 'u64',
-  LeadId: 'u64',
-  PrincipalId: 'u64',
+  ChannelId,
+  CuratorId,
+  CuratorOpeningId,
+  CuratorApplicationId,
+  LeadId,
+  PrincipalId,
   OptionalText,
   Channel,
   ChannelContentType,

+ 1 - 1
types/src/index.ts

@@ -62,7 +62,7 @@ export const types: RegistryTypes = {
 }
 
 // Allows creating types without api instance (it's not a recommended way though, so should be used just for mocks)
-const mockRegistry = new TypeRegistry()
+export const mockRegistry = new TypeRegistry()
 mockRegistry.register(types)
 
 export function createMock<TypeName extends keyof InterfaceTypes>(

+ 2 - 2
types/src/versioned-store/index.ts

@@ -156,8 +156,8 @@ export function unifyPropName(propName: string): string {
 }
 
 export const versionedStoreTypes: RegistryTypes = {
-  ClassId: 'u64',
-  EntityId: 'u64',
+  ClassId,
+  EntityId,
   Class,
   Entity,
   ClassSchema,

+ 256 - 28
yarn.lock

@@ -1383,6 +1383,14 @@
     pirates "^4.0.0"
     source-map-support "^0.5.16"
 
+"@babel/runtime-corejs2@^7.6.3":
+  version "7.11.2"
+  resolved "https://registry.yarnpkg.com/@babel/runtime-corejs2/-/runtime-corejs2-7.11.2.tgz#700a03945ebad0d31ba6690fc8a6bcc9040faa47"
+  integrity sha512-AC/ciV28adSSpEkBglONBWq4/Lvm6GAZuxIoyVtsnUpZMl0bxLtoChEnYAkP+47KyOCayZanojtflUEUJtR/6Q==
+  dependencies:
+    core-js "^2.6.5"
+    regenerator-runtime "^0.13.4"
+
 "@babel/runtime@7.0.0":
   version "7.0.0"
   resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.0.0.tgz#adeb78fedfc855aa05bc041640f3f6f98e85424c"
@@ -4567,6 +4575,11 @@
   resolved "https://registry.yarnpkg.com/@types/memoizee/-/memoizee-0.4.4.tgz#a8a5e917ef70c79523b8b8d57f529e49616a760c"
   integrity sha512-c9+1g6+6vEqcw5UuM0RbfQV0mssmZcoG9+hNC5ptDCsv4G+XJW1Z4pE13wV5zbc9e0+YrDydALBTiD3nWG1a3g==
 
+"@types/mime-types@^2.1.0":
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/@types/mime-types/-/mime-types-2.1.0.tgz#9ca52cda363f699c69466c2a6ccdaad913ea7a73"
+  integrity sha1-nKUs2jY/aZxpRmwqbM2q2RPqenM=
+
 "@types/minimatch@*":
   version "3.0.3"
   resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
@@ -4664,6 +4677,13 @@
     "@types/history" "*"
     "@types/react" "*"
 
+"@types/react-beautiful-dnd@^11.0.3":
+  version "11.0.5"
+  resolved "https://registry.yarnpkg.com/@types/react-beautiful-dnd/-/react-beautiful-dnd-11.0.5.tgz#2f5bc733dd46da28312c8ee0c126ab7202b90247"
+  integrity sha512-idvycolYX3IxwIln8yahzQj3EBgYq4KimPHSP0a2lNHiz2OZSskGg2dLmq1VxTGvvTtdG+Za8p596D/dalRlrA==
+  dependencies:
+    "@types/react" "*"
+
 "@types/react-beautiful-dnd@^13.0.0":
   version "13.0.0"
   resolved "https://registry.yarnpkg.com/@types/react-beautiful-dnd/-/react-beautiful-dnd-13.0.0.tgz#e60d3d965312fcf1516894af92dc3e9249587db4"
@@ -5884,6 +5904,15 @@ anymatch@^3.0.3, anymatch@~3.1.1:
     normalize-path "^3.0.0"
     picomatch "^2.0.4"
 
+aplayer@^1.10.0, aplayer@^1.10.1:
+  version "1.10.1"
+  resolved "https://registry.yarnpkg.com/aplayer/-/aplayer-1.10.1.tgz#318289206107452cc39e8f552fa6cc6cb459a90c"
+  integrity sha512-HAfyxgCUTLAqtYlxzzK9Fyqg6y+kZ9CqT1WfeWE8FSzwspT6oBqWOZHANPHF3RGTtC33IsyEgrfthPDzU5r9kQ==
+  dependencies:
+    balloon-css "^0.5.0"
+    promise-polyfill "7.1.0"
+    smoothscroll "0.4.0"
+
 app-builder-bin@3.5.9:
   version "3.5.9"
   resolved "https://registry.yarnpkg.com/app-builder-bin/-/app-builder-bin-3.5.9.tgz#a3ac0c25286bac68357321cb2eaf7128b0bc0a4f"
@@ -6333,21 +6362,29 @@ aws4@^1.8.0:
   resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.9.0.tgz#24390e6ad61386b0a747265754d2a17219de862c"
   integrity sha512-Uvq6hVe90D0B2WEnUqtdgY1bATGz3mw33nH9Y+dmA+w5DHvUmBgkr5rM/KCHpCsiFNRUfokW/szpPPgMK2hm4A==
 
-axios@^0.18.0, axios@^0.18.1:
-  version "0.18.1"
-  resolved "https://registry.yarnpkg.com/axios/-/axios-0.18.1.tgz#ff3f0de2e7b5d180e757ad98000f1081b87bcea3"
-  integrity sha512-0BfJq4NSfQXd+SkFdrvFbG7addhYSBA2mQwISr46pD6E5iqkWg02RAs8vyTT/j0RTnoYmeXauBuSv1qKwR179g==
+axios@0.18.0:
+  version "0.18.0"
+  resolved "https://registry.yarnpkg.com/axios/-/axios-0.18.0.tgz#32d53e4851efdc0a11993b6cd000789d70c05102"
+  integrity sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=
   dependencies:
-    follow-redirects "1.5.10"
-    is-buffer "^2.0.2"
+    follow-redirects "^1.3.0"
+    is-buffer "^1.1.5"
 
-axios@^0.19.0, axios@^0.19.2:
+axios@0.19.2, axios@^0.19.0, axios@^0.19.2:
   version "0.19.2"
   resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27"
   integrity sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==
   dependencies:
     follow-redirects "1.5.10"
 
+axios@^0.18.0, axios@^0.18.1:
+  version "0.18.1"
+  resolved "https://registry.yarnpkg.com/axios/-/axios-0.18.1.tgz#ff3f0de2e7b5d180e757ad98000f1081b87bcea3"
+  integrity sha512-0BfJq4NSfQXd+SkFdrvFbG7addhYSBA2mQwISr46pD6E5iqkWg02RAs8vyTT/j0RTnoYmeXauBuSv1qKwR179g==
+  dependencies:
+    follow-redirects "1.5.10"
+    is-buffer "^2.0.2"
+
 babel-code-frame@^6.22.0:
   version "6.26.0"
   resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
@@ -6761,6 +6798,16 @@ balanced-match@^1.0.0:
   resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
   integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
 
+balloon-css@^0.5.0:
+  version "0.5.2"
+  resolved "https://registry.yarnpkg.com/balloon-css/-/balloon-css-0.5.2.tgz#9e2163565a136c9d4aa20e8400772ce3b738d3ff"
+  integrity sha512-zheJpzwyNrG4t39vusA67v3BYg1HTVXOF8cErPEHzWK88PEOFwgo6Ea9VHOgOWNMgeuOtFVtB73NE2NWl9uDyQ==
+
+balloon-css@^1.0.3:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/balloon-css/-/balloon-css-1.2.0.tgz#53d3fb4051264a278a58713bed6865845dbcaf4b"
+  integrity sha512-urXwkHgwp6GsXVF+it01485Z2Cj4pnW02ICnM0TemOlkKmCNnDLmyy+ZZiRXBpwldUXO+aRNr7Hdia4CBvXJ5A==
+
 base-path-converter@^1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/base-path-converter/-/base-path-converter-1.0.2.tgz#e80b4b4f31c7b1561e632158e00774b6f2f27978"
@@ -6951,17 +6998,7 @@ bluebird@^3.1.1, bluebird@^3.3.5, bluebird@^3.5.1, bluebird@^3.5.3, bluebird@^3.
   resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
   integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==
 
-bn.js@^4.0.0, bn.js@^4.11.8, bn.js@^4.4.0:
-  version "4.11.8"
-  resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f"
-  integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==
-
-bn.js@^4.1.0, bn.js@^4.1.1:
-  version "4.11.9"
-  resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.9.tgz#26d556829458f9d1e81fc48952493d0ba3507828"
-  integrity sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==
-
-bn.js@^5.1.2:
+bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.11.8, bn.js@^4.4.0, bn.js@^5.1.2:
   version "5.1.2"
   resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.1.2.tgz#c9686902d3c9a27729f43ab10f9d79c2004da7b0"
   integrity sha512-40rZaf3bUNKTVYu9sIeeEGOg7g14Yvnj9kH7b50EiwX0Q7A6umbvfI5tvHaOERH0XigqKkfLkFQxzb4e6CIXnA==
@@ -10124,6 +10161,26 @@ dotenv@^8.0.0, dotenv@^8.2.0:
   resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a"
   integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==
 
+dplayer@1.25.0:
+  version "1.25.0"
+  resolved "https://registry.yarnpkg.com/dplayer/-/dplayer-1.25.0.tgz#10afb3416b42125b8926d9b157aae594c84945fb"
+  integrity sha512-TG2IKT4IXH5trE3DKeeOqmGlewheHT5R30ya4jhMrjysc1rrCPMJYnmsBfiTS8h6613YZeriFIDHZHEEi/rs3Q==
+  dependencies:
+    axios "0.18.0"
+    balloon-css "^0.5.0"
+    mini-css-extract-plugin "0.4.0"
+    promise-polyfill "8.0.0"
+    webpack-cli "3.0.4"
+
+dplayer@^1.24.0:
+  version "1.26.0"
+  resolved "https://registry.yarnpkg.com/dplayer/-/dplayer-1.26.0.tgz#d366200b1962bd09e91226066f2aadea6f35c71b"
+  integrity sha512-uOE0w/WdlX7N9d0ppIEcAYrcnUjY52TMX+MBL4lj9Mj+JMljVuaEc5w88HkZp5Q11VqvN/jxnM8ktx2Dr7/MgA==
+  dependencies:
+    axios "0.19.2"
+    balloon-css "^1.0.3"
+    promise-polyfill "8.1.3"
+
 drbg.js@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/drbg.js/-/drbg.js-1.0.1.tgz#3e36b6c42b37043823cdbc332d58f31e2445480b"
@@ -11999,6 +12056,11 @@ follow-redirects@^1.0.0:
   dependencies:
     debug "^3.0.0"
 
+follow-redirects@^1.3.0:
+  version "1.13.0"
+  resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.0.tgz#b42e8d93a2a7eea5ed88633676d6597bc8e384db"
+  integrity sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==
+
 for-in@^0.1.3:
   version "0.1.8"
   resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1"
@@ -12664,6 +12726,11 @@ global-dirs@^2.0.1:
   dependencies:
     ini "^1.3.5"
 
+global-modules-path@^2.1.0:
+  version "2.3.1"
+  resolved "https://registry.yarnpkg.com/global-modules-path/-/global-modules-path-2.3.1.tgz#e541f4c800a1a8514a990477b267ac67525b9931"
+  integrity sha512-y+shkf4InI7mPRHSo2b/k6ix6+NLDtyccYv86whhxrSGX9wjPX1VMITmrDbE1eh7zkzhiWtW2sHklJYoQ62Cxg==
+
 global-modules@2.0.0, global-modules@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780"
@@ -13816,6 +13883,14 @@ import-lazy@^4.0.0:
   resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-4.0.0.tgz#e8eb627483a0a43da3c03f3e35548be5cb0cc153"
   integrity sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==
 
+import-local@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/import-local/-/import-local-1.0.0.tgz#5e4ffdc03f4fe6c009c6729beb29631c2f8227bc"
+  integrity sha512-vAaZHieK9qjGo58agRBg+bhHX3hoTZU/Oa3GESWLz7t1U62fk63aHuDJJEteXoDeTCcPmUT+z38gkHPZkkmpmQ==
+  dependencies:
+    pkg-dir "^2.0.0"
+    resolve-cwd "^2.0.0"
+
 import-local@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d"
@@ -13959,7 +14034,7 @@ inquirer@6.5.0:
     strip-ansi "^5.1.0"
     through "^2.3.6"
 
-inquirer@^6.2.0:
+inquirer@^6.0.0, inquirer@^6.2.0:
   version "6.5.2"
   resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.2.tgz#ad50942375d036d327ff528c08bd5fab089928ca"
   integrity sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==
@@ -14050,7 +14125,7 @@ interpret@^1.0.0:
   resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296"
   integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==
 
-interpret@^1.4.0:
+interpret@^1.1.0, interpret@^1.4.0:
   version "1.4.0"
   resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e"
   integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==
@@ -14072,6 +14147,11 @@ invert-kv@^1.0.0:
   resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
   integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY=
 
+invert-kv@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02"
+  integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==
+
 ip-regex@^2.0.0, ip-regex@^2.1.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9"
@@ -15049,6 +15129,11 @@ isexe@^2.0.0:
   resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
   integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
 
+iso-639-1@^2.1.0:
+  version "2.1.4"
+  resolved "https://registry.yarnpkg.com/iso-639-1/-/iso-639-1-2.1.4.tgz#c08b3d43a1c18945b05e26a257991ae6e36693ee"
+  integrity sha512-pwJRHnpz1sCR5saQ+Hm1E2YESw2eLGKP5TzsYKXuQ7SIfvKWMRb9CHhptqunYpCIcRCpq3LgLuhYG5hiLPRbFQ==
+
 iso-random-stream@^1.1.0:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/iso-random-stream/-/iso-random-stream-1.1.1.tgz#83824bba77fbb3480dd6b35fbb06de7f9e93e80f"
@@ -16500,6 +16585,13 @@ lcid@^1.0.0:
   dependencies:
     invert-kv "^1.0.0"
 
+lcid@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf"
+  integrity sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==
+  dependencies:
+    invert-kv "^2.0.0"
+
 lcov-parse@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/lcov-parse/-/lcov-parse-1.0.0.tgz#eb0d46b54111ebc561acb4c408ef9363bdc8f7e0"
@@ -17210,6 +17302,13 @@ makeerror@1.0.x:
   dependencies:
     tmpl "1.0.x"
 
+map-age-cleaner@^0.1.1:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a"
+  integrity sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==
+  dependencies:
+    p-defer "^1.0.0"
+
 map-cache@^0.2.2:
   version "0.2.2"
   resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf"
@@ -17397,6 +17496,15 @@ mem@^1.1.0:
   dependencies:
     mimic-fn "^1.0.0"
 
+mem@^4.0.0:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178"
+  integrity sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==
+  dependencies:
+    map-age-cleaner "^0.1.1"
+    mimic-fn "^2.0.0"
+    p-is-promise "^2.0.0"
+
 memoize-one@^5.0.0, memoize-one@^5.1.1:
   version "5.1.1"
   resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.1.1.tgz#047b6e3199b508eaec03504de71229b8eb1d75c0"
@@ -17623,7 +17731,7 @@ mime-types@^2.1.12, mime-types@~2.1.19, mime-types@~2.1.24:
   dependencies:
     mime-db "1.42.0"
 
-mime-types@^2.1.18, mime-types@^2.1.26, mime-types@~2.1.17:
+mime-types@^2.1.18, mime-types@^2.1.22, mime-types@^2.1.26, mime-types@~2.1.17:
   version "2.1.27"
   resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f"
   integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==
@@ -17645,7 +17753,7 @@ mimic-fn@^1.0.0:
   resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022"
   integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==
 
-mimic-fn@^2.1.0:
+mimic-fn@^2.0.0, mimic-fn@^2.1.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
   integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
@@ -17680,6 +17788,14 @@ mini-create-react-context@^0.4.0:
     "@babel/runtime" "^7.5.5"
     tiny-warning "^1.0.3"
 
+mini-css-extract-plugin@0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.4.0.tgz#ff3bf08bee96e618e177c16ca6131bfecef707f9"
+  integrity sha512-2Zik6PhUZ/MbiboG6SDS9UTPL4XXy4qnyGjSdCIWRrr8xb6PwLtHE+AYOjkXJWdF0OG8vo/yrJ8CgS5WbMpzIg==
+  dependencies:
+    loader-utils "^1.1.0"
+    webpack-sources "^1.1.0"
+
 mini-css-extract-plugin@0.6.0:
   version "0.6.0"
   resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.6.0.tgz#a3f13372d6fcde912f3ee4cd039665704801e3b9"
@@ -19199,6 +19315,15 @@ os-locale@^2.0.0:
     lcid "^1.0.0"
     mem "^1.1.0"
 
+os-locale@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a"
+  integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==
+  dependencies:
+    execa "^1.0.0"
+    lcid "^2.0.0"
+    mem "^4.0.0"
+
 os-name@^3.1.0:
   version "3.1.0"
   resolved "https://registry.yarnpkg.com/os-name/-/os-name-3.1.0.tgz#dec19d966296e1cd62d701a5a66ee1ddeae70801"
@@ -19237,6 +19362,11 @@ p-cancelable@^1.0.0:
   resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc"
   integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==
 
+p-defer@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c"
+  integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=
+
 p-defer@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-3.0.0.tgz#d1dceb4ee9b2b604b1d94ffec83760175d4e6f83"
@@ -19257,6 +19387,11 @@ p-finally@^2.0.0:
   resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-2.0.1.tgz#bd6fcaa9c559a096b680806f4d657b3f0f240561"
   integrity sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw==
 
+p-is-promise@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e"
+  integrity sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==
+
 p-limit@^1.1.0:
   version "1.3.0"
   resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8"
@@ -20515,6 +20650,21 @@ promise-inflight@^1.0.1:
   resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3"
   integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM=
 
+promise-polyfill@7.1.0:
+  version "7.1.0"
+  resolved "https://registry.yarnpkg.com/promise-polyfill/-/promise-polyfill-7.1.0.tgz#4d749485b44577c14137591c6f36e5d7e2dd3378"
+  integrity sha512-P6NJ2wU/8fac44ENORsuqT8TiolKGB2u0fEClPtXezn7w5cmLIjM/7mhPlTebke2EPr6tmqZbXvnX0TxwykGrg==
+
+promise-polyfill@8.0.0:
+  version "8.0.0"
+  resolved "https://registry.yarnpkg.com/promise-polyfill/-/promise-polyfill-8.0.0.tgz#b47c7fc74052cc5b2132b703cca144f1a5eb56ef"
+  integrity sha512-QGmPnw2hDEaRS6freHynJ7nfS1nDg0/P0c/CGglA43utoJjYQMiY9ojEpK0HaJ4wbUztdmwqQRlEfGWdsEQ5uQ==
+
+promise-polyfill@8.1.3:
+  version "8.1.3"
+  resolved "https://registry.yarnpkg.com/promise-polyfill/-/promise-polyfill-8.1.3.tgz#8c99b3cf53f3a91c68226ffde7bde81d7f904116"
+  integrity sha512-MG5r82wBzh7pSKDRa9y+vllNHz3e3d4CNj1PQE4BQYxLme0gKYYBm9YENq+UkEikyZ0XbiGWxYlVw3Rl9O/U8g==
+
 promise-retry@^1.1.1:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-1.1.1.tgz#6739e968e3051da20ce6497fb2b50f6911df3d6d"
@@ -21005,6 +21155,28 @@ rc@^1.0.1, rc@^1.1.6, rc@^1.2.7, rc@^1.2.8:
     minimist "^1.2.0"
     strip-json-comments "~2.0.1"
 
+react-aplayer@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/react-aplayer/-/react-aplayer-1.0.0.tgz#ff8bae803c01d479126b072980783242294fae94"
+  integrity sha512-jGoNhjT8cEieakK5fwXVn2J849RAa4JAx+subEtrAr/34DWpEF8KZohedceyAzsJygSmBWVjX3plNoOMBbPlhA==
+  dependencies:
+    aplayer "^1.10.0"
+    prop-types "^15.6.1"
+    react "^16.2.0"
+
+react-beautiful-dnd@^12.0.0:
+  version "12.2.0"
+  resolved "https://registry.yarnpkg.com/react-beautiful-dnd/-/react-beautiful-dnd-12.2.0.tgz#e5f6222f9e7934c6ed4ee09024547f9e353ae423"
+  integrity sha512-s5UrOXNDgeEC+sx65IgbeFlqKKgK3c0UfbrJLWufP34WBheyu5kJ741DtJbsSgPKyNLkqfswpMYr0P8lRj42cA==
+  dependencies:
+    "@babel/runtime-corejs2" "^7.6.3"
+    css-box-model "^1.2.0"
+    memoize-one "^5.1.1"
+    raf-schd "^4.0.2"
+    react-redux "^7.1.1"
+    redux "^4.0.4"
+    use-memo-one "^1.1.1"
+
 react-beautiful-dnd@^13.0.0:
   version "13.0.0"
   resolved "https://registry.yarnpkg.com/react-beautiful-dnd/-/react-beautiful-dnd-13.0.0.tgz#f70cc8ff82b84bc718f8af157c9f95757a6c3b40"
@@ -21118,6 +21290,15 @@ react-dom@^16.13.1, react-dom@^16.8.3:
     prop-types "^15.6.2"
     scheduler "^0.19.1"
 
+react-dplayer@^0.2.3:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/react-dplayer/-/react-dplayer-0.2.3.tgz#45d46ef256df4e69f642a900e8f607c98cb1b8cf"
+  integrity sha512-CcZCeolaGqxfiKF+Fnb8sUYt2gauxXpivZkr3X0Um9l5c/qMsZ2K0fQEV5nGBdTWMQEz2dh01c9vHk5pN3klGg==
+  dependencies:
+    classnames "^2.2.6"
+    dplayer "^1.24.0"
+    prop-types "^15.6.2"
+
 react-draggable@^4.0.3:
   version "4.4.3"
   resolved "https://registry.yarnpkg.com/react-draggable/-/react-draggable-4.4.3.tgz#0727f2cae5813e36b0e4962bf11b2f9ef2b406f3"
@@ -21400,7 +21581,7 @@ react@^16.12.0:
     object-assign "^4.1.1"
     prop-types "^15.6.2"
 
-react@^16.13.1, react@^16.8.3:
+react@^16.13.1, react@^16.2.0, react@^16.8.3:
   version "16.13.1"
   resolved "https://registry.yarnpkg.com/react/-/react-16.13.1.tgz#2e818822f1a9743122c063d6410d85c1e3afe48e"
   integrity sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w==
@@ -23062,6 +23243,11 @@ smoothscroll-polyfill@^0.4.3:
   resolved "https://registry.yarnpkg.com/smoothscroll-polyfill/-/smoothscroll-polyfill-0.4.4.tgz#3a259131dc6930e6ca80003e1cb03b603b69abf8"
   integrity sha512-TK5ZA9U5RqCwMpfoMq/l1mrH0JAR7y7KRvOBx0n2869aLxch+gT9GhN3yUfjiw+d/DiF1mKo14+hd62JyMmoBg==
 
+smoothscroll@0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/smoothscroll/-/smoothscroll-0.4.0.tgz#40e507b46461408ba1b787d0081e1e883c4124a5"
+  integrity sha512-sggQ3U2Un38b3+q/j1P4Y4fCboCtoUIaBYoge+Lb6Xg1H8RTIif/hugVr+ErMtIDpvBbhQfTjtiTeYAfbw1ZGQ==
+
 snapdragon-node@^2.0.1:
   version "2.1.1"
   resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b"
@@ -25684,16 +25870,16 @@ uuid@^8.2.0, uuid@^8.3.0:
   resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.0.tgz#ab738085ca22dc9a8c92725e459b1d507df5d6ea"
   integrity sha512-fX6Z5o4m6XsXBdli9g7DtWgAx+osMsRRZFKma1mIUsLCz6vRvv+pz5VNbyu9UEDzpMWulZfvpgb/cmDXVulYFQ==
 
+v8-compile-cache@^2.0.0, v8-compile-cache@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz#54bc3cdd43317bca91e35dcaf305b1a7237de745"
+  integrity sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==
+
 v8-compile-cache@^2.0.3:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e"
   integrity sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==
 
-v8-compile-cache@^2.1.1:
-  version "2.1.1"
-  resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz#54bc3cdd43317bca91e35dcaf305b1a7237de745"
-  integrity sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==
-
 v8-to-istanbul@^4.1.3:
   version "4.1.4"
   resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-4.1.4.tgz#b97936f21c0e2d9996d4985e5c5156e9d4e49cd6"
@@ -26091,6 +26277,23 @@ webpack-chain@^6.0.0:
     deepmerge "^1.5.2"
     javascript-stringify "^2.0.1"
 
+webpack-cli@3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.0.4.tgz#55d6ad2cdd608de8c0f757dde5bc4bf5bd2dec68"
+  integrity sha512-r5R0hMck4GxUS6a3TXClwi1KhQfnHZRtIfXqsSytQZG4kawKMhTtd5//uNZGoGks/h61Zv5jMnR6jwx15Qf8dA==
+  dependencies:
+    chalk "^2.4.1"
+    cross-spawn "^6.0.5"
+    enhanced-resolve "^4.0.0"
+    global-modules-path "^2.1.0"
+    import-local "^1.0.0"
+    inquirer "^6.0.0"
+    interpret "^1.1.0"
+    loader-utils "^1.1.0"
+    supports-color "^5.4.0"
+    v8-compile-cache "^2.0.0"
+    yargs "^11.1.0"
+
 webpack-cli@^3.3.12:
   version "3.3.12"
   resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.3.12.tgz#94e9ada081453cd0aa609c99e500012fd3ad2d4a"
@@ -26719,6 +26922,13 @@ yargs-parser@^8.1.0:
   dependencies:
     camelcase "^4.1.0"
 
+yargs-parser@^9.0.2:
+  version "9.0.2"
+  resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-9.0.2.tgz#9ccf6a43460fe4ed40a9bb68f48d43b8a68cc077"
+  integrity sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=
+  dependencies:
+    camelcase "^4.1.0"
+
 yargs@^10.0.3:
   version "10.1.2"
   resolved "https://registry.yarnpkg.com/yargs/-/yargs-10.1.2.tgz#454d074c2b16a51a43e2fb7807e4f9de69ccb5c5"
@@ -26737,6 +26947,24 @@ yargs@^10.0.3:
     y18n "^3.2.1"
     yargs-parser "^8.1.0"
 
+yargs@^11.1.0:
+  version "11.1.1"
+  resolved "https://registry.yarnpkg.com/yargs/-/yargs-11.1.1.tgz#5052efe3446a4df5ed669c995886cc0f13702766"
+  integrity sha512-PRU7gJrJaXv3q3yQZ/+/X6KBswZiaQ+zOmdprZcouPYtQgvNU35i+68M4b1ZHLZtYFT5QObFLV+ZkmJYcwKdiw==
+  dependencies:
+    cliui "^4.0.0"
+    decamelize "^1.1.1"
+    find-up "^2.1.0"
+    get-caller-file "^1.0.1"
+    os-locale "^3.1.0"
+    require-directory "^2.1.1"
+    require-main-filename "^1.0.1"
+    set-blocking "^2.0.0"
+    string-width "^2.0.0"
+    which-module "^2.0.0"
+    y18n "^3.2.1"
+    yargs-parser "^9.0.2"
+
 yargs@^13.2.2, yargs@^13.3.2:
   version "13.3.2"
   resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd"