Browse Source

Pioneer: Storage working group "My applicatons" and "My roles"

Leszek Wiesner 4 years ago
parent
commit
353e01cc35

+ 3 - 1
pioneer/packages/joy-roles/src/OpeningMetadata.ts

@@ -1,6 +1,8 @@
+import { WorkingGroups } from "./working_groups"
+
 export type OpeningMetadata = {
   id: string;
-  group: string;
+  group: WorkingGroups;
 }
 
 export type OpeningMetadataProps = {

+ 1 - 1
pioneer/packages/joy-roles/src/flows/apply.tsx

@@ -484,7 +484,7 @@ export function ConfirmStakes2Up (props: ConfirmStakes2UpProps) {
   const [valid, setValid] = useState(true);
   const slotCount = props.slots.length;
   const [rank, setRank] = useState(1);
-  const minStake = props.slots[0];
+  const minStake = props.slots[0] || props.applications.requiredApplicationStake.hard.add(props.applications.requiredRoleStake.hard);
   const [combined, setCombined] = useState(new u128(0));
 
   const findRankValue = (newStake: Balance): number => {

+ 6 - 6
pioneer/packages/joy-roles/src/tabs/MyRoles.controller.tsx

@@ -34,18 +34,18 @@ export class MyRolesController extends Controller<State, ITransport> {
   }
 
   protected async updateApplications (myAddress: string) {
-    this.state.applications = await this.transport.openingApplications(myAddress);
+    this.state.applications = await this.transport.openingApplicationsByAddress(myAddress);
     this.dispatch();
   }
 
   protected async updateCurationGroupRoles (myAddress: string) {
-    const roles = await this.transport.myCurationGroupRoles(myAddress);
+    const roles = await this.transport.myRoles(myAddress);
     this.state.currentCurationRoles = roles.map(role => ({
       ...role,
       CTAs: [
         {
           title: 'Leave role',
-          callback: (rationale: string) => { this.leaveCurationRole(role, rationale); }
+          callback: (rationale: string) => { this.leaveRole(role, rationale); }
         }
       ]
     })
@@ -53,12 +53,12 @@ export class MyRolesController extends Controller<State, ITransport> {
     this.dispatch();
   }
 
-  leaveCurationRole (role: ActiveRole, rationale: string) {
-    this.transport.leaveCurationRole(this.state.myAddress, role.curatorId.toNumber(), rationale);
+  leaveRole (role: ActiveRole, rationale: string) {
+    this.transport.leaveRole(role.group, this.state.myAddress, role.workerId.toNumber(), rationale);
   }
 
   cancelApplication (application: OpeningApplication) {
-    this.transport.withdrawCuratorApplication(this.state.myAddress, application.id);
+    this.transport.withdrawApplication(application.meta.group, this.state.myAddress, application.id);
   }
 }
 

+ 12 - 9
pioneer/packages/joy-roles/src/tabs/MyRoles.elements.stories.tsx

@@ -31,6 +31,7 @@ import {
 } from './Opportunities.stories';
 
 import { CuratorId } from '@joystream/types/content-working-group';
+import { WorkingGroups, workerRoleNameByGroup } from '../working_groups';
 
 export default {
   title: 'Roles / Components / My roles tab / Elements',
@@ -45,10 +46,11 @@ export function CurrentRolesFragment () {
   const props: CurrentRolesProps = {
     currentRoles: [
       {
-        curatorId: new CuratorId(1),
-        name: 'Storage provider',
+        workerId: new CuratorId(1),
+        name: workerRoleNameByGroup[WorkingGroups.StorageProviders],
         reward: new u128(321),
         stake: new u128(100),
+        group: WorkingGroups.StorageProviders,
         CTAs: [
           {
             title: 'Unstake',
@@ -57,11 +59,12 @@ export function CurrentRolesFragment () {
         ]
       },
       {
-        curatorId: new CuratorId(1),
+        workerId: new CuratorId(1),
         name: 'Some other role',
         url: 'some URL',
         reward: new u128(321),
         stake: new u128(12343200),
+        group: WorkingGroups.ContentCurators,
         CTAs: [
           {
             title: 'Leave role',
@@ -164,7 +167,7 @@ const permutations: (ApplicationProps & TestProps)[] = [
     id: 1,
     meta: {
       id: '1',
-      group: 'group-name'
+      group: WorkingGroups.ContentCurators
     },
     stage: {
       state: OpeningState.AcceptingApplications,
@@ -184,7 +187,7 @@ const permutations: (ApplicationProps & TestProps)[] = [
     id: 1,
     meta: {
       id: '1',
-      group: 'group-name'
+      group: WorkingGroups.ContentCurators
     },
     stage: {
       state: OpeningState.AcceptingApplications,
@@ -204,7 +207,7 @@ const permutations: (ApplicationProps & TestProps)[] = [
     id: 1,
     meta: {
       id: '1',
-      group: 'group-name'
+      group: WorkingGroups.ContentCurators
     },
     stage: {
       state: OpeningState.InReview,
@@ -226,7 +229,7 @@ const permutations: (ApplicationProps & TestProps)[] = [
     id: 1,
     meta: {
       id: '1',
-      group: 'group-name'
+      group: WorkingGroups.ContentCurators
     },
     stage: {
       state: OpeningState.InReview,
@@ -248,7 +251,7 @@ const permutations: (ApplicationProps & TestProps)[] = [
     id: 1,
     meta: {
       id: '1',
-      group: 'group-name'
+      group: WorkingGroups.ContentCurators
     },
     stage: {
       state: OpeningState.Complete,
@@ -268,7 +271,7 @@ const permutations: (ApplicationProps & TestProps)[] = [
     id: 1,
     meta: {
       id: '1',
-      group: 'group-name'
+      group: WorkingGroups.ContentCurators
     },
     stage: {
       state: OpeningState.Cancelled,

+ 11 - 1
pioneer/packages/joy-roles/src/tabs/MyRoles.tsx

@@ -35,6 +35,9 @@ import {
 import { CancelledReason, OpeningStageClassification, OpeningState } from '../classifiers';
 import { OpeningMetadata } from '../OpeningMetadata';
 import { CuratorId } from '@joystream/types/content-working-group';
+import _ from 'lodash';
+import styled from 'styled-components';
+import { WorkingGroups } from '../working_groups';
 
 type CTACallback = (rationale: string) => void
 
@@ -102,9 +105,10 @@ function RoleName (props: NameAndURL) {
 }
 
 export interface ActiveRole extends NameAndURL {
-  curatorId: CuratorId;
+  workerId: CuratorId;
   reward: Balance;
   stake: Balance;
+  group: WorkingGroups;
 }
 
 export interface ActiveRoleWithCTAs extends ActiveRole {
@@ -379,6 +383,11 @@ function CancelButton (props: ApplicationProps) {
   );
 }
 
+const ApplicationLabel = styled(Label)`
+  margin-left: 1em !important;
+  border: 1px solid #999 !important;
+`;
+
 export function Application (props: ApplicationProps) {
   let countdown = null;
   if (props.stage.state === OpeningState.InReview) {
@@ -400,6 +409,7 @@ export function Application (props: ApplicationProps) {
         <Label.Detail className="right">
           {openingIcon(props.stage.state)}
           {openingDescription(props.stage.state)}
+          <ApplicationLabel>{_.startCase(props.meta.group)}</ApplicationLabel>
         </Label.Detail>
       </Label>
       <Grid columns="equal">

+ 2 - 1
pioneer/packages/joy-roles/src/tabs/Opportunities.elements.stories.tsx

@@ -22,6 +22,7 @@ import { OpeningMetadata } from '../OpeningMetadata';
 
 import 'semantic-ui-css/semantic.min.css';
 import '@polkadot/joy-roles/index.sass';
+import { WorkingGroups } from '../working_groups';
 
 export default {
   title: 'Roles / Components / Opportunities groups tab / Elements',
@@ -34,7 +35,7 @@ type TestProps = {
 
 const meta: OpeningMetadata = {
   id: '1',
-  group: 'group-name'
+  group: WorkingGroups.ContentCurators
 };
 
 export function OpeningHeaderByState () {

+ 2 - 1
pioneer/packages/joy-roles/src/tabs/Opportunities.stories.tsx

@@ -27,6 +27,7 @@ import { OpeningMetadata } from '../OpeningMetadata';
 
 import 'semantic-ui-css/semantic.min.css';
 import '@polkadot/joy-roles/index.sass';
+import { WorkingGroups } from '../working_groups';
 
 export default {
   title: 'Roles / Components / Opportunities groups tab',
@@ -153,7 +154,7 @@ export function OpportunitySandbox () {
 
   const meta: OpeningMetadata = {
     id: '1',
-    group: 'group-name'
+    group: WorkingGroups.ContentCurators
   };
 
   return (

+ 12 - 20
pioneer/packages/joy-roles/src/transport.mock.ts

@@ -27,7 +27,7 @@ import { OpeningState } from './classifiers';
 
 import * as faker from 'faker';
 import { mockProfile } from './mocks';
-import { WorkingGroups } from './working_groups';
+import { WorkingGroups, workerRoleNameByGroup } from './working_groups';
 
 export class Transport extends TransportBase implements ITransport {
   protected simulateApiResponse<T> (value: T): Promise<T> {
@@ -185,7 +185,7 @@ export class Transport extends TransportBase implements ITransport {
           }),
           meta: {
             id: '1',
-            group: 'somegroup'
+            group: WorkingGroups.ContentCurators
           },
           stage: {
             state: OpeningState.AcceptingApplications,
@@ -212,7 +212,7 @@ export class Transport extends TransportBase implements ITransport {
     );
   }
 
-  curationGroupOpening (id: number): Promise<WorkingGroupOpening> {
+  async groupOpening (group: WorkingGroups, id: number): Promise<WorkingGroupOpening> {
     return this.simulateApiResponse<WorkingGroupOpening>(
       {
         opening: new Opening({
@@ -269,7 +269,7 @@ export class Transport extends TransportBase implements ITransport {
         }),
         meta: {
           id: '1',
-          group: 'group-name'
+          group: WorkingGroups.ContentCurators
         },
         stage: {
           state: OpeningState.AcceptingApplications,
@@ -296,10 +296,6 @@ export class Transport extends TransportBase implements ITransport {
     );
   }
 
-  async groupOpening (group: WorkingGroups, id: number): Promise<WorkingGroupOpening> {
-    return await this.curationGroupOpening(id);
-  }
-
   openingApplicationRanks (group: WorkingGroups, openingId: number): Promise<Balance[]> {
     const slots: Balance[] = [];
     for (let i = 0; i < 20; i++) {
@@ -350,12 +346,12 @@ export class Transport extends TransportBase implements ITransport {
   }
 
   // eslint-disable-next-line @typescript-eslint/require-await
-  async openingApplications (): Promise<OpeningApplication[]> {
+  async openingApplicationsByAddress (address: string): Promise<OpeningApplication[]> {
     return [{
       id: 1,
       meta: {
         id: '1',
-        group: 'group-name'
+        group: WorkingGroups.ContentCurators
       },
       stage: {
         state: OpeningState.AcceptingApplications,
@@ -422,12 +418,12 @@ export class Transport extends TransportBase implements ITransport {
     }];
   }
 
-  // eslint-disable-next-line @typescript-eslint/require-await
-  async myCurationGroupRoles (): Promise<ActiveRole[]> {
+  async myRoles (address: string): Promise<ActiveRole[]> {
     return [
       {
-        curatorId: new CuratorId(1),
-        name: 'My curation group role',
+        workerId: new CuratorId(1),
+        name: workerRoleNameByGroup[WorkingGroups.ContentCurators],
+        group: WorkingGroups.ContentCurators,
         url: 'some URL',
         reward: new u128(321),
         stake: new u128(12343200)
@@ -435,10 +431,6 @@ export class Transport extends TransportBase implements ITransport {
     ];
   }
 
-  myStorageGroupRoles (): Subscribable<ActiveRole[]> {
-    return new Observable<ActiveRole[]>(observer => { /* do nothing */ });
-  }
-
   // eslint-disable-next-line @typescript-eslint/require-await
   async applyToOpening (
     group: WorkingGroups,
@@ -451,11 +443,11 @@ export class Transport extends TransportBase implements ITransport {
     return 0;
   }
 
-  leaveCurationRole (sourceAccount: string, id: number, rationale: string) {
+  leaveRole (group: WorkingGroups, sourceAccount: string, id: number, rationale: string) {
     /* do nothing */
   }
 
-  withdrawCuratorApplication (sourceAccount: string, id: number) {
+  withdrawApplication (group: WorkingGroups, sourceAccount: string, id: number) {
     /* do nothing */
   }
 }

+ 73 - 63
pioneer/packages/joy-roles/src/transport.substrate.ts

@@ -1,4 +1,3 @@
-import { Observable } from 'rxjs';
 import { map, switchMap } from 'rxjs/operators';
 
 import ApiPromise from '@polkadot/api/promise';
@@ -31,7 +30,7 @@ import {
   Lead as LeadOf
 } from '@joystream/types/working-group';
 
-import { Application, Opening, OpeningId } from '@joystream/types/hiring';
+import { Application, Opening, OpeningId, ApplicationId } from '@joystream/types/hiring';
 import { Stake, StakeId } from '@joystream/types/stake';
 import { RewardRelationship, RewardRelationshipId } from '@joystream/types/recurring-rewards';
 import { ActorInRole, Profile, MemberId, Role, RoleKeys, ActorId } from '@joystream/types/members';
@@ -49,7 +48,7 @@ import {
   classifyOpeningStakes,
   isApplicationHired
 } from './classifiers';
-import { WorkingGroups, AvailableGroups } from './working_groups';
+import { WorkingGroups, AvailableGroups, workerRoleNameByGroup } from './working_groups';
 import { Sort, Sum, Zero } from './balances';
 import _ from 'lodash';
 
@@ -71,7 +70,9 @@ type WGApiMethodType =
   | 'nextWorkerId'
   | 'workerById';
 type WGApiTxMethodType =
-  'applyOnOpening';
+  'applyOnOpening'
+  | 'withdrawApplication'
+  | 'leaveRole';
 type WGApiMethodsMapping = {
   query: { [key in WGApiMethodType]: string };
   tx: { [key in WGApiTxMethodType]: string };
@@ -113,7 +114,9 @@ const workingGroupsApiMapping: WGApiMapping = {
         workerById: 'workerById'
       },
       tx: {
-        applyOnOpening: 'applyOnWorkerOpening'
+        applyOnOpening: 'applyOnWorkerOpening',
+        withdrawApplication: 'withdrawWorkerApplication',
+        leaveRole: 'leaveWorkerRole'
       }
     },
     openingType: WorkerOpening,
@@ -132,7 +135,9 @@ const workingGroupsApiMapping: WGApiMapping = {
         workerById: 'curatorById'
       },
       tx: {
-        applyOnOpening: 'applyOnCuratorOpening'
+        applyOnOpening: 'applyOnCuratorOpening',
+        withdrawApplication: 'withdrawCuratorApplication',
+        leaveRole: 'leaveCuratorRole'
       }
     },
     openingType: CuratorOpening,
@@ -256,7 +261,7 @@ export class Transport extends TransportBase implements ITransport {
       roleAccount,
       memberId,
       profile: profile.unwrap(),
-      title: _.startCase(group).slice(0, -1), // FIXME: Temporary solution (just removes "s" at the end)
+      title: workerRoleNameByGroup[group],
       stake: stakeValue,
       earned: earnedValue
     });
@@ -286,11 +291,6 @@ export class Transport extends TransportBase implements ITransport {
     return false;
   }
 
-  protected async areAnyCuratorRolesOpen (): Promise<boolean> {
-    // Backward compatibility
-    return this.areAnyGroupRolesOpen(WorkingGroups.ContentCurators);
-  }
-
   protected async currentCuratorLead (): Promise<GroupLeadWithMemberId | null> {
     const optLeadId = (await this.cachedApi.query.contentWorkingGroup.currentLeadId()) as Option<LeadId>;
 
@@ -458,12 +458,6 @@ export class Transport extends TransportBase implements ITransport {
     return output;
   }
 
-  protected async curatorOpeningApplications (curatorOpeningId: number): Promise<WorkingGroupPair<Application, CuratorApplication>[]> {
-    // Backwards compatibility
-    const applications = await this.groupOpeningApplications(WorkingGroups.ContentCurators, curatorOpeningId);
-    return applications as WorkingGroupPair<Application, CuratorApplication>[];
-  }
-
   async groupOpening (group: WorkingGroups, id: number): Promise<WorkingGroupOpening> {
     const nextId = (await this.cachedApiMethodByGroup(group, 'nextOpeningId')() as u32).toNumber();
     if (id < 0 || id >= nextId) {
@@ -500,11 +494,6 @@ export class Transport extends TransportBase implements ITransport {
     });
   }
 
-  async curationGroupOpening (id: number): Promise<WorkingGroupOpening> {
-    // Backwards compatibility
-    return this.groupOpening(WorkingGroups.ContentCurators, id);
-  }
-
   protected async openingApplicationTotalStake (application: Application): Promise<Balance> {
     const promises = new Array<Promise<Balance>>();
 
@@ -613,15 +602,15 @@ export class Transport extends TransportBase implements ITransport {
     return appvalues.findIndex(v => v.app.eq(myApp)) + 1;
   }
 
-  async openingApplications (roleKeyId: string): Promise<OpeningApplication[]> {
-    const curatorApps = new MultipleLinkedMapEntry<CuratorApplicationId, CuratorApplication>(
-      CuratorApplicationId,
-      CuratorApplication,
-      await this.cachedApi.query.contentWorkingGroup.curatorApplicationById()
+  async openingApplicationsByAddressAndGroup (group: WorkingGroups, roleKey: string): Promise<OpeningApplication[]> {
+    const applications = new MultipleLinkedMapEntry<GroupApplicationId, GroupApplication>(
+      ApplicationId,
+      workingGroupsApiMapping[group].applicationType,
+      await this.cachedApiMethodByGroup(group, 'applicationById')()
     );
 
-    const myApps = curatorApps.linked_values.filter(app => app.role_account.eq(roleKeyId));
-    const myAppIds = curatorApps.linked_keys.filter((id, key) => curatorApps.linked_values[key].role_account.eq(roleKeyId));
+    const myApps = applications.linked_values.filter(app => app.role_account.eq(roleKey));
+    const myAppIds = applications.linked_keys.filter((id, key) => applications.linked_values[key].role_account.eq(roleKey));
 
     const hiringAppPairs = await Promise.all(
       myApps.map(
@@ -640,73 +629,94 @@ export class Transport extends TransportBase implements ITransport {
       hiringApps.map(app => this.applicationStakes(app))
     );
 
-    const wgs = await Promise.all(
-      myApps.map(curatorOpening => {
-        return this.curationGroupOpening(curatorOpening.curator_opening_id.toNumber());
+    const openings = await Promise.all(
+      myApps.map(opening => {
+        return this.groupOpening(group, opening.worker_opening_id.toNumber());
       })
     );
 
     const allAppsByOpening = (await Promise.all(
-      myApps.map(curatorOpening => {
-        return this.curatorOpeningApplications(curatorOpening.curator_opening_id.toNumber());
+      myApps.map(opening => {
+        return this.groupOpeningApplications(group, opening.worker_opening_id.toNumber());
       })
     ));
 
     return await Promise.all(
-      wgs.map(async (wg, key) => {
+      openings.map(async (o, key) => {
         return {
           id: myAppIds[key].toNumber(),
           hired: isApplicationHired(hiringApps[key]),
           cancelledReason: classifyApplicationCancellation(hiringApps[key]),
           rank: await this.myApplicationRank(hiringApps[key], allAppsByOpening[key].map(a => a.hiringModule)),
-          capacity: wg.applications.maxNumberOfApplications,
-          stage: wg.stage,
-          opening: wg.opening,
-          meta: wg.meta,
+          capacity: o.applications.maxNumberOfApplications,
+          stage: o.stage,
+          opening: o.opening,
+          meta: o.meta,
           applicationStake: stakes[key].application,
           roleStake: stakes[key].role,
-          review_end_time: wg.stage.review_end_time,
-          review_end_block: wg.stage.review_end_block
+          review_end_time: o.stage.review_end_time,
+          review_end_block: o.stage.review_end_block
         };
       })
     );
   }
 
-  async myCurationGroupRoles (roleKeyId: string): Promise<ActiveRole[]> {
-    const curators = new MultipleLinkedMapEntry<CuratorId, Curator>(
-      CuratorId,
-      Curator,
-      await this.cachedApi.query.contentWorkingGroup.curatorById()
+  // Get opening applications for all groups by address
+  async openingApplicationsByAddress (roleKey: string): Promise<OpeningApplication[]> {
+    let applications: OpeningApplication[] = [];
+    for (const group of AvailableGroups) {
+      applications = applications.concat(await this.openingApplicationsByAddressAndGroup(group, roleKey));
+    }
+
+    return applications;
+  }
+
+  async myRolesByGroup (group: WorkingGroups, roleKeyId: string): Promise<ActiveRole[]> {
+    const workers = new MultipleLinkedMapEntry<GroupWorkerId, GroupWorker>(
+      ActorId,
+      workingGroupsApiMapping[group].workerType,
+      await this.cachedApiMethodByGroup(group, 'workerById')()
     );
 
     return Promise.all(
-      curators
+      workers
         .linked_values
         .toArray()
-        .filter(curator => curator.role_account.eq(roleKeyId) && curator.is_active)
-        .map(async (curator, key) => {
+        // We need to associate worker ids with workers BEFORE filtering the array
+        .map((worker, index) => ({ worker, id: workers.linked_keys[index] }))
+        .filter(({worker}) => worker.role_account.eq(roleKeyId) && worker.is_active)
+        .map(async workerWithId => {
+          const { worker, id } = workerWithId;
+
           let stakeValue: Balance = new u128(0);
-          if (curator.role_stake_profile && curator.role_stake_profile.isSome) {
-            stakeValue = await this.workerStake(curator.role_stake_profile.unwrap());
+          if (worker.role_stake_profile && worker.role_stake_profile.isSome) {
+            stakeValue = await this.workerStake(worker.role_stake_profile.unwrap());
           }
 
           let earnedValue: Balance = new u128(0);
-          if (curator.reward_relationship && curator.reward_relationship.isSome) {
-            earnedValue = await this.workerTotalReward(curator.reward_relationship.unwrap());
+          if (worker.reward_relationship && worker.reward_relationship.isSome) {
+            earnedValue = await this.workerTotalReward(worker.reward_relationship.unwrap());
           }
 
           return {
-            curatorId: curators.linked_keys[key],
-            name: 'Content curator',
+            workerId: id,
+            name: workerRoleNameByGroup[group],
             reward: earnedValue,
-            stake: stakeValue
+            stake: stakeValue,
+            group
           };
         })
     );
   }
 
-  myStorageGroupRoles (): Subscribable<ActiveRole[]> {
-    return new Observable<ActiveRole[]>(observer => { /* do nothing */ });
+  // All groups roles by key
+  async myRoles(roleKey: string): Promise<ActiveRole[]> {
+    let roles: ActiveRole[] = [];
+    for (let group of AvailableGroups) {
+      roles = roles.concat(await this.myRolesByGroup(group, roleKey));
+    }
+
+    return roles;
   }
 
   protected generateRoleAccount (name: string, password = ''): string | null {
@@ -767,8 +777,8 @@ export class Transport extends TransportBase implements ITransport {
     });
   }
 
-  leaveCurationRole (sourceAccount: string, id: number, rationale: string) {
-    const tx = this.api.tx.contentWorkingGroup.leaveCuratorRole(
+  leaveRole (group: WorkingGroups, sourceAccount: string, id: number, rationale: string) {
+    const tx = this.apiExtrinsicByGroup(group, 'leaveRole')(
       id,
       rationale
     ) as unknown as SubmittableExtrinsic;
@@ -779,8 +789,8 @@ export class Transport extends TransportBase implements ITransport {
     });
   }
 
-  withdrawCuratorApplication (sourceAccount: string, id: number) {
-    const tx = this.api.tx.contentWorkingGroup.withdrawCuratorApplication(
+  withdrawApplication (group: WorkingGroups, sourceAccount: string, id: number) {
+    const tx = this.apiExtrinsicByGroup(group, 'withdrawApplication')(
       id
     ) as unknown as SubmittableExtrinsic;
 

+ 4 - 6
pioneer/packages/joy-roles/src/transport.ts

@@ -16,16 +16,14 @@ export interface ITransport {
   storageGroup: () => Promise<WorkingGroupMembership>;
   currentOpportunities: () => Promise<Array<WorkingGroupOpening>>;
   groupOpening: (group: WorkingGroups, id: number) => Promise<WorkingGroupOpening>;
-  curationGroupOpening: (id: number) => Promise<WorkingGroupOpening>;
   openingApplicationRanks: (group: WorkingGroups, openingId: number) => Promise<Balance[]>;
   expectedBlockTime: () => Promise<number>;
   blockHash: (height: number) => Promise<string>;
   blockTimestamp: (height: number) => Promise<Date>;
   transactionFee: () => Promise<Balance>;
   accounts: () => Subscribable<keyPairDetails[]>;
-  openingApplications: (address: string) => Promise<OpeningApplication[]>;
-  myCurationGroupRoles: (address: string) => Promise<ActiveRole[]>;
-  myStorageGroupRoles: () => Subscribable<ActiveRole[]>;
+  openingApplicationsByAddress: (address: string) => Promise<OpeningApplication[]>;
+  myRoles: (address: string) => Promise<ActiveRole[]>;
   applyToOpening: (
     group: WorkingGroups,
     id: number,
@@ -35,6 +33,6 @@ export interface ITransport {
     roleStake: Balance,
     applicationText: string
   ) => Promise<number>;
-  leaveCurationRole: (sourceAccount: string, id: number, rationale: string) => void;
-  withdrawCuratorApplication: (sourceAccount: string, id: number) => void;
+  leaveRole: (group: WorkingGroups, sourceAccount: string, id: number, rationale: string) => void;
+  withdrawApplication: (group: WorkingGroups, sourceAccount: string, id: number) => void;
 }

+ 5 - 0
pioneer/packages/joy-roles/src/working_groups.ts

@@ -7,3 +7,8 @@ export const AvailableGroups: readonly WorkingGroups[] = [
   WorkingGroups.ContentCurators,
   WorkingGroups.StorageProviders
 ] as const;
+
+export const workerRoleNameByGroup: { [key in WorkingGroups]: string } = {
+  [WorkingGroups.ContentCurators]: 'Content Curator',
+  [WorkingGroups.StorageProviders]: 'Storage Provider'
+};