mirror of
https://github.com/ilyakooo0/urbit.git
synced 2024-09-22 07:59:22 +03:00
landscape: add "messages" workspace and logic
This commit is contained in:
parent
a48c372a0e
commit
f0033ab02f
@ -110,8 +110,12 @@ export default function index(contacts, associations, apps, currentGroup, groups
|
||||
landscape.push(obj);
|
||||
} else {
|
||||
const app = each.metadata.module || each['app-name'];
|
||||
const group = (groups[each.group]?.hidden)
|
||||
? '/home' : each.group;
|
||||
let group = each.group;
|
||||
if (groups[each.group]?.hidden && app === 'chat') {
|
||||
group = '/messages';
|
||||
} else if (groups[each.group]?.hidden) {
|
||||
group = '/home';
|
||||
}
|
||||
const obj = result(
|
||||
title,
|
||||
`/~landscape${group}/join/${app}${each.resource}`,
|
||||
|
@ -392,3 +392,16 @@ export const useHovering = (): useHoveringInterface => {
|
||||
};
|
||||
return { hovering, bind };
|
||||
};
|
||||
|
||||
const DM_REGEX = /ship\/~([a-z]|-)*\/dm--/;
|
||||
export function getItemTitle(association: Association) {
|
||||
if(DM_REGEX.test(association.resource)) {
|
||||
const [,,ship,name] = association.resource.split('/');
|
||||
if(ship.slice(1) === window.ship) {
|
||||
return cite(`~${name.slice(4)}`);
|
||||
}
|
||||
return cite(ship);
|
||||
|
||||
}
|
||||
return association.metadata.title || association.resource
|
||||
};
|
||||
|
@ -7,6 +7,8 @@ export function getTitleFromWorkspace(
|
||||
switch (workspace.type) {
|
||||
case "home":
|
||||
return "My Channels";
|
||||
case "messages":
|
||||
return "Messages";
|
||||
case "group":
|
||||
const association = associations.groups[workspace.group];
|
||||
return association?.metadata?.title || "";
|
||||
|
@ -9,4 +9,8 @@ interface HomeWorkspace {
|
||||
type: 'home'
|
||||
}
|
||||
|
||||
export type Workspace = HomeWorkspace | GroupWorkspace;
|
||||
interface Messages {
|
||||
type: 'messages'
|
||||
}
|
||||
|
||||
export type Workspace = HomeWorkspace | GroupWorkspace | Messages;
|
||||
|
@ -27,7 +27,7 @@ const StatusBar = (props) => {
|
||||
const invites = [].concat(...Object.values(props.invites).map(obj => Object.values(obj)));
|
||||
const metaKey = (window.navigator.platform.includes('Mac')) ? '⌘' : 'Ctrl+';
|
||||
const { toggleOmnibox, hideAvatars } =
|
||||
useLocalState(({ toggleOmnibox, hideAvatars }) =>
|
||||
useLocalState(({ toggleOmnibox, hideAvatars }) =>
|
||||
({ toggleOmnibox, hideAvatars })
|
||||
);
|
||||
|
||||
@ -91,6 +91,9 @@ const StatusBar = (props) => {
|
||||
>
|
||||
<Text color='#000000'>Submit <Text color='#000000' display={['none', 'inline']}>an</Text> issue</Text>
|
||||
</StatusBarItem>
|
||||
<StatusBarItem mr={2} onClick={() => props.history.push('/~landscape/messages')}>
|
||||
<Icon icon="Users"/>
|
||||
</StatusBarItem>
|
||||
<Dropdown
|
||||
dropWidth="150px"
|
||||
width="auto"
|
||||
|
@ -78,7 +78,9 @@ export function GroupSwitcher(props: {
|
||||
}) {
|
||||
const { associations, workspace, isAdmin } = props;
|
||||
const title = getTitleFromWorkspace(associations, workspace);
|
||||
const metadata = workspace.type === 'home' ? undefined : associations.groups[workspace.group].metadata;
|
||||
const metadata = (workspace.type === 'home' || workspace.type === 'messages')
|
||||
? undefined
|
||||
: associations.groups[workspace.group].metadata;
|
||||
const navTo = (to: string) => `${props.baseUrl}${to}`;
|
||||
return (
|
||||
<Row width="100%" alignItems="center" height='48px' backgroundColor="white" zIndex="2" position="sticky" top="0px" pl='3' borderBottom='1px solid' borderColor='washedGray'>
|
||||
|
@ -47,10 +47,6 @@ export function InvitePopover(props: InvitePopoverProps) {
|
||||
useOutsideClick(innerRef, onOutsideClick);
|
||||
|
||||
const onSubmit = async ({ ships, emails }: { ships: string[] }, actions) => {
|
||||
if(props.workspace.type === 'home') {
|
||||
history.push(`/~landscape/dm/${deSig(ships[0])}`);
|
||||
return;
|
||||
}
|
||||
// TODO: how to invite via email?
|
||||
try {
|
||||
const resource = resourceFromPath(association.group);
|
||||
@ -105,14 +101,13 @@ export function InvitePopover(props: InvitePopoverProps) {
|
||||
<Col gapY="3" pt={3} px={3}>
|
||||
<Box>
|
||||
<Text>Invite to </Text>
|
||||
<Text fontWeight="800">{title || "DM"}</Text>
|
||||
<Text fontWeight="800">{title}</Text>
|
||||
</Box>
|
||||
<ShipSearch
|
||||
groups={props.groups}
|
||||
contacts={props.contacts}
|
||||
id="ships"
|
||||
label=""
|
||||
maxLength={props.workspace.type === 'home' ? 1 : undefined}
|
||||
autoFocus
|
||||
/>
|
||||
<FormError message="Failed to invite" />
|
||||
|
@ -3,10 +3,7 @@ import {
|
||||
Box,
|
||||
ManagedTextInputField as Input,
|
||||
Col,
|
||||
ManagedRadioButtonField as Radio,
|
||||
Text,
|
||||
Icon,
|
||||
Row
|
||||
Text
|
||||
} from '@tlon/indigo-react';
|
||||
import { Formik, Form } from 'formik';
|
||||
import * as Yup from 'yup';
|
||||
@ -21,8 +18,8 @@ import { useWaitForProps } from '~/logic/lib/useWaitForProps';
|
||||
import { Groups } from '~/types/group-update';
|
||||
import { ShipSearch, shipSearchSchemaInGroup, shipSearchSchema } from '~/views/components/ShipSearch';
|
||||
import { Rolodex, Workspace } from '~/types';
|
||||
import {IconRadio} from '~/views/components/IconRadio';
|
||||
import {ChannelWriteFieldSchema, ChannelWritePerms} from './ChannelWritePerms';
|
||||
import { IconRadio } from '~/views/components/IconRadio';
|
||||
import { ChannelWriteFieldSchema, ChannelWritePerms } from './ChannelWritePerms';
|
||||
|
||||
type FormSchema = {
|
||||
name: string;
|
||||
@ -32,7 +29,7 @@ type FormSchema = {
|
||||
} & ChannelWriteFieldSchema;
|
||||
|
||||
const formSchema = (members?: string[]) => Yup.object({
|
||||
name: Yup.string().required('Channel must have a name'),
|
||||
name: Yup.string(),
|
||||
description: Yup.string(),
|
||||
ships: Yup.array(Yup.string()),
|
||||
moduleType: Yup.string().required('Must choose channel type'),
|
||||
@ -55,11 +52,16 @@ export function NewChannel(props: NewChannelProps & RouteComponentProps) {
|
||||
const waiter = useWaitForProps(props, 5000);
|
||||
|
||||
const onSubmit = async (values: FormSchema, actions) => {
|
||||
const name = (values.name) ? values.name : values.moduleType;
|
||||
const resId: string = stringToSymbol(values.name)
|
||||
+ ((workspace?.type !== 'home') ? `-${Math.floor(Math.random() * 10000)}`
|
||||
+ ((workspace?.type !== 'messages') ? `-${Math.floor(Math.random() * 10000)}`
|
||||
: '');
|
||||
try {
|
||||
let { name, description, moduleType, ships, writers } = values;
|
||||
let { description, moduleType, ships, writers } = values;
|
||||
ships = ships.filter(e => e !== "");
|
||||
if (workspace?.type === 'messages' && ships.length === 1) {
|
||||
return history.push(`/~landscape/dm/${deSig(ships[0])}`);
|
||||
}
|
||||
if (group) {
|
||||
await api.graph.createManagedGraph(
|
||||
resId,
|
||||
@ -83,7 +85,6 @@ export function NewChannel(props: NewChannelProps & RouteComponentProps) {
|
||||
writers.push(us);
|
||||
await api.groups.addTag(resource, tag, writers);
|
||||
}
|
||||
|
||||
} else {
|
||||
await api.graph.createUnmanagedGraph(
|
||||
resId,
|
||||
@ -115,13 +116,13 @@ export function NewChannel(props: NewChannelProps & RouteComponentProps) {
|
||||
<Box pb='3' display={['block', 'none']} onClick={() => history.push(props.baseUrl)}>
|
||||
<Text fontSize='0' bold>{'<- Back'}</Text>
|
||||
</Box>
|
||||
<Box fontSize="1" fontWeight="bold" mb={4} color="black">
|
||||
New Channel
|
||||
<Box color="black">
|
||||
<Text fontSize={2} bold>{workspace?.type === 'messages' ? 'Direct Message' : 'New Channel'}</Text>
|
||||
</Box>
|
||||
<Formik
|
||||
validationSchema={formSchema(members)}
|
||||
initialValues={{
|
||||
moduleType: 'chat',
|
||||
moduleType: (workspace?.type === 'home') ? 'publish' : 'chat',
|
||||
name: '',
|
||||
description: '',
|
||||
group: '',
|
||||
@ -136,37 +137,54 @@ export function NewChannel(props: NewChannelProps & RouteComponentProps) {
|
||||
maxWidth="348px"
|
||||
gapY="4"
|
||||
>
|
||||
<Col gapY="2">
|
||||
<Col pt={4} gapY="2" display={(workspace?.type === "messages") ? 'none' : 'flex'}>
|
||||
<Box fontSize="1" color="black" mb={2}>Channel Type</Box>
|
||||
<IconRadio icon="Chat" label="Chat" id="chat" name="moduleType" />
|
||||
<IconRadio icon="Publish" label="Notebook" id="publish" name="moduleType" />
|
||||
<IconRadio icon="Links" label="Collection" id="link" name="moduleType" />
|
||||
<IconRadio
|
||||
display={!(workspace?.type === 'home') ? 'flex' : 'none'}
|
||||
icon="Chat"
|
||||
label="Chat"
|
||||
id="chat"
|
||||
name="moduleType"
|
||||
/>
|
||||
<IconRadio
|
||||
icon="Publish"
|
||||
label="Notebook"
|
||||
id="publish"
|
||||
name="moduleType"
|
||||
/>
|
||||
<IconRadio
|
||||
icon="Links"
|
||||
label="Collection"
|
||||
id="link"
|
||||
name="moduleType"
|
||||
/>
|
||||
</Col>
|
||||
<Input
|
||||
display={workspace?.type === 'messages' ? 'none' : 'flex'}
|
||||
id="name"
|
||||
label="Name"
|
||||
caption="Provide a name for your channel"
|
||||
placeholder="eg. My Channel"
|
||||
/>
|
||||
<Input
|
||||
display={workspace?.type === 'messages' ? 'none' : 'flex'}
|
||||
id="description"
|
||||
label="Description"
|
||||
caption="What's your channel about?"
|
||||
placeholder="Channel description"
|
||||
/>
|
||||
{(workspace?.type === 'home') ? (
|
||||
{(workspace?.type === 'home' || workspace?.type === 'messages') ? (
|
||||
<ShipSearch
|
||||
groups={props.groups}
|
||||
contacts={props.contacts}
|
||||
id="ships"
|
||||
label="Invitees"
|
||||
/>) : (
|
||||
/>) : (
|
||||
<ChannelWritePerms
|
||||
groups={props.groups}
|
||||
contacts={props.contacts}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Box justifySelf="start">
|
||||
<AsyncButton
|
||||
primary
|
||||
@ -174,7 +192,7 @@ export function NewChannel(props: NewChannelProps & RouteComponentProps) {
|
||||
type="submit"
|
||||
border
|
||||
>
|
||||
Create Channel
|
||||
Create
|
||||
</AsyncButton>
|
||||
</Box>
|
||||
<FormError message="Channel creation failed" />
|
||||
|
@ -28,14 +28,14 @@ type ResourceProps = StoreState & {
|
||||
} & RouteComponentProps;
|
||||
|
||||
export function Resource(props: ResourceProps) {
|
||||
const { association, api, notificationsGraphConfig, groups } = props;
|
||||
const { association, api, notificationsGraphConfig, groups, contacts } = props;
|
||||
const app = association.metadata.module || association["app-name"];
|
||||
const rid = association.resource;
|
||||
const selectedGroup = association.group;
|
||||
const relativePath = (p: string) =>
|
||||
|
||||
`${props.baseUrl}/resource/${app}${rid}${p}`;
|
||||
const skelProps = { api, association, groups };
|
||||
const skelProps = { api, association, groups, contacts };
|
||||
let title = props.association.metadata.title;
|
||||
if ('workspace' in props) {
|
||||
if ('group' in props.workspace && props.workspace.group in props.associations.groups) {
|
||||
@ -65,12 +65,12 @@ export function Resource(props: ResourceProps) {
|
||||
render={(routeProps) => {
|
||||
return (
|
||||
<ChannelPopoverRoutes
|
||||
association={association}
|
||||
association={association}
|
||||
group={props.groups?.[selectedGroup]}
|
||||
groups={props.groups}
|
||||
contacts={props.contacts}
|
||||
api={props.api}
|
||||
baseUrl={relativePath("")}
|
||||
baseUrl={relativePath("")}
|
||||
notificationsGraphConfig={notificationsGraphConfig}
|
||||
/>
|
||||
);
|
||||
|
@ -15,6 +15,8 @@ import { ChannelSettings } from "./ChannelSettings";
|
||||
import { ChannelMenu } from "./ChannelMenu";
|
||||
import { NotificationGraphConfig, Groups } from "~/types";
|
||||
import {isWriter} from "~/logic/lib/group";
|
||||
import urbitOb from 'urbit-ob';
|
||||
import { getItemTitle } from '~/logic/lib/util';
|
||||
|
||||
const TruncatedBox = styled(Box)`
|
||||
white-space: pre;
|
||||
@ -24,6 +26,7 @@ const TruncatedBox = styled(Box)`
|
||||
|
||||
type ResourceSkeletonProps = {
|
||||
groups: Groups;
|
||||
contacts: any;
|
||||
association: Association;
|
||||
api: GlobalApi;
|
||||
baseUrl: string;
|
||||
@ -35,16 +38,30 @@ type ResourceSkeletonProps = {
|
||||
export function ResourceSkeleton(props: ResourceSkeletonProps) {
|
||||
const { association, api, baseUrl, children, atRoot, groups } = props;
|
||||
const app = association?.metadata?.module || association["app-name"];
|
||||
const rid = association.resource;
|
||||
const rid = association.resource;
|
||||
const group = groups[association.group];
|
||||
const workspace =
|
||||
group?.hidden ? "/home" : association.group;
|
||||
let workspace = association.group;
|
||||
|
||||
const title = props.title || association?.metadata?.title;
|
||||
if (group?.hidden && app === "chat") {
|
||||
workspace = "/messages";
|
||||
} else if (group?.hidden) {
|
||||
workspace = "/home";
|
||||
}
|
||||
|
||||
let title = (workspace === "/messages")
|
||||
? getItemTitle(association)
|
||||
: association?.metadata?.title;
|
||||
|
||||
let recipient = false;
|
||||
|
||||
if (urbitOb.isValidPatp(title)) {
|
||||
recipient = title;
|
||||
title = (props.contacts?.[title]?.nickname) ? props.contacts[title].nickname : title;
|
||||
}
|
||||
|
||||
const [, , ship, resource] = rid.split("/");
|
||||
|
||||
const resourcePath = (p: string) => baseUrl + `/resource/${app}/ship/${ship}/${resource}` + p;
|
||||
const resourcePath = (p: string) => baseUrl + p;
|
||||
|
||||
const isOwn = `~${window.ship}` === ship;
|
||||
let canWrite = (app === 'publish') ? true : false;
|
||||
@ -78,7 +95,16 @@ export function ResourceSkeleton(props: ResourceSkeletonProps) {
|
||||
<Link to={`/~landscape${workspace}`}> {"<- Back"}</Link>
|
||||
</Box>
|
||||
<Box px={1} mr={2} minWidth={0} display="flex">
|
||||
<Text fontSize='2' fontWeight='700' display="inline-block" verticalAlign="middle" textOverflow="ellipsis" overflow="hidden" whiteSpace="pre" minWidth={0}>
|
||||
<Text
|
||||
mono={urbitOb.isValidPatp(title)}
|
||||
fontSize='2'
|
||||
fontWeight='700'
|
||||
display="inline-block"
|
||||
verticalAlign="middle"
|
||||
textOverflow="ellipsis"
|
||||
overflow="hidden"
|
||||
whiteSpace="pre"
|
||||
minWidth={0}>
|
||||
{title}
|
||||
</Text>
|
||||
</Box>
|
||||
@ -91,12 +117,13 @@ export function ResourceSkeleton(props: ResourceSkeletonProps) {
|
||||
color="gray"
|
||||
>
|
||||
<RichText
|
||||
display={(workspace === '/messages' && (urbitOb.isValidPatp(title))) ? "none" : "inline-block"}
|
||||
mono={(workspace === '/messages' && !(urbitOb.isValidPatp(title)))}
|
||||
color="gray"
|
||||
mb="0"
|
||||
display="inline-block"
|
||||
disableRemoteContent
|
||||
>
|
||||
{association?.metadata?.description}
|
||||
{(workspace === "/messages") ? recipient : association?.metadata?.description}
|
||||
</RichText>
|
||||
</TruncatedBox>
|
||||
<Box flexGrow={1} />
|
||||
|
@ -93,6 +93,8 @@ export function Sidebar(props: SidebarProps) {
|
||||
handleSubmit={setConfig}
|
||||
selected={selected || ''}
|
||||
workspace={workspace}
|
||||
api={props.api}
|
||||
history={props.history}
|
||||
/>
|
||||
<SidebarList
|
||||
config={config}
|
||||
@ -102,6 +104,8 @@ export function Sidebar(props: SidebarProps) {
|
||||
groups={props.groups}
|
||||
apps={props.apps}
|
||||
baseUrl={props.baseUrl}
|
||||
workspace={workspace}
|
||||
contacts={props.contacts}
|
||||
/>
|
||||
</ScrollbarLessCol>
|
||||
);
|
||||
|
@ -1,13 +1,14 @@
|
||||
import React from "react";
|
||||
import _ from 'lodash';
|
||||
|
||||
import { Icon, Row, Box, Text } from "@tlon/indigo-react";
|
||||
import { Icon, Row, Box, Text, BaseImage } from "@tlon/indigo-react";
|
||||
|
||||
import { SidebarAppConfigs, SidebarItemStatus } from "./Sidebar";
|
||||
import { HoverBoxLink } from "~/views/components/HoverBox";
|
||||
import { Groups, Association } from "~/types";
|
||||
|
||||
import { cite, getModuleIcon } from "~/logic/lib/util";
|
||||
import { Sigil } from '~/logic/lib/sigil';
|
||||
import urbitOb from 'urbit-ob';
|
||||
import { getModuleIcon, getItemTitle, uxToHex } from "~/logic/lib/util";
|
||||
|
||||
function SidebarItemIndicator(props: { status?: SidebarItemStatus }) {
|
||||
switch (props.status) {
|
||||
@ -24,31 +25,18 @@ function SidebarItemIndicator(props: { status?: SidebarItemStatus }) {
|
||||
}
|
||||
}
|
||||
|
||||
;
|
||||
|
||||
const DM_REGEX = /ship\/~([a-z]|-)*\/dm--/;
|
||||
function getItemTitle(association: Association) {
|
||||
if(DM_REGEX.test(association.resource)) {
|
||||
const [,,ship,name] = association.resource.split('/');
|
||||
if(ship.slice(1) === window.ship) {
|
||||
return cite(`~${name.slice(4)}`);
|
||||
}
|
||||
return cite(ship);
|
||||
|
||||
}
|
||||
return association.metadata.title || association.resource
|
||||
}
|
||||
|
||||
export function SidebarItem(props: {
|
||||
hideUnjoined: boolean;
|
||||
association: Association;
|
||||
contacts: any;
|
||||
groups: Groups;
|
||||
path: string;
|
||||
selected: boolean;
|
||||
apps: SidebarAppConfigs;
|
||||
workspace: Workspace;
|
||||
}) {
|
||||
const { association, path, selected, apps, groups } = props;
|
||||
const title = getItemTitle(association);
|
||||
let title = getItemTitle(association);
|
||||
const appName = association?.["app-name"];
|
||||
const mod = association?.metadata?.module || appName;
|
||||
const rid = association?.resource
|
||||
@ -58,12 +46,19 @@ export function SidebarItem(props: {
|
||||
if (!app) {
|
||||
return null;
|
||||
}
|
||||
const DM = (isUnmanaged && props.workspace?.type === "messages");
|
||||
const itemStatus = app.getStatus(path);
|
||||
const hasUnread = itemStatus === "unread" || itemStatus === "mention";
|
||||
|
||||
const isSynced = itemStatus !== "unsubscribed";
|
||||
|
||||
const baseUrl = isUnmanaged ? `/~landscape/home` : `/~landscape${groupPath}`;
|
||||
let baseUrl = `/~landscape${groupPath}`;
|
||||
|
||||
if (DM) {
|
||||
baseUrl = '/~landscape/messages';
|
||||
} else if (isUnmanaged) {
|
||||
baseUrl = '/~landscape/home';
|
||||
}
|
||||
|
||||
const to = isSynced
|
||||
? `${baseUrl}/resource/${mod}${rid}`
|
||||
@ -75,6 +70,21 @@ export function SidebarItem(props: {
|
||||
return null;
|
||||
}
|
||||
|
||||
let img = null;
|
||||
|
||||
if (urbitOb.isValidPatp(title)) {
|
||||
if (props.contacts?.[title] && props.contacts[title].avatar) {
|
||||
img = <BaseImage src={props.contacts[title].avatar} width='16px' height='16px' borderRadius={2}/>;
|
||||
} else {
|
||||
img = <Sigil ship={title} color={`#${uxToHex(props.contacts?.[title]?.color || '0x0')}`} icon padded size={16}/>
|
||||
}
|
||||
if (props.contacts?.[title] && props.contacts[title].nickname) {
|
||||
title = props.contacts[title].nickname;
|
||||
}
|
||||
} else {
|
||||
img = <Box flexShrink={0} height={16} width={16} borderRadius={2} backgroundColor={`#${uxToHex(props?.association?.metadata?.color)}` || "#000000"}/>
|
||||
}
|
||||
|
||||
return (
|
||||
<HoverBoxLink
|
||||
to={to}
|
||||
@ -90,11 +100,14 @@ export function SidebarItem(props: {
|
||||
selected={selected}
|
||||
>
|
||||
<Row width='100%' alignItems="center" flex='1 auto' minWidth='0'>
|
||||
<Icon
|
||||
display="block"
|
||||
color={color}
|
||||
icon={getModuleIcon(mod) as any}
|
||||
/>
|
||||
{DM ? img : (
|
||||
<Icon
|
||||
display="block"
|
||||
color={color}
|
||||
icon={getModuleIcon(mod) as any}
|
||||
/>
|
||||
)
|
||||
}
|
||||
<Box width='100%' flexShrink={2} ml={2} display='flex' overflow='hidden'>
|
||||
<Text
|
||||
lineHeight="tall"
|
||||
@ -102,6 +115,7 @@ export function SidebarItem(props: {
|
||||
flex='1'
|
||||
overflow='hidden'
|
||||
width='100%'
|
||||
mono={urbitOb.isValidPatp(title)}
|
||||
fontWeight={hasUnread ? "bold" : "regular"}
|
||||
color={selected || isSynced ? "black" : "lightGray"}
|
||||
style={{ textOverflow: 'ellipsis', whiteSpace: 'pre'}}
|
||||
|
@ -37,22 +37,28 @@ function sidebarSort(
|
||||
|
||||
export function SidebarList(props: {
|
||||
apps: SidebarAppConfigs;
|
||||
contacts: any;
|
||||
config: SidebarListConfig;
|
||||
associations: Associations;
|
||||
groups: Groups;
|
||||
baseUrl: string;
|
||||
group?: string;
|
||||
selected?: string;
|
||||
workspace: Workspace;
|
||||
}) {
|
||||
const { selected, group, config } = props;
|
||||
const { selected, group, config, workspace } = props;
|
||||
const associations = { ...props.associations.graph };
|
||||
|
||||
const ordered = Object.keys(associations)
|
||||
.filter((a) => {
|
||||
const assoc = associations[a];
|
||||
return group
|
||||
? assoc.group === group
|
||||
: !(assoc.group in props.associations.groups);
|
||||
if (workspace?.type === 'messages') {
|
||||
return (!(assoc.group in props.associations.groups) && assoc.metadata.module === "chat");
|
||||
} else {
|
||||
return group
|
||||
? assoc.group === group
|
||||
: (!(assoc.group in props.associations.groups) && assoc.metadata.module !== "chat");
|
||||
}
|
||||
})
|
||||
.sort(sidebarSort(associations, props.apps)[config.sortBy]);
|
||||
|
||||
@ -69,6 +75,8 @@ export function SidebarList(props: {
|
||||
apps={props.apps}
|
||||
hideUnjoined={config.hideUnjoined}
|
||||
groups={props.groups}
|
||||
contacts={props.contacts}
|
||||
workspace={workspace}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
@ -17,8 +17,11 @@ import { Link, useHistory } from 'react-router-dom';
|
||||
import { getGroupFromWorkspace } from "~/logic/lib/workspace";
|
||||
import { roleForShip } from "~/logic/lib/group";
|
||||
import {Groups, Rolodex, Associations} from "~/types";
|
||||
import { NewChannel } from "~/views/landscape/components/NewChannel";
|
||||
import GlobalApi from "~/logic/api/global";
|
||||
|
||||
export function SidebarListHeader(props: {
|
||||
api: GlobalApi;
|
||||
initialValues: SidebarListConfig;
|
||||
associations: Associations;
|
||||
groups: Groups;
|
||||
@ -40,10 +43,12 @@ export function SidebarListHeader(props: {
|
||||
|
||||
const groupPath = getGroupFromWorkspace(props.workspace);
|
||||
const role = props.groups?.[groupPath] ? roleForShip(props.groups[groupPath], window.ship) : undefined;
|
||||
const memberMetadata =
|
||||
const memberMetadata =
|
||||
groupPath ? props.associations.contacts?.[groupPath].metadata.vip === 'member-metadata' : false;
|
||||
|
||||
const isAdmin = memberMetadata || (role === "admin") || (props.workspace?.type === 'home');
|
||||
const isAdmin = memberMetadata || (role === "admin") || (props.workspace?.type === 'home') || (props.workspace?.type === "messages");
|
||||
|
||||
const noun = (props.workspace?.type === "messages") ? "Messages" : "Channels";
|
||||
|
||||
return (
|
||||
<Row
|
||||
@ -56,7 +61,7 @@ export function SidebarListHeader(props: {
|
||||
>
|
||||
<Box flexShrink='0'>
|
||||
<Text>
|
||||
{props.initialValues.hideUnjoined ? "Joined Channels" : "All Channels"}
|
||||
{props.initialValues.hideUnjoined ? `Joined ${noun}` : `All ${noun}`}
|
||||
</Text>
|
||||
</Box>
|
||||
<Box
|
||||
@ -64,26 +69,44 @@ export function SidebarListHeader(props: {
|
||||
display='flex'
|
||||
alignItems='center'
|
||||
>
|
||||
<Link
|
||||
style={{
|
||||
{props.workspace?.type === "messages"
|
||||
? (
|
||||
<Dropdown
|
||||
flexShrink={0}
|
||||
dropWidth="300px"
|
||||
width="auto"
|
||||
alignY="top"
|
||||
alignX={["right", "left"]}
|
||||
options={
|
||||
<Col
|
||||
background="white"
|
||||
border={1}
|
||||
borderColor="washedGray"
|
||||
>
|
||||
<NewChannel
|
||||
api={props.api}
|
||||
history={props.history}
|
||||
associations={props.associations}
|
||||
contacts={props.contacts}
|
||||
groups={props.groups}
|
||||
workspace={props.workspace}
|
||||
/>
|
||||
</Col>
|
||||
}
|
||||
>
|
||||
<Icon icon="Plus" color="gray" pr='12px'/>
|
||||
</Dropdown>
|
||||
)
|
||||
: (
|
||||
<Link style={{
|
||||
display: isAdmin ? "inline-block" : "none" }}
|
||||
to={
|
||||
!!groupPath ? `/~landscape${groupPath}/new` : `/~landscape/home/new`}>
|
||||
to={!!groupPath
|
||||
? `/~landscape${groupPath}/new`
|
||||
: `/~landscape/${props.workspace?.type}/new`}>
|
||||
<Icon icon="Plus" color="gray" pr='12px'/>
|
||||
</Link>
|
||||
<Link to={`${props.baseUrl}/invites`}
|
||||
style={{ display: (props.workspace?.type === 'home') ? 'inline-block' : 'none'}}>
|
||||
<Text
|
||||
display='inline-block'
|
||||
py='1px'
|
||||
px='3px'
|
||||
mr='12px'
|
||||
backgroundColor='washedBlue'
|
||||
color='blue'
|
||||
borderRadius='1'>
|
||||
+ DM
|
||||
</Text>
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
<Dropdown
|
||||
flexShrink='0'
|
||||
width="auto"
|
||||
|
@ -63,6 +63,7 @@ export function Skeleton(props: SkeletonProps) {
|
||||
groups={props.groups}
|
||||
mobileHide={props.mobileHide}
|
||||
workspace={props.workspace}
|
||||
history={props.history}
|
||||
/>
|
||||
{props.children}
|
||||
</Body>
|
||||
|
@ -27,7 +27,7 @@ type LandscapeProps = StoreState & {
|
||||
export function DMRedirect(props: LandscapeProps & RouteComponentProps & { ship: string; }) {
|
||||
const { ship, api, history, graphKeys } = props;
|
||||
const goToGraph = useCallback((graph: string) => {
|
||||
history.push(`/~landscape/home/resource/chat/ship/~${graph}`);
|
||||
history.push(`/~landscape/messages/resource/chat/ship/~${graph}`);
|
||||
}, [history]);
|
||||
|
||||
useEffect(() => {
|
||||
|
Loading…
Reference in New Issue
Block a user