types#ProposalType TypeScript Examples

The following examples show how to use types#ProposalType. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: proposal.ts    From commonwealth with GNU General Public License v3.0 6 votes vote down vote up
constructor(
    Chain: AaveChain,
    Accounts: EthereumAccounts,
    Gov: AaveGovernance,
    entity: ChainEntity
  ) {
    // must set identifier before super() because of how response object is named
    super(ProposalType.AaveProposal, backportEntityToAdapter(entity));

    this._Chain = Chain;
    this._Accounts = Accounts;
    this._Gov = Gov;

    entity.chainEvents
      .sort((e1, e2) => e1.blockNumber - e2.blockNumber)
      .forEach((e) => this.update(e));

    this._Executor = this._Gov.api.getExecutor(this.data.executor);
    this._Gov.store.add(this);
    // insert Qm prefix via hex
    this._ipfsAddress = bs58.encode(
      Buffer.from(`1220${this.data.ipfsHash.slice(2)}`, 'hex')
    );
  }
Example #2
Source File: proposal_header_links.tsx    From commonwealth with GNU General Public License v3.0 6 votes vote down vote up
view(vnode) {
    const { id, title } = vnode.attrs.thread;

    const proposalLink = getProposalUrlPath(ProposalType.OffchainThread, id);

    return (
      <div class="ProposalHeaderLink">
        {link('a', proposalLink, [
          decodeURIComponent(title),
          <CWIcon iconName="externalLink" iconSize="small" />,
        ])}
      </div>
    );
  }
Example #3
Source File: proposal_header_links.tsx    From commonwealth with GNU General Public License v3.0 6 votes vote down vote up
view(vnode) {
    const { proposal } = vnode.attrs;

    const path = getProposalUrlPath(
      ProposalType.OffchainThread,
      `${proposal.threadId}`,
      false,
      proposal['chain']
    );

    return (
      <div class="ProposalHeaderLink">
        {link('a', path, [
          'Go to discussion',
          <CWIcon iconName="externalLink" iconSize="small" />,
        ])}
      </div>
    );
  }
Example #4
Source File: identifiers.ts    From commonwealth with GNU General Public License v3.0 6 votes vote down vote up
proposalSlugToChainEntityType = (
  t: ProposalType
): IChainEntityKind => {
  if (t === ProposalType.SubstrateTreasuryProposal)
    return SubstrateTypes.EntityKind.TreasuryProposal;
  else if (t === ProposalType.SubstrateDemocracyReferendum)
    return SubstrateTypes.EntityKind.DemocracyReferendum;
  else if (t === ProposalType.SubstrateDemocracyProposal)
    return SubstrateTypes.EntityKind.DemocracyProposal;
  else if (t === ProposalType.SubstrateCollectiveProposal)
    return SubstrateTypes.EntityKind.CollectiveProposal;
  else if (t === ProposalType.SubstrateBountyProposal)
    return SubstrateTypes.EntityKind.TreasuryBounty;
  else if (t === ProposalType.SubstrateTreasuryTip)
    return SubstrateTypes.EntityKind.TipProposal;
}
Example #5
Source File: identifiers.ts    From commonwealth with GNU General Public License v3.0 6 votes vote down vote up
chainEntityTypeToProposalSlug = (
  t: IChainEntityKind
): ProposalType => {
  if (t === SubstrateTypes.EntityKind.TreasuryProposal)
    return ProposalType.SubstrateTreasuryProposal;
  else if (t === SubstrateTypes.EntityKind.DemocracyReferendum)
    return ProposalType.SubstrateDemocracyReferendum;
  else if (t === SubstrateTypes.EntityKind.DemocracyProposal)
    return ProposalType.SubstrateDemocracyProposal;
  else if (t === SubstrateTypes.EntityKind.CollectiveProposal)
    return ProposalType.SubstrateCollectiveProposal;
  else if (t === SubstrateTypes.EntityKind.TreasuryBounty)
    return ProposalType.SubstrateBountyProposal;
  else if (t === SubstrateTypes.EntityKind.TipProposal)
    return ProposalType.SubstrateTreasuryTip;
  else if (t === 'proposal') {
    if (app.chain.network === ChainNetwork.Sputnik) {
      return ProposalType.SputnikProposal;
    }
    if (app.chain.network === ChainNetwork.Moloch) {
      return ProposalType.MolochProposal;
    }
    if (app.chain.network === ChainNetwork.Compound) {
      return ProposalType.CompoundProposal;
    }
    if (app.chain.network === ChainNetwork.Aave) {
      return ProposalType.AaveProposal;
    }
  }
}
Example #6
Source File: identifiers.ts    From commonwealth with GNU General Public License v3.0 6 votes vote down vote up
proposalSlugToFriendlyName = new Map<ProposalType, string>([
  [ProposalType.SubstrateDemocracyReferendum, 'Democracy Referendum'],
  [ProposalType.SubstrateDemocracyProposal, 'Democracy Proposal'],
  [ProposalType.SubstratePreimage, 'Democracy Preimage'],
  [ProposalType.SubstrateBountyProposal, 'Bounty Proposal'],
  [ProposalType.SubstrateImminentPreimage, 'Democracy Imminent Preimage'],
  [ProposalType.SubstrateCollectiveProposal, 'Council Motion'],
  [ProposalType.PhragmenCandidacy, 'Phragmen Council Candidacy'],
  [ProposalType.SubstrateTreasuryProposal, 'Treasury Proposal'],
  [ProposalType.SubstrateTreasuryTip, 'Treasury Tip'],
  [ProposalType.OffchainThread, 'Discussion Thread'],
  [ProposalType.CompoundProposal, 'Proposal'],
  [ProposalType.CosmosProposal, 'Proposal'],
  [ProposalType.MolochProposal, 'Proposal'],
  [ProposalType.AaveProposal, 'Proposal'],
  [ProposalType.SputnikProposal, 'Proposal'],
])
Example #7
Source File: identifiers.ts    From commonwealth with GNU General Public License v3.0 6 votes vote down vote up
getProposalUrlPath = (type: ProposalType, id: string, omitActiveId = false, chainId?: string): string => {
  let basePath: string;
  const useTypeSlug = requiresTypeSlug(type);
  if (type === ProposalType.OffchainThread) {
    basePath = `/discussion/${id}`;
  } else if (useTypeSlug) {
    basePath = `/proposal/${type}/${id}`;
  } else {
    basePath = `/proposal/${id}`;
  }
  if (omitActiveId || (app.isCustomDomain() && !chainId)) {
    return basePath;
  } else {
    return `/${chainId || app.activeChainId()}${basePath}`;
  }
}
Example #8
Source File: treasury_tip.ts    From commonwealth with GNU General Public License v3.0 6 votes vote down vote up
constructor(
    ChainInfo: SubstrateChain,
    Accounts: SubstrateAccounts,
    Tips: SubstrateTreasuryTips,
    entity: ChainEntity,
  ) {
    super(ProposalType.SubstrateTreasuryTip, backportEventToAdapter(
      ChainInfo,
      entity.chainEvents
        .find(
          (e) => e.data.kind === SubstrateTypes.EventKind.NewTip
        ).data as SubstrateTypes.INewTip
    ));
    this._Chain = ChainInfo;
    this._Accounts = Accounts;
    this._Tips = Tips;

    this._author = this._Accounts.fromAddress(this.data.finder);
    this._description = this.data.reason;
    this.createdAt = entity.createdAt;

    entity.chainEvents.forEach((e) => this.update(e));

    if (!this.completed) {
      const slug = chainEntityTypeToProposalSlug(entity.type);
      const uniqueId = `${slug}_${entity.typeId}`;
      this._Chain.app.chain.chainEntities._fetchTitle(entity.chain, uniqueId).then((response) => {
        if (response.status === 'Success' && response.result?.length) {
          this._title = response.result;
        }
      });
    }
    this._initialized = true;
    this._Tips.store.add(this);
  }
Example #9
Source File: phragmen_election.ts    From commonwealth with GNU General Public License v3.0 6 votes vote down vote up
constructor(
    ChainInfo: SubstrateChain,
    Accounts: SubstrateAccounts,
    Elections: SubstratePhragmenElections,
    data: ISubstratePhragmenElection,
    moduleName: string,
  ) {
    super(ProposalType.PhragmenCandidacy, data);
    this._Chain = ChainInfo;
    this._Accounts = Accounts;
    this._Elections = Elections;
    this.title = `Set council votes for election ${data.round}`;
    this.moduleName = moduleName;

    this._initialized = true;
    this.updateVoters();
    this._Elections.store.add(this);
  }
Example #10
Source File: proposal.ts    From commonwealth with GNU General Public License v3.0 6 votes vote down vote up
constructor(
    Accounts: EthereumAccounts,
    Chain: CompoundChain,
    Gov: CompoundGovernance,
    entity: ChainEntity,
  ) {
    // must set identifier before super() because of how response object is named
    super(ProposalType.CompoundProposal, backportEntityToAdapter(Gov, entity));

    this._Accounts = Accounts;
    this._Chain = Chain;
    this._Gov = Gov;

    entity.chainEvents.sort((e1, e2) => e1.blockNumber - e2.blockNumber).forEach((e) => this.update(e));

    this._Gov.store.add(this);
  }
Example #11
Source File: bounty.ts    From commonwealth with GNU General Public License v3.0 6 votes vote down vote up
constructor(
    ChainInfo: SubstrateChain,
    Accounts: SubstrateAccounts,
    Treasury: SubstrateBountyTreasury,
    entity: ChainEntity,
  ) {
    super(ProposalType.SubstrateBountyProposal, backportEventToAdapter( // TODO: check if this is the right backport string
      ChainInfo,
      entity.chainEvents
        .find(
          (e) => e.data.kind === SubstrateTypes.EventKind.TreasuryBountyProposed
        ).data as SubstrateTypes.ITreasuryBountyProposed
    ));
    this._Chain = ChainInfo;
    this._Accounts = Accounts;
    this._Treasury = Treasury;

    this._value = this._Chain.coins(this.data.value);
    this._bond = this._Chain.coins(this.data.bond);
    this._curatorDeposit = this._Chain.coins(this.data.curator_deposit);
    this._author = this._Accounts.fromAddress(this.data.proposer);
    this._description = this.data.description;
    this.createdAt = entity.createdAt;

    entity.chainEvents.forEach((e) => this.update(e));

    this._initialized = true;
    this._Treasury.store.add(this);
  }
Example #12
Source File: proposal.ts    From commonwealth with GNU General Public License v3.0 6 votes vote down vote up
constructor(
    Chain: NearChain,
    Accounts: NearAccounts,
    Dao: NearSputnikDao,
    data: INearSputnikProposal
  ) {
    super(ProposalType.SputnikProposal, data);
    this._Chain = Chain;
    this._Accounts = Accounts;
    this._Dao = Dao;

    // init constants from data
    this._votePolicy = getVotePolicy(Dao.policy, data.kind);
    this._totalSupply = getTotalSupply(Dao.policy, this._votePolicy, Dao.tokenSupply);

    const periodS = +this._Dao.policy.proposal_period.slice(0, this._Dao.policy.proposal_period.length - 9);
    const submissionTimeS = +this.data.submission_time.slice(0, this.data.submission_time.length - 9);
    this._endTimeS = submissionTimeS + periodS;
    const nowS = moment.now() / 1000;
    if (data.status !== NearSputnikProposalStatus.InProgress) {
      this.complete(this._Dao.store);
    } else if (this._endTimeS < nowS) {
      console.log(`Marking proposal ${this.identifier} expired, by ${nowS - this._endTimeS} seconds.`);
      // special case for expiration that hasn't yet been triggered
      data.status = NearSputnikProposalStatus.Expired;
      this.complete(this._Dao.store);
    }
    // TODO: fetch weights for each voter? is this necessary?
    for (const [voter, choice] of Object.entries(data.votes)) {
      this.addOrUpdateVote(new NearSputnikVote(this._Accounts.get(voter), choice));
    }
    this._Dao.store.add(this);
  }
Example #13
Source File: proposal.ts    From commonwealth with GNU General Public License v3.0 6 votes vote down vote up
constructor(
    Members: MolochMembers,
    Gov: MolochGovernance,
    entity: ChainEntity,
  ) {
    // must set identifier before super() because of how response object is named
    super(ProposalType.MolochProposal, backportEntityToAdapter(Gov, entity));

    this._Members = Members;
    this._Gov = Gov;

    entity.chainEvents.sort((e1, e2) => e1.blockNumber - e2.blockNumber).forEach((e) => this.update(e));
    this._initialized = true;
    this._Gov.store.add(this);
  }
Example #14
Source File: treasury_proposal.ts    From commonwealth with GNU General Public License v3.0 5 votes vote down vote up
constructor(
    ChainInfo: SubstrateChain,
    Accounts: SubstrateAccounts,
    Treasury: SubstrateTreasury,
    entity: ChainEntity,
  ) {
    super(ProposalType.SubstrateTreasuryProposal, backportEventToAdapter(
      ChainInfo,
      // sometimes a TreasuryProposed chainEvent isn't available, so we have to fill in stub data
      (entity.chainEvents.find((e) => e.data.kind === SubstrateTypes.EventKind.TreasuryProposed)?.data as SubstrateTypes.ITreasuryProposed) || entity.typeId
    ));
    this._Chain = ChainInfo;
    this._Accounts = Accounts;
    this._Treasury = Treasury;

    this.value = this._Chain.coins(this.data.value);
    this.bond = this._Chain.coins(this.data.bond);
    this.beneficiaryAddress = this.data.beneficiary;
    this._author = this.data.proposer ? this._Accounts.fromAddress(this.data.proposer)
      : entity.author ? this._Accounts.fromAddress(this.data.proposer) : null;

    this.title = entity.title || this.generateTitle();
    this.createdAt = entity.createdAt;
    this.threadId = entity.threadId;
    this.threadTitle = entity.threadTitle;

    entity.chainEvents.forEach((e) => this.update(e));

    if (!this._completed) {
      const slug = chainEntityTypeToProposalSlug(entity.type);
      const uniqueId = `${slug}_${entity.typeId}`;
      this._Chain.app.chain.chainEntities._fetchTitle(entity.chain, uniqueId).then((response) => {
        if (response.status === 'Success' && response.result?.length) {
          this.title = response.result;
        }
      });
      this._initialized = true;
      this._Treasury.store.add(this);
    } else {
      this._initialized = true;
      this._Treasury.store.add(this);
    }
  }
Example #15
Source File: proposal.ts    From commonwealth with GNU General Public License v3.0 5 votes vote down vote up
constructor(ChainInfo: CosmosChain, Accounts: CosmosAccounts, Governance: CosmosGovernance, data: ICosmosProposal) {
    super(ProposalType.CosmosProposal, data);
    this._Chain = ChainInfo;
    this._Accounts = Accounts;
    this._Governance = Governance;
    this._Governance.store.add(this);
  }
Example #16
Source File: Proposal.ts    From commonwealth with GNU General Public License v3.0 5 votes vote down vote up
public readonly slug: ProposalType;
Example #17
Source File: Proposal.ts    From commonwealth with GNU General Public License v3.0 5 votes vote down vote up
constructor(slug: ProposalType, data: ConstructorT) {
    this.slug = slug;
    this._data = data;
    this.identifier = data.identifier;
  }
Example #18
Source File: OffchainThread.ts    From commonwealth with GNU General Public License v3.0 5 votes vote down vote up
public readonly slug = ProposalType.OffchainThread;
Example #19
Source File: identifiers.ts    From commonwealth with GNU General Public License v3.0 5 votes vote down vote up
proposalSlugToClass = () => {
  const mmap = new Map<
    string,
    ProposalModule<any, any, any> | ThreadsController
  >([[ProposalType.OffchainThread, app.threads]]);
  if (app.chain.base === ChainBase.Substrate) {
    mmap.set(
      ProposalType.SubstrateDemocracyReferendum,
      (app.chain as any).democracy
    );
    mmap.set(
      ProposalType.SubstrateDemocracyProposal,
      (app.chain as any).democracyProposals
    );
    mmap.set(
      ProposalType.SubstrateCollectiveProposal,
      (app.chain as any).council
    );
    mmap.set(
      ProposalType.PhragmenCandidacy,
      (app.chain as any).phragmenElections
    );
    mmap.set(
      ProposalType.SubstrateTreasuryProposal,
      (app.chain as any).treasury
    );
    mmap.set(ProposalType.SubstrateBountyProposal, (app.chain as any).bounties);
    mmap.set(ProposalType.SubstrateTreasuryTip, (app.chain as any).tips);
  } else if (app.chain.base === ChainBase.CosmosSDK) {
    mmap.set(ProposalType.CosmosProposal, (app.chain as any).governance);
  }
  if (
    app.chain.network === ChainNetwork.Kusama ||
    app.chain.network === ChainNetwork.Polkadot
  ) {
    mmap.set(
      ProposalType.SubstrateTechnicalCommitteeMotion,
      (app.chain as any).technicalCommittee
    );
  }
  if (app.chain.network === ChainNetwork.Moloch) {
    mmap.set(ProposalType.MolochProposal, (app.chain as any).governance);
  }
  if (app.chain.network === ChainNetwork.Compound) {
    mmap.set(ProposalType.CompoundProposal, (app.chain as any).governance);
  }
  if (app.chain.network === ChainNetwork.Aave) {
    mmap.set(ProposalType.AaveProposal, (app.chain as any).governance);
  }
  if (app.chain.network === ChainNetwork.Sputnik) {
    mmap.set(ProposalType.SputnikProposal, (app.chain as any).dao);
  }
  return mmap;
}
Example #20
Source File: democracy_referendum.ts    From commonwealth with GNU General Public License v3.0 5 votes vote down vote up
// CONSTRUCTORS
  constructor(
    ChainInfo: SubstrateChain,
    Accounts: SubstrateAccounts,
    Democracy: SubstrateDemocracy,
    entity: ChainEntity,
  ) {
    super(ProposalType.SubstrateDemocracyReferendum, backportEventToAdapter(
      entity.chainEvents
        .find(
          (e) => e.data.kind === SubstrateTypes.EventKind.DemocracyStarted
        ).data as SubstrateTypes.IDemocracyStarted
    ));

    const eventData = entity.chainEvents
      .find(
        (e) => e.data.kind === SubstrateTypes.EventKind.DemocracyStarted
      ).data as SubstrateTypes.IDemocracyStarted;
    this._Chain = ChainInfo;
    this._Accounts = Accounts;
    this._Democracy = Democracy;
    this._endBlock = this.data.endBlock;
    this._threshold = this.data.threshold;
    this.hash = eventData.proposalHash;
    this.createdAt = entity.createdAt;
    this.threadId = entity.threadId;
    this.threadTitle = entity.threadTitle;

    // see if associated entity title exists, otherwise try to populate title with preimage
    const preimage = this._Democracy.app.chain.chainEntities.getPreimage(eventData.proposalHash);
    const associatedProposalOrMotion = this.getProposalOrMotion(preimage);
    if (associatedProposalOrMotion) {
      this.title = associatedProposalOrMotion.title;
    } else {
      if (preimage) {
        this._preimage = preimage;
        this.title = formatCall(preimage);
      } else {
        this.title = `Referendum #${this.data.index}`;
      }
    }

    // handle events params for passing, if exists at init time
    entity.chainEvents.forEach((e) => this.update(e));

    this._initialized = true;
    this.updateVoters();
    this._Democracy.store.add(this);

    // fetcher cannot generate "NotPassed" events
    if (this._endBlock < this._Democracy.app.chain.block.height && !this.passed && !this.completed) {
      this.complete();
    }
  }
Example #21
Source File: democracy_proposal.ts    From commonwealth with GNU General Public License v3.0 5 votes vote down vote up
// CONSTRUCTORS
  constructor(
    ChainInfo: SubstrateChain,
    Accounts: SubstrateAccounts,
    Proposals: SubstrateDemocracyProposals,
    entity: ChainEntity,
  ) {
    // fake adapter data
    super(ProposalType.SubstrateDemocracyProposal, backportEventToAdapter(
      ChainInfo,
      entity.chainEvents
        .find(
          (e) => e.data.kind === SubstrateTypes.EventKind.DemocracyProposed
        ).data as SubstrateTypes.IDemocracyProposed
    ));
    const eventData = entity.chainEvents
      .find(
        (e) => e.data.kind === SubstrateTypes.EventKind.DemocracyProposed
      ).data as SubstrateTypes.IDemocracyProposed;
    this._Chain = ChainInfo;
    this._Accounts = Accounts;
    this._Proposals = Proposals;
    this.deposit = this._Chain.coins(new BN(eventData.deposit, 10));
    this._author = this._Accounts.fromAddress(eventData.proposer || entity.author);
    this.hash = eventData.proposalHash;
    this.createdAt = entity.createdAt;
    this.threadId = entity.threadId;
    this.threadTitle = entity.threadTitle;

    // see if preimage exists and populate data if it does
    const preimage = this._Proposals.app.chain.chainEntities.getPreimage(eventData.proposalHash);
    if (preimage) {
      this._method = preimage.method;
      this._section = preimage.section;
      this._preimage = preimage;
      this.title = entity.title || formatCall(preimage);
    } else {
      this.title = entity.title || `Proposal ${formatProposalHashShort(eventData.proposalHash)}`;
    }

    entity.chainEvents.forEach((e) => this.update(e));

    if (!this._completed) {
      const slug = chainEntityTypeToProposalSlug(entity.type);
      const uniqueId = `${slug}_${entity.typeId}`;
      this._Proposals.app.chain.chainEntities._fetchTitle(entity.chain, uniqueId).then((response) => {
        if (response.status === 'Success' && response.result?.length) {
          this.title = response.result;
        }
        this._initialized = true;
        this.updateVoters();
        this._Proposals.store.add(this);
      });
    } else {
      this._initialized = true;
      this.updateVoters();
      this._Proposals.store.add(this);
    }
  }
Example #22
Source File: collective_proposal.ts    From commonwealth with GNU General Public License v3.0 5 votes vote down vote up
// CONSTRUCTORS
  constructor(
    ChainInfo: SubstrateChain,
    Accounts: SubstrateAccounts,
    Collective: SubstrateCollective,
    entity: ChainEntity,
  ) {
    super(ProposalType.SubstrateCollectiveProposal, backportEventToAdapter(
      entity.chainEvents
        .find(
          (e) => e.data.kind === SubstrateTypes.EventKind.CollectiveProposed
        ).data as SubstrateTypes.ICollectiveProposed
    ));
    const eventData = entity.chainEvents
      .find(
        (e) => e.data.kind === SubstrateTypes.EventKind.CollectiveProposed
      ).data as SubstrateTypes.ICollectiveProposed;
    this._Chain = ChainInfo;
    this._Accounts = Accounts;
    this._Collective = Collective;
    this._call = eventData.call;
    this.title = entity.title || formatCall(eventData.call);
    this.createdAt = entity.createdAt;
    this.threadId = entity.threadId;
    this.threadTitle = entity.threadTitle;

    entity.chainEvents.forEach((e) => this.update(e));

    if (!this._completed) {
      const slug = chainEntityTypeToProposalSlug(entity.type);
      const uniqueId = `${slug}_${entity.typeId}`;
      this._Chain.app.chain.chainEntities._fetchTitle(entity.chain, uniqueId).then((response) => {
        if (response.status === 'Success' && response.result?.length) {
          this.title = response.result;
        }
      });
      this._initialized = true;
      this.updateVoters();
      this._Collective.store.add(this);
    } else {
      this._initialized = true;
      this.updateVoters();
      this._Collective.store.add(this);
    }
  }
Example #23
Source File: identifiers.ts    From commonwealth with GNU General Public License v3.0 5 votes vote down vote up
chainToProposalSlug = (c: ChainInfo): ProposalType => {
  if (c.base === ChainBase.CosmosSDK) return ProposalType.CosmosProposal;
  if (c.network === ChainNetwork.Sputnik) return ProposalType.SputnikProposal;
  if (c.network === ChainNetwork.Moloch) return ProposalType.MolochProposal;
  if (c.network === ChainNetwork.Compound) return ProposalType.CompoundProposal;
  if (c.network === ChainNetwork.Aave) return ProposalType.AaveProposal;
  throw new Error(`Cannot determine proposal slug from chain ${c.id}.`);
}
Example #24
Source File: AbridgedThread.ts    From commonwealth with GNU General Public License v3.0 5 votes vote down vote up
public readonly slug = ProposalType.OffchainThread;
Example #25
Source File: new_proposal_button.tsx    From commonwealth with GNU General Public License v3.0 4 votes vote down vote up
view(vnode) {
    const { mobile } = vnode.attrs;

    const activeAccount = app.user.activeAccount;

    const showSnapshotOptions =
      app.user.activeAccount && app.chain?.meta.snapshot.length > 0;

    const topics = app.topics
      .getByCommunity(app.activeChainId())
      .reduce(
        (acc, current) => (current.featuredInNewPost ? [...acc, current] : acc),
        []
      )
      .sort((a, b) => a.name.localeCompare(b.name));

    return (
      <>
        <MenuItem
          onclick={() => {
            navigateToSubpage('/new/discussion');
          }}
          label="New thread"
          iconLeft={mobile ? Icons.PLUS : undefined}
        />
        {topics.map((t) => (
          <MenuItem
            onclick={() => {
              localStorage.setItem(
                `${app.activeChainId()}-active-topic`,
                t.name
              );
              if (t.defaultOffchainTemplate) {
                localStorage.setItem(
                  `${app.activeChainId()}-active-topic-default-template`,
                  t.defaultOffchainTemplate
                );
              } else {
                localStorage.removeItem(
                  `${app.activeChainId()}-active-topic-default-template`
                );
              }
              navigateToSubpage('/new/discussion');
            }}
            label={`New ${t.name} Thread`}
            iconLeft={mobile ? Icons.PLUS : undefined}
          />
        ))}
        {(app.chain?.network === ChainNetwork.Aave ||
          app.chain?.network === ChainNetwork.dYdX ||
          app.chain?.network === ChainNetwork.Compound ||
          app.chain?.base === ChainBase.CosmosSDK ||
          app.chain?.base === ChainBase.Substrate) &&
          !mobile && <MenuDivider />}
        {app.chain?.base === ChainBase.CosmosSDK && (
          <MenuItem
            onclick={() => navigateToSubpage('/new/proposal')}
            label="New On-Chain Proposal"
            iconLeft={mobile ? Icons.PLUS : undefined}
          />
        )}
        {app.chain?.base === ChainBase.Ethereum &&
          app.chain?.network === ChainNetwork.Aave && (
            <MenuItem
              onclick={() => navigateToSubpage('/new/proposal')}
              label="New On-Chain Proposal"
              iconLeft={mobile ? Icons.PLUS : undefined}
            />
          )}
        {app.chain?.network === ChainNetwork.Compound && (
          <MenuItem
            onclick={() => navigateToSubpage('/new/proposal')}
            label="New On-Chain Proposal"
            iconLeft={mobile ? Icons.PLUS : undefined}
          />
        )}
        {app.chain?.base === ChainBase.Substrate &&
          app.chain?.network !== ChainNetwork.Plasm && (
            <>
              <MenuItem
                onclick={() =>
                  navigateToSubpage('/new/proposal/:type', {
                    type: ProposalType.SubstrateTreasuryProposal,
                  })
                }
                label="New treasury proposal"
                iconLeft={mobile ? Icons.PLUS : undefined}
              />
              <MenuItem
                onclick={() =>
                  navigateToSubpage('/new/proposal/:type', {
                    type: ProposalType.SubstrateDemocracyProposal,
                  })
                }
                label="New democracy proposal"
                iconLeft={mobile ? Icons.PLUS : undefined}
              />
              <MenuItem
                class={
                  activeAccount && (activeAccount as any).isCouncillor
                    ? ''
                    : 'disabled'
                }
                onclick={() =>
                  navigateToSubpage('/new/proposal/:type', {
                    type: ProposalType.SubstrateCollectiveProposal,
                  })
                }
                label="New council motion"
                iconLeft={mobile ? Icons.PLUS : undefined}
              />
              <MenuItem
                onclick={() =>
                  navigateToSubpage('/new/proposal/:type', {
                    type: ProposalType.SubstrateBountyProposal,
                  })
                }
                label="New bounty proposal"
                iconLeft={mobile ? Icons.PLUS : undefined}
              />
              <MenuItem
                onclick={() =>
                  navigateToSubpage('/new/proposal/:type', {
                    type: ProposalType.SubstrateTreasuryTip,
                  })
                }
                label="New tip"
                iconLeft={mobile ? Icons.PLUS : undefined}
              />
            </>
          )}
        {app.chain.network === ChainNetwork.Sputnik && (
          <MenuItem
            onclick={() => navigateToSubpage('/new/proposal')}
            label="New Sputnik proposal"
            iconLeft={mobile ? Icons.PLUS : undefined}
          />
        )}
        {showSnapshotOptions && (
          <MenuItem
            onclick={() => {
              const snapshotSpaces = app.chain.meta.snapshot;
              if (snapshotSpaces.length > 1) {
                navigateToSubpage('/multiple-snapshots', {
                  action: 'create-proposal',
                });
              } else {
                navigateToSubpage(`/new/snapshot/${snapshotSpaces}`);
              }
            }}
            label="New Snapshot Proposal"
            iconLeft={mobile ? Icons.PLUS : undefined}
          />
        )}
      </>
    );
  }
Example #26
Source File: notification_row.ts    From commonwealth with GNU General Public License v3.0 4 votes vote down vote up
getNotificationFields = (category, data: IPostNotificationData) => {
  const {
    created_at,
    root_id,
    root_title,
    root_type,
    comment_id,
    comment_text,
    parent_comment_id,
    parent_comment_text,
    chain_id,
    author_address,
    author_chain,
  } = data;

  const community_name =
    app.config.chains.getById(chain_id)?.name || 'Unknown chain';

  let notificationHeader;
  let notificationBody;
  const decoded_title = decodeURIComponent(root_title).trim();

  if (comment_text) {
    notificationBody = getCommentPreview(comment_text);
  } else if (root_type === ProposalType.OffchainThread) {
    notificationBody = null;
  }

  const actorName = m(User, {
    user: new AddressInfo(null, author_address, author_chain, null),
    hideAvatar: true,
    hideIdentityIcon: true,
  });

  if (category === NotificationCategories.NewComment) {
    // Needs logic for notifications issued to parents of nested comments
    notificationHeader = parent_comment_id
      ? m('span', [
          actorName,
          ' commented on ',
          m('span.commented-obj', decoded_title),
        ])
      : m('span', [
          actorName,
          ' responded in ',
          m('span.commented-obj', decoded_title),
        ]);
  } else if (category === NotificationCategories.NewThread) {
    notificationHeader = m('span', [
      actorName,
      ' created a new thread ',
      m('span.commented-obj', decoded_title),
    ]);
  } else if (category === `${NotificationCategories.NewMention}`) {
    notificationHeader = m('span', [
      actorName,
      ' mentioned you in ',
      m('span.commented-obj', decoded_title),
    ]);
  } else if (category === `${NotificationCategories.NewCollaboration}`) {
    notificationHeader = m('span', [
      actorName,
      ' added you as a collaborator on ',
      m('span.commented-obj', decoded_title),
    ]);
  } else if (category === `${NotificationCategories.NewReaction}`) {
    notificationHeader = !comment_id
      ? m('span', [
          actorName,
          ' liked the post ',
          m('span.commented-obj', decoded_title),
        ])
      : m('span', [
          actorName,
          ' liked your comment in ',
          m('span.commented-obj', decoded_title || community_name),
        ]);
  }
  const pseudoProposal = {
    id: root_id,
    title: root_title,
    chain: chain_id,
  };
  const args = comment_id
    ? [root_type, pseudoProposal, { id: comment_id }]
    : [root_type, pseudoProposal];
  const path = (getProposalUrl as any)(...args);
  const pageJump = comment_id
    ? () => jumpHighlightComment(comment_id)
    : () => jumpHighlightComment('parent');

  return {
    authorInfo: [[author_chain, author_address]],
    createdAt: moment.utc(created_at),
    notificationHeader,
    notificationBody,
    path,
    pageJump,
  };
}
Example #27
Source File: notification_row.ts    From commonwealth with GNU General Public License v3.0 4 votes vote down vote up
getBatchNotificationFields = (
  category,
  data: IPostNotificationData[]
) => {
  if (data.length === 1) {
    return getNotificationFields(category, data[0]);
  }

  const {
    created_at,
    root_id,
    root_title,
    root_type,
    comment_id,
    comment_text,
    parent_comment_id,
    parent_comment_text,
    chain_id,
    author_address,
    author_chain,
  } = data[0];

  const authorInfo = _.uniq(
    data.map((d) => `${d.author_chain}#${d.author_address}`)
  ).map((u) => u.split('#'));
  const length = authorInfo.length - 1;
  const community_name =
    app.config.chains.getById(chain_id)?.name || 'Unknown chain';

  let notificationHeader;
  let notificationBody;
  const decoded_title = decodeURIComponent(root_title).trim();

  if (comment_text) {
    notificationBody = getCommentPreview(comment_text);
  } else if (root_type === ProposalType.OffchainThread) {
    notificationBody = null;
  }

  const actorName = m(User, {
    user: new AddressInfo(null, author_address, author_chain, null),
    hideAvatar: true,
    hideIdentityIcon: true,
  });

  if (category === NotificationCategories.NewComment) {
    // Needs logic for notifications issued to parents of nested comments
    notificationHeader = parent_comment_id
      ? m('span', [
          actorName,
          length > 0 && ` and ${pluralize(length, 'other')}`,
          ' commented on ',
          m('span.commented-obj', decoded_title),
        ])
      : m('span', [
          actorName,
          length > 0 && ` and ${pluralize(length, 'other')}`,
          ' responded in ',
          m('span.commented-obj', decoded_title),
        ]);
  } else if (category === NotificationCategories.NewThread) {
    notificationHeader = m('span', [
      actorName,
      length > 0 && ` and ${pluralize(length, 'other')}`,
      ' created new threads in ',
      m('span.commented-obj', community_name),
    ]);
  } else if (category === `${NotificationCategories.NewMention}`) {
    notificationHeader = !comment_id
      ? m('span', [
          actorName,
          length > 0 && ` and ${pluralize(length, 'other')}`,
          ' mentioned you in ',
          m('span.commented-obj', community_name),
        ])
      : m('span', [
          actorName,
          length > 0 && ` and ${pluralize(length, 'other')}`,
          ' mentioned you in ',
          m('span.commented-obj', decoded_title || community_name),
        ]);
  } else if (category === `${NotificationCategories.NewReaction}`) {
    notificationHeader = !comment_id
      ? m('span', [
          actorName,
          length > 0 && ` and ${pluralize(length, 'other')}`,
          ' liked the post ',
          m('span.commented-obj', decoded_title),
        ])
      : m('span', [
          actorName,
          length > 0 && ` and ${pluralize(length, 'other')}`,
          ' liked your comment in ',
          m('span.commented-obj', decoded_title || community_name),
        ]);
  }
  const pseudoProposal = {
    id: root_id,
    title: root_title,
    chain: chain_id,
  };
  const args = comment_id
    ? [root_type, pseudoProposal, { id: comment_id }]
    : [root_type, pseudoProposal];
  const path =
    category === NotificationCategories.NewThread
      ? (getCommunityUrl as any)(chain_id)
      : (getProposalUrl as any)(...args);
  const pageJump = comment_id
    ? () => jumpHighlightComment(comment_id)
    : () => jumpHighlightComment('parent');
  return {
    authorInfo,
    createdAt: moment.utc(created_at),
    notificationHeader,
    notificationBody,
    path,
    pageJump,
  };
}
Example #28
Source File: proposal_card.tsx    From commonwealth with GNU General Public License v3.0 4 votes vote down vote up
view(vnode) {
    const { proposal, injectedContent } = vnode.attrs;

    return (
      <CWCard
        elevation="elevation-2"
        interactive={true}
        className="ProposalCard"
        onclick={(e) => {
          e.stopPropagation();
          e.preventDefault();
          localStorage[`${app.activeChainId()}-proposals-scrollY`] =
            window.scrollY;
          const path = getProposalUrlPath(
            proposal.slug,
            `${proposal.identifier}-${slugify(proposal.title)}`,
            true
          );
          navigateToSubpage(path); // avoid resetting scroll point
        }}
      >
        <div class="proposal-card-metadata">
          <Tag
            label={[
              chainEntityTypeToProposalShortName(
                proposalSlugToChainEntityType(proposal.slug)
              ),
              ' ',
              proposal.shortIdentifier,
            ]}
            intent="primary"
            rounded={true}
            size="xs"
          />
          {(proposal instanceof SubstrateDemocracyProposal ||
            proposal instanceof SubstrateCollectiveProposal) &&
            proposal.getReferendum() && (
              <Tag
                label={`REF #${proposal.getReferendum().identifier}`}
                intent="primary"
                rounded={true}
                size="xs"
                class="proposal-became-tag"
              />
            )}
          {proposal instanceof SubstrateDemocracyReferendum &&
            (() => {
              const originatingProposalOrMotion = proposal.getProposalOrMotion(
                proposal.preimage
              );
              return (
                <Tag
                  label={
                    originatingProposalOrMotion instanceof
                    SubstrateDemocracyProposal
                      ? `PROP #${originatingProposalOrMotion.identifier}`
                      : originatingProposalOrMotion instanceof
                        SubstrateCollectiveProposal
                      ? `MOT #${originatingProposalOrMotion.identifier}`
                      : 'MISSING PROP'
                  }
                  intent="primary"
                  rounded={true}
                  size="xs"
                  class="proposal-became-tag"
                />
              );
            })()}
          {proposal instanceof SubstrateTreasuryProposal &&
            !proposal.data.index && (
              <Tag
                label="MISSING DATA"
                intent="primary"
                rounded={true}
                size="xs"
                class="proposal-became-tag"
              />
            )}
          <div class="proposal-title" title={proposal.title}>
            {proposal.title}
          </div>
          {proposal instanceof SubstrateTreasuryProposal && (
            <div class="proposal-amount">{proposal.value?.format(true)}</div>
          )}
          {proposal instanceof SubstrateDemocracyReferendum && (
            <div class="proposal-amount">{proposal.threshold}</div>
          )}
          {proposal instanceof AaveProposal && (
            <p class="card-subheader">
              {proposal.ipfsData?.shortDescription || 'Proposal'}
            </p>
          )}
          {/* linked treasury proposals
            proposal instanceof SubstrateDemocracyReferendum && proposal.preimage?.section === 'treasury'
               && proposal.preimage?.method === 'approveProposal'
              && m('.proposal-action', [ 'Approves TRES-', proposal.preimage?.args[0] ]),
             proposal instanceof SubstrateDemocracyProposal && proposal.preimage?.section === 'treasury'
              && proposal.preimage?.method === 'approveProposal'
              && m('.proposal-action', [ 'Approves TRES-', proposal.preimage?.args[0] ]),
             proposal instanceof SubstrateCollectiveProposal && proposal.call?.section === 'treasury'
               && proposal.call?.method === 'approveProposal'
               && m('.proposal-action', [ 'Approves TRES-', proposal.call?.args[0] ]),
             linked referenda */}
        </div>
        {injectedContent ? (
          <div class="proposal-injected">
            {m(injectedContent, {
              proposal,
              statusClass: getStatusClass(proposal),
              statusText: getStatusText(proposal),
            })}
          </div>
        ) : proposal.isPassing !== 'none' ? (
          <div class={`proposal-status ${getStatusClass(proposal)}`}>
            {getStatusText(proposal)}
          </div>
        ) : null}
        {proposal.threadId && (
          <div class="proposal-thread-link">
            <a
              href={getProposalUrlPath(
                ProposalType.OffchainThread,
                `${proposal.threadId}`
              )}
              onclick={(e) => {
                e.stopPropagation();
                e.preventDefault();
                localStorage[`${app.activeChainId()}-proposals-scrollY`] =
                  window.scrollY;
                navigateToSubpage(
                  getProposalUrlPath(
                    ProposalType.OffchainThread,
                    `${proposal.threadId}`,
                    true
                  )
                );
                // avoid resetting scroll point
              }}
            >
              <CWIcon iconName="expand" iconSize="small" />
              <span>
                {proposal.threadTitle ? proposal.threadTitle : 'Go to thread'}
              </span>
            </a>
          </div>
        )}
      </CWCard>
    );
  }
Example #29
Source File: governance_section.tsx    From commonwealth with GNU General Public License v3.0 4 votes vote down vote up
view(vnode) {
    // Conditional Render Details
    const hasProposals =
      app.chain &&
      (app.chain.base === ChainBase.CosmosSDK ||
        app.chain.network === ChainNetwork.Sputnik ||
        (app.chain.base === ChainBase.Substrate &&
          app.chain.network !== ChainNetwork.Plasm) ||
        app.chain.network === ChainNetwork.Moloch ||
        app.chain.network === ChainNetwork.Compound ||
        app.chain.network === ChainNetwork.Aave ||
        app.chain.network === ChainNetwork.Commonwealth ||
        app.chain.meta.snapshot);
    if (!hasProposals) return;

    const isNotOffchain = app.chain?.meta.type !== ChainType.Offchain;

    const showMolochMenuOptions =
      isNotOffchain &&
      app.user.activeAccount &&
      app.chain?.network === ChainNetwork.Moloch;
    const showMolochMemberOptions =
      isNotOffchain &&
      showMolochMenuOptions &&
      (app.user.activeAccount as any)?.shares?.gtn(0);
    const showCommonwealthMenuOptions =
      isNotOffchain && app.chain?.network === ChainNetwork.Commonwealth;
    const showCompoundOptions =
      isNotOffchain &&
      app.user.activeAccount &&
      app.chain?.network === ChainNetwork.Compound;
    const showAaveOptions =
      isNotOffchain &&
      app.user.activeAccount &&
      app.chain?.network === ChainNetwork.Aave;
    const showSnapshotOptions =
      isNotOffchain && app.chain?.meta.snapshot?.length > 0;
    const showReferenda =
      isNotOffchain &&
      app.chain?.base === ChainBase.Substrate &&
      app.chain.network !== ChainNetwork.Darwinia &&
      app.chain.network !== ChainNetwork.HydraDX;
    const showProposals =
      isNotOffchain &&
      ((app.chain?.base === ChainBase.Substrate &&
        app.chain.network !== ChainNetwork.Darwinia) ||
        (app.chain?.base === ChainBase.CosmosSDK && 
        app.chain.network !== ChainNetwork.Terra) ||
        app.chain?.network === ChainNetwork.Sputnik ||
        app.chain?.network === ChainNetwork.Moloch ||
        app.chain?.network === ChainNetwork.Compound ||
        app.chain?.network === ChainNetwork.Aave);
    const showCouncillors =
      isNotOffchain && app.chain?.base === ChainBase.Substrate;
    const showTreasury =
      isNotOffchain &&
      app.chain?.base === ChainBase.Substrate &&
      app.chain.network !== ChainNetwork.Centrifuge;
    const showBounties =
      isNotOffchain &&
      app.chain?.base === ChainBase.Substrate &&
      app.chain.network !== ChainNetwork.Centrifuge &&
      app.chain.network !== ChainNetwork.HydraDX;
    const showTips =
      isNotOffchain &&
      app.chain?.base === ChainBase.Substrate &&
      app.chain.network !== ChainNetwork.Centrifuge;
    const showValidators =
      isNotOffchain &&
      app.chain?.base === ChainBase.Substrate &&
      app.chain?.network !== ChainNetwork.Kulupu &&
      app.chain?.network !== ChainNetwork.Darwinia;

    // ---------- Build Toggle Tree ---------- //
    const governanceDefaultToggleTree: ToggleTree = {
      toggledState: true,
      children: {
        Members: {
          toggledState: false,
          children: {},
        },
        ...(showSnapshotOptions && {
          Snapshots: {
            toggledState: false,
            children: {},
          },
        }),
        ...(showCompoundOptions && {
          Delegate: {
            toggledState: true,
            children: {},
          },
        }),
        ...(showTreasury && {
          Treasury: {
            toggledState: false,
            children: {},
          },
        }),
        ...(showBounties && {
          Bounties: {
            toggledState: false,
            children: {},
          },
        }),
        ...(showReferenda && {
          Referenda: {
            toggledState: false,
            children: {},
          },
        }),
        ...(showProposals && {
          Proposals: {
            toggledState: false,
            children: {},
          },
        }),
        ...(showTips && {
          Tips: {
            toggledState: false,
            children: {},
          },
        }),
        ...(showCouncillors && {
          Councillors: {
            toggledState: false,
            children: {},
          },
        }),
        ...(showValidators && {
          Validators: {
            toggledState: false,
            children: {},
          },
        }),
      },
    };

    // Check if an existing toggle tree is stored
    if (!localStorage[`${app.activeChainId()}-governance-toggle-tree`]) {
      console.log('setting toggle tree from scratch');
      localStorage[`${app.activeChainId()}-governance-toggle-tree`] =
        JSON.stringify(governanceDefaultToggleTree);
    } else if (
      !verifyCachedToggleTree('governance', governanceDefaultToggleTree)
    ) {
      console.log(
        'setting discussions toggle tree since the cached version differs from the updated version'
      );
      localStorage[`${app.activeChainId()}-governance-toggle-tree`] =
        JSON.stringify(governanceDefaultToggleTree);
    }
    let toggleTreeState = JSON.parse(
      localStorage[`${app.activeChainId()}-governance-toggle-tree`]
    );
    if (vnode.attrs.mobile) {
      toggleTreeState = governanceDefaultToggleTree;
    }

    const onSnapshotProposal = (p) =>
      p.startsWith(`/${app.activeChainId()}/snapshot`);
    const onSnapshotProposalCreation = (p) =>
      p.startsWith(`/${app.activeChainId()}/new/snapshot/`);
    const onProposalPage = (p) =>
      p.startsWith(`/${app.activeChainId()}/proposals`) ||
      p.startsWith(
        `/${app.activeChainId()}/proposal/${
          ProposalType.SubstrateDemocracyProposal
        }`
      );
    const onReferendaPage = (p) =>
      p.startsWith(`/${app.activeChainId()}/referenda`) ||
      p.startsWith(
        `/${app.activeChainId()}/proposal/${
          ProposalType.SubstrateDemocracyReferendum
        }`
      );
    const onTreasuryPage = (p) =>
      p.startsWith(`/${app.activeChainId()}/treasury`) ||
      p.startsWith(
        `/${app.activeChainId()}/proposal/${
          ProposalType.SubstrateTreasuryProposal
        }`
      );
    const onBountiesPage = (p) =>
      p.startsWith(`/${app.activeChainId()}/bounties`);
    const onTipsPage = (p) =>
      p.startsWith(`/${app.activeChainId()}/tips`) ||
      p.startsWith(
        `/${app.activeChainId()}/proposal/${ProposalType.SubstrateTreasuryTip}`
      );
    const onCouncilPage = (p) =>
      p.startsWith(`/${app.activeChainId()}/council`);
    const onMotionPage = (p) =>
      p.startsWith(`/${app.activeChainId()}/motions`) ||
      p.startsWith(
        `/${app.activeChainId()}/proposal/${
          ProposalType.SubstrateCollectiveProposal
        }`
      );
    const onValidatorsPage = (p) =>
      p.startsWith(`/${app.activeChainId()}/validators`);
    const onNotificationsPage = (p) => p.startsWith('/notifications');
    const onMembersPage = (p) =>
      p.startsWith(`/${app.activeChainId()}/members`) ||
      p.startsWith(`/${app.activeChainId()}/account/`);

    if (onNotificationsPage(m.route.get())) return;

    // ---------- Build Section Props ---------- //

    // Members
    const membersData: SectionGroupAttrs = {
      title: 'Members',
      containsChildren: false,
      hasDefaultToggle: toggleTreeState['children']['Members']['toggledState'],
      isVisible: true,
      isUpdated: true,
      isActive:
        onMembersPage(m.route.get()) &&
        (app.chain ? app.chain.serverLoaded : true),
      onclick: (e, toggle: boolean) => {
        e.preventDefault();
        setGovernanceToggleTree('children.Members.toggledState', toggle);
        navigateToSubpage('/members');
      },
      displayData: null,
    };

    // Snapshots
    const snapshotData: SectionGroupAttrs = {
      title: 'Snapshots',
      containsChildren: false,
      hasDefaultToggle: showSnapshotOptions
        ? toggleTreeState['children']['Snapshots']['toggledState']
        : false,
      isVisible: showSnapshotOptions,
      isActive: onSnapshotProposal(m.route.get()),
      isUpdated: true,
      onclick: (e, toggle: boolean) => {
        e.preventDefault();
        setGovernanceToggleTree('children.Snapshots.toggledState', toggle);
        // Check if we have multiple snapshots for conditional redirect
        const snapshotSpaces = app.chain.meta.snapshot;
        if (snapshotSpaces.length > 1) {
          navigateToSubpage('/multiple-snapshots', { action: 'select-space' });
        } else {
          navigateToSubpage(`/snapshot/${snapshotSpaces}`);
        }
      },
      displayData: null,
    };

    // Proposals
    const proposalsData: SectionGroupAttrs = {
      title: 'Proposals',
      containsChildren: false,
      hasDefaultToggle: showProposals
        ? toggleTreeState['children']['Proposals']['toggledState']
        : false,
      onclick: (e, toggle: boolean) => {
        e.preventDefault();
        navigateToSubpage('/proposals');
        setGovernanceToggleTree('children.Proposals.toggledState', toggle);
      },
      isVisible: showProposals,
      isUpdated: true,
      isActive: onProposalPage(m.route.get()),
      displayData: null,
    };

    // Treasury
    const treasuryData: SectionGroupAttrs = {
      title: 'Treasury',
      containsChildren: false,
      hasDefaultToggle: showTreasury
        ? toggleTreeState['children']['Treasury']['toggledState']
        : false,
      onclick: (e, toggle: boolean) => {
        e.preventDefault();
        navigateToSubpage('/treasury');
        setGovernanceToggleTree('children.Treasury.toggledState', toggle);
      },
      isVisible: showTreasury,
      isUpdated: true,
      isActive: onTreasuryPage(m.route.get()),
      displayData: null,
    };

    const bountyData: SectionGroupAttrs = {
      title: 'Bounties',
      containsChildren: false,
      hasDefaultToggle: showBounties
        ? toggleTreeState['children']['Bounties']['toggledState']
        : false,
      onclick: (e, toggle: boolean) => {
        e.preventDefault();
        navigateToSubpage('/bounties');
        setGovernanceToggleTree('children.Bounties.toggledState', toggle);
      },
      isVisible: showBounties,
      isUpdated: true,
      isActive: onBountiesPage(m.route.get()),
      displayData: null,
    };

    const referendaData: SectionGroupAttrs = {
      title: 'Referenda',
      containsChildren: false,
      hasDefaultToggle: showReferenda
        ? toggleTreeState['children']['Referenda']['toggledState']
        : false,
      onclick: (e, toggle: boolean) => {
        e.preventDefault();
        navigateToSubpage('/referenda');
        setGovernanceToggleTree('children.Referenda.toggledState', toggle);
      },
      isVisible: showReferenda,
      isUpdated: true,
      isActive: onReferendaPage(m.route.get()),
      displayData: null,
    };

    const tipsData: SectionGroupAttrs = {
      title: 'Tips',
      containsChildren: false,
      hasDefaultToggle: showTips
        ? toggleTreeState['children']['Tips']['toggledState']
        : false,
      onclick: (e, toggle: boolean) => {
        e.preventDefault();
        navigateToSubpage('/tips');
        setGovernanceToggleTree('children.Tips.toggledState', toggle);
      },
      isVisible: showTips,
      isUpdated: true,
      isActive: onTipsPage(m.route.get()),
      displayData: null,
    };

    const councillorsData: SectionGroupAttrs = {
      title: 'Councillors',
      containsChildren: false,
      hasDefaultToggle: showCouncillors
        ? toggleTreeState['children']['Councillors']['toggledState']
        : false,
      onclick: (e, toggle: boolean) => {
        e.preventDefault();
        navigateToSubpage('/council');
        setGovernanceToggleTree('children.Councillors.toggledState', toggle);
      },
      isVisible: showCouncillors,
      isUpdated: true,
      isActive: onCouncilPage(m.route.get()),
      displayData: null,
    };

    const validatorsData: SectionGroupAttrs = {
      title: 'Validators',
      containsChildren: false,
      hasDefaultToggle: showValidators
        ? toggleTreeState['children']['Validators']['toggledState']
        : false,
      onclick: (e, toggle: boolean) => {
        e.preventDefault();
        navigateToSubpage('/validators');
        setGovernanceToggleTree('children.Validators.toggledState', toggle);
      },
      isVisible: showValidators,
      isUpdated: true,
      isActive: onValidatorsPage(m.route.get()),
      displayData: null,
    };

    // Delegate
    const delegateData: SectionGroupAttrs = {
      title: 'Delegate',
      containsChildren: false,
      hasDefaultToggle: showCompoundOptions
        ? toggleTreeState['children']['Delegate']['toggledState']
        : false,
      isVisible: showCompoundOptions,
      isUpdated: true,
      isActive: m.route.get() === `/${app.activeChainId()}/delegate`,
      onclick: (e, toggle: boolean) => {
        e.preventDefault();
        setGovernanceToggleTree('children.Delegate.toggledState', toggle);
        navigateToSubpage('/delegate');
      },
      displayData: null,
    };

    const governanceGroupData: SectionGroupAttrs[] = [
      membersData,
      snapshotData,
      delegateData,
      treasuryData,
      bountyData,
      referendaData,
      proposalsData,
      tipsData,
      councillorsData,
      validatorsData,
    ];

    const sidebarSectionData: SidebarSectionAttrs = {
      title: 'GOVERNANCE',
      hasDefaultToggle: toggleTreeState['toggledState'],
      onclick: (e, toggle: boolean) => {
        e.preventDefault();
        setGovernanceToggleTree('toggledState', toggle);
      },
      displayData: governanceGroupData,
      isActive: false,
      toggleDisabled: vnode.attrs.mobile,
    };

    return <SidebarSectionGroup {...sidebarSectionData} />;
  }