Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add members space page #971

Open
wants to merge 24 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
f910024
feat: add members space page
bartosz-io Nov 5, 2024
0c3e3f9
Merge branch 'master' into feat-960-add-members-space-page
bartosz-io Nov 5, 2024
5cc5563
Merge branch 'master' into feat-960-add-members-space-page
bartosz-io Nov 5, 2024
d8738d3
Show Members even if only controller present
bartosz-io Nov 7, 2024
707bc7d
Display names, remove label, load members at once
bartosz-io Nov 7, 2024
58a8eba
Merge remote-tracking branch 'origin/master' into feat-960-add-member…
bartosz-io Nov 7, 2024
0060899
Merge remote-tracking branch 'origin/feat-960-add-members-space-page'…
bartosz-io Nov 7, 2024
d5ca893
Fix div
bartosz-io Nov 7, 2024
b65c7f4
Merge branch 'master' into feat-960-add-members-space-page
bartosz-io Nov 7, 2024
cf5db05
Fix typo in Members.vue
bartosz-io Nov 7, 2024
c0d131f
Update apps/ui/src/networks/offchain/api/queries.ts
bartosz-io Dec 5, 2024
bb3c9ff
Update apps/ui/src/components/App/Nav.vue
bartosz-io Dec 5, 2024
7a28a5c
Avoid calling method with fallback value
bartosz-io Dec 5, 2024
8b38089
Merge remote-tracking branch 'origin/feat-960-add-members-space-page'…
bartosz-io Dec 5, 2024
6a60da0
Merge remote-tracking branch 'upstream/master' into feat-960-add-memb…
bartosz-io Dec 5, 2024
96cfe73
Improve navigation visibility rules
bartosz-io Dec 5, 2024
6bb8aae
Merge branch 'master' into feat-960-add-members-space-page
bartosz-io Dec 6, 2024
cd65e71
Merge branch 'master' into feat-960-add-members-space-page
bartosz-io Dec 17, 2024
3daf35c
Fix query param name
bartosz-io Dec 17, 2024
0cee0b7
Fix style warning
bartosz-io Dec 17, 2024
31fb757
Fix var name
bartosz-io Jan 2, 2025
060e418
Change the number of statements fetched
bartosz-io Jan 2, 2025
de47315
Merge branch 'master' into feat-960-add-members-space-page
bartosz-io Jan 2, 2025
90fef44
chore: add whitespace
Sekhmet Jan 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 34 additions & 7 deletions apps/ui/src/components/App/Nav.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@
import { FunctionalComponent } from 'vue';
import { SPACES_DISCUSSIONS } from '@/helpers/discourse';
import { compareAddresses } from '@/helpers/utils';
import { getNetwork } from '@/networks';
import { getNetwork, offchainNetworks } from '@/networks';
import IHAnnotation from '~icons/heroicons-outline/annotation';
import IHBell from '~icons/heroicons-outline/bell';
import IHCash from '~icons/heroicons-outline/cash';
import IHCog from '~icons/heroicons-outline/cog';
import IHGlobeAlt from '~icons/heroicons-outline/globe-alt';
import IHGlobe from '~icons/heroicons-outline/globe-americas';
import IHHome from '~icons/heroicons-outline/home';
import IHIdentification from '~icons/heroicons-outline/identification';
import IHLightningBolt from '~icons/heroicons-outline/lightning-bolt';
import IHNewspaper from '~icons/heroicons-outline/newspaper';
import IHStop from '~icons/heroicons-outline/stop';
Expand Down Expand Up @@ -42,15 +43,17 @@ const space = computed(() =>
: null
);

const isController = computedAsync(async () => {
if (!networkId.value || !space.value) return false;

const { account } = web3.value;
const controller = computedAsync(async () => {
if (!networkId.value || !space.value) return null;

const network = getNetwork(networkId.value);
const controller = await network.helpers.getSpaceController(space.value);
return network.helpers.getSpaceController(space.value);
});

return compareAddresses(controller, account);
const isController = computed(() => {
const { account } = web3.value;

return controller.value && compareAddresses(controller.value, account);
});

const canSeeSettings = computed(() => {
Expand All @@ -63,6 +66,22 @@ const canSeeSettings = computed(() => {

return admins.includes(web3.value.account.toLowerCase());
}
return false;
});

const canSeeMembers = computed(() => {
const data = space.value?.additionalRawData;

if (!networkId.value || !offchainNetworks.includes(networkId.value)) {
return false;
}

return (
controller.value ||
(data?.admins?.length ?? 0) > 0 ||
(data?.moderators?.length ?? 0) > 0 ||
(data?.members?.length ?? 0) > 0
);
});

const navigationConfig = computed<
Expand All @@ -81,6 +100,14 @@ const navigationConfig = computed<
name: 'Leaderboard',
icon: IHUserGroup
},
...(canSeeMembers.value
? {
members: {
name: 'Members',
icon: IHIdentification
}
}
: undefined),
...(space.value?.delegations && space.value.delegations.length > 0
? {
delegates: {
Expand Down
24 changes: 24 additions & 0 deletions apps/ui/src/networks/offchain/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import {
RANKING_QUERY,
SPACE_QUERY,
SPACES_QUERY,
STATEMENTS_AND_USERS_QUERY,
STATEMENTS_QUERY,
STRATEGIES_QUERY,
STRATEGY_QUERY,
Expand Down Expand Up @@ -791,6 +792,29 @@ export function createApi(

return statements;
},
loadStatementsAndUsers: async (
networkId: NetworkID,
spaceId: string,
userIds: string[]
): Promise<{ statements: Statement[]; users: User[] }> => {
const { data } = await apollo.query({
query: STATEMENTS_AND_USERS_QUERY,
variables: {
statementsFirst: 100,
statementsWhere: {
delegate_in: userIds,
network: networkId,
space: spaceId
},
userIds
}
});

return {
statements: data.statements,
users: data.users
};
},
loadStrategies: async () => {
const { data } = await apollo.query({
query: STRATEGIES_QUERY
Expand Down
19 changes: 19 additions & 0 deletions apps/ui/src/networks/offchain/api/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,25 @@ export const STRATEGY_QUERY = gql`
${STRATEGY_FRAGMENT}
`;

export const STATEMENTS_AND_USERS_QUERY = gql`
query (
$statementsFirst: Int!
$statementsWhere: StatementsWhere
$userIds: [String!]
) {
statements(first: $statementsFirst, where: $statementsWhere) {
delegate
space
network
statement
}
users(where: { id_in: $userIds }) {
id
about
}
}
`;

export const NETWORKS_USAGE_QUERY = gql`
query Networks {
networks {
Expand Down
5 changes: 5 additions & 0 deletions apps/ui/src/networks/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,11 @@ export type NetworkApi = {
spaceId: string,
userIds: string[]
): Promise<Statement[]>;
loadStatementsAndUsers(
networkId: NetworkID,
spaceId: string,
userIds: string[]
): Promise<{ statements: Statement[]; users: User[] }>;
loadStrategies(): Promise<StrategyTemplate[]>;
loadStrategy(address: string): Promise<StrategyTemplate | null>;
getNetworksUsage(): Promise<Record<ChainId, number | undefined>>;
Expand Down
6 changes: 6 additions & 0 deletions apps/ui/src/routes/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import SpaceDelegates from '@/views/Space/Delegates.vue';
import SpaceDiscussions from '@/views/Space/Discussions.vue';
import SpaceEditor from '@/views/Space/Editor.vue';
import SpaceLeaderboard from '@/views/Space/Leaderboard.vue';
import SpaceMembers from '@/views/Space/Members.vue';
import SpaceOverview from '@/views/Space/Overview.vue';
import SpaceProposals from '@/views/Space/Proposals.vue';
import SpaceSearch from '@/views/Space/Search.vue';
Expand Down Expand Up @@ -71,6 +72,11 @@ export const spaceChildrenRoutes: RouteRecordRaw[] = [
name: 'space-leaderboard',
component: SpaceLeaderboard
},
{
path: 'members',
name: 'space-members',
component: SpaceMembers
},
{
path: 'profile/:user',
name: 'space-user',
Expand Down
127 changes: 127 additions & 0 deletions apps/ui/src/views/Space/Members.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
<script setup lang="ts">
import removeMarkdown from 'remove-markdown';
import { getNames } from '@/helpers/stamp';
import { shorten } from '@/helpers/utils';
import { getNetwork } from '@/networks';
import { Space } from '@/types';

const props = defineProps<{ space: Space }>();

const { addNotification } = useUiStore();
const { setTitle } = useTitle();

const loaded = ref(false);
const roles = ref<{ data: string[]; label: string }[]>([]);
const names = ref<Record<string, string>>({});
const statements = ref<Record<string, string>>({});
const abouts = ref<Record<string, string>>({});
const network = computed(() => getNetwork(props.space.network));

const admins = props.space.additionalRawData?.admins || [];
const moderators = props.space.additionalRawData?.moderators || [];
const authors = props.space.additionalRawData?.members || [];

async function loadMembersData() {
try {
const controller = await network.value.helpers
.getSpaceController(props.space)
.then(c => c.toLowerCase());

const allUsers = [controller, ...admins, ...moderators, ...authors].map(u =>
u.toLowerCase()
);

names.value = await getNames(allUsers);

const { statements: userStatements, users } =
await network.value.api.loadStatementsAndUsers(
props.space.network,
props.space.id,
allUsers
);

statements.value = userStatements.reduce(
(acc, statement) => {
acc[statement.delegate.toLowerCase()] = statement.statement;
return acc;
},
{} as Record<string, string>
);

abouts.value = users.reduce(
(acc, user) => {
acc[user.id.toLowerCase()] = user.about || '';
return acc;
},
{} as Record<string, string>
);

roles.value = [
{ data: [controller], label: 'Controller' },
{ data: admins, label: 'Admin(s)' },
{ data: moderators, label: 'Moderator(s)' },
{ data: authors, label: 'Authors(s)' }
] as const;

loaded.value = true;
} catch (e) {
addNotification('error', 'Failed to load members data.');
loaded.value = true;
}
}
watchEffect(() => setTitle(`Members - ${props.space.name}`));
Sekhmet marked this conversation as resolved.
Show resolved Hide resolved

onMounted(loadMembersData);
</script>

<template>
<div>
<div v-if="!loaded" class="px-4 py-4 block">
<UiLoading class="block" />
</div>
<template v-for="role in roles" v-else :key="role.label">
<UiLabel v-if="role.data?.length" :label="role.label" />
<div class="text-left table-fixed w-full">
<div
v-for="(user, i) in role.data"
:key="`${role.label}-${i}`"
class="border-b flex space-x-1"
>
<div
class="flex items-center pl-4 py-3 gap-x-3 leading-[22px] min-w-[220px] truncate"
>
<UiStamp :id="user" :size="32" />
<AppLink
:to="{
name: 'space-user-statement',
params: { space: `${space.network}:${space.id}`, user: user }
}"
class="overflow-hidden"
>
<h4
class="text-skin-link truncate"
v-text="names[user] || shorten(user)"
/>
<div
class="text-[17px] text-skin-text truncate"
v-text="shorten(user)"
/>
</AppLink>
</div>
<div
class="hidden sm:flex items-center grow text-[17px] px-4 overflow-hidden leading-[22px] text-skin-text"
>
<span
v-if="statements[user] || abouts[user]"
class="line-clamp-2 max-h-[44px]"
>
{{
shorten(removeMarkdown(statements[user] || abouts[user]), 250)
}}
</span>
</div>
</div>
</div>
</template>
</div>
</template>