Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
29 changes: 18 additions & 11 deletions src/components/InvitePeopleModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<p class="mt-2">Enter an email address or NDN name below</p>

<div class="field mt-2">
<input class="input" type="text" :placeholder="`name@example.com or /ndn/user-name`" v-model="inviteInput"
<input class="input" type="text" :placeholder="`name@example.com or /user-name`" v-model="inviteInput"
:disabled="!isOwner" @keydown.enter.prevent="addInvitees(inviteInput)" @paste="addInviteesOnPaste" autofocus />
</div>

Expand All @@ -39,7 +39,7 @@

<div class="Info">
<div class="header">
<span class="name">{{ item.name }}</span>
<span class="name">{{ displayProfileName(item.name) }}</span>
</div>

<div class="email" v-if="item.email">{{ item.email }}</div>
Expand Down Expand Up @@ -84,7 +84,7 @@

<div class="Info">
<div class="header">
<span class="name">{{ item.name }}</span>
<span class="name">{{ displayProfileName(item.name) }}</span>
</div>

<div class="email" v-if="item.email">{{ item.email }}</div>
Expand Down Expand Up @@ -131,7 +131,7 @@
<div class="title is-6 mb-4">Current Workspace Members</div>
This list currenly only shows members who have published messages in discussions.
<p v-if="members.length > 0" class="mt-4">
<code>{{ members.join('\n') }}</code>
<code>{{ displayMembers.join('\n') }}</code>
</p>

</ModalComponent>
Expand Down Expand Up @@ -171,6 +171,9 @@ const members = ref([] as string[]);
const invitees = ref([] as IProfile[]);
const pendingInvitees = ref([] as IProfile[]);
const pendingRequests = ref([] as IProfile[]);
const displayMembers = computed(() =>
members.value.map((member) => utils.stripNdnPrefixForDisplay(member)),
);

const allInvitees = computed(() => {
return [
Expand Down Expand Up @@ -224,7 +227,7 @@ async function copyInviteeList() {
if (profile.email) {
return `${profile.email}`;
} else {
return `${profile.name}`;
return utils.stripNdnPrefixForDisplay(profile.name);
}
}).toString()
)
Expand Down Expand Up @@ -280,7 +283,7 @@ function addInvitee(invitee: string) {

// Check if it is an NDN name
if (entry.startsWith('/')) {
new_profile = { name: entry };
new_profile = { name: utils.restoreNdnPrefixFromDisplay(entry) };
} else {
// Validate the email address
if (!utils.validateEmail(entry)) {
Expand All @@ -297,7 +300,7 @@ function addInvitee(invitee: string) {

// Check repetition
if (allInvitees.value.some((profile) => profile.name === new_profile.name)) {
Toast.error(`${new_profile.name} already in the invitation list`);
Toast.error(`${displayProfileName(new_profile.name)} already in the invitation list`);
return;
}

Expand All @@ -322,7 +325,7 @@ function addRequest(invitee: string) {

// Check if it is an NDN name
if (entry.startsWith('/')) {
new_profile = { name: entry };
new_profile = { name: utils.restoreNdnPrefixFromDisplay(entry) };
} else {
// Validate the email address
if (!utils.validateEmail(entry)) {
Expand Down Expand Up @@ -381,14 +384,14 @@ async function acceptRequest(invitee: IProfile) {
// Generate and publish invitation to sync
await wksp.value.invite.tryInvite(invitee);
} catch (err) {
Toast.error(`Failed to invite ${invitee.name}: ${err}`);
Toast.error(`Failed to invite ${displayProfileName(invitee.name)}: ${err}`);
return; // rare
}

invitees.value.push(invitee);

// Finish
Toast.success(`Invited ${invitee.name} to workspace!`);
Toast.success(`Invited ${displayProfileName(invitee.name)} to workspace!`);
}

function denyRequest(invitee: IProfile) {
Expand All @@ -412,7 +415,7 @@ async function send() {
// Generate and publish invitation to sync
await wksp.value.invite.tryInvite(invitee);
} catch (err) {
Toast.error(`Failed to invite ${invitee.name}: ${err}`);
Toast.error(`Failed to invite ${displayProfileName(invitee.name)}: ${err}`);
return; // rare
}
}
Expand All @@ -422,6 +425,10 @@ async function send() {
emit('close');
}

function displayProfileName(name: string): string {
return utils.stripNdnPrefixForDisplay(name);
}

</script>

<style scoped lang="scss">
Expand Down
10 changes: 6 additions & 4 deletions src/components/InviteWorkspaceModal.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<ModalComponent :show="show" @close="emit('close')">
<div class="title is-5 mb-4">
Invite <code>{{ name }}</code>
Invite <code>{{ displayName }}</code>
</div>

<div v-if="joinLink" class="my-2">
Expand All @@ -23,7 +23,7 @@
<template v-else v-for="ws in workspaces" :key="ws.name">
<div class="wksp p-2" @click="invite(ws)">
<p class="has-text-weight-bold">{{ ws.label }}</p>
<p>{{ ws.name }}</p>
<p>{{ utils.stripNdnPrefixForDisplay(ws.name) }}</p>
</div>
</template>
</div>
Expand All @@ -37,7 +37,7 @@
</template>

<script setup lang="ts">
import { ref, shallowRef, watch } from 'vue';
import { computed, ref, shallowRef, watch } from 'vue';
import { useRouter, useRoute } from 'vue-router';

import QRCode from 'qrcode';
Expand All @@ -46,6 +46,7 @@ import ModalComponent from '@/components/ModalComponent.vue';

import { Workspace } from '@/services/workspace';
import { Toast } from '@/utils/toast';
import * as utils from '@/utils';

import type { IWkspStats } from '@/services/types';

Expand All @@ -62,6 +63,7 @@ const router = useRouter();
const route = useRoute();

const name = ref(String());
const displayName = computed(() => utils.stripNdnPrefixForDisplay(name.value));
const joinLink = ref(String());
const joinLinkQr = ref(String());
const workspaces = shallowRef([] as IWkspStats[]);
Expand All @@ -75,7 +77,7 @@ async function create() {
workspaces.value = [];
joinLink.value = String();

name.value = route.query.invite as string;
name.value = utils.restoreNdnPrefixFromDisplay((route.query.invite as string) || String());
if (!name.value) {
close();
return;
Expand Down
6 changes: 4 additions & 2 deletions src/components/QRIdentityModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
</p>

<p class="my-1">
<code class="select-all">{{ name }}</code>
<code class="select-all">{{ displayName }}</code>
</p>

<img class="qr" v-if="qrimg" :src="qrimg" />
Expand All @@ -22,12 +22,13 @@
</template>

<script setup lang="ts">
import { ref, watch } from 'vue';
import { computed, ref, watch } from 'vue';

import QRCode from 'qrcode';

import ModalComponent from '@/components/ModalComponent.vue';
import ndn from '@/services/ndn';
import * as utils from '@/utils';

const props = defineProps({
show: {
Expand All @@ -39,6 +40,7 @@ const props = defineProps({
const emit = defineEmits(['close']);
const name = ref(String());
const qrimg = ref(String());
const displayName = computed(() => utils.stripNdnPrefixForDisplay(name.value));

watch(
() => props.show,
Expand Down
4 changes: 3 additions & 1 deletion src/components/home/CreateWorkspaceModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

<div>
Your workspace will have the network name &ndash;<br />
<code>{{ fullName }}</code>
<code>{{ displayFullName }}</code>
</div>

<div class="field mt-2 has-text-right">
Expand All @@ -48,6 +48,7 @@ import ModalComponent from '@/components/ModalComponent.vue';
import ndn from '@/services/ndn';
import { Workspace } from '@/services/workspace';
import { Toast } from '@/utils/toast';
import * as utils from '@/utils';

defineProps({
show: {
Expand All @@ -70,6 +71,7 @@ const opts = ref({

// Name we intend to give the workspace
const fullName = computed(() => `${idName.value}/${opts.value.name.trim()}`);
const displayFullName = computed(() => utils.stripNdnPrefixForDisplay(fullName.value));

// No need to reset these values on show
onMounted(async () => {
Expand Down
4 changes: 2 additions & 2 deletions src/components/home/JoinWorkspaceModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ watch(
// Check if URL specifies a workspace
if (route.name === 'join') {
const space = route.params.space as string;
opts.value.name = utils.unescapeUrlName(space || String());
opts.value.name = utils.stripNdnPrefixForDisplay(utils.unescapeUrlName(space || String()));
opts.value.label = (route.query.label as string) || String();
opts.value.psk = (route.query.psk as string) || String();
}
Expand All @@ -97,7 +97,7 @@ async function join() {

// Validate the inputs
const label = opts.value.label.trim();
const name = opts.value.name.trim();
const name = utils.restoreNdnPrefixFromDisplay(opts.value.name.trim());
const psk = opts.value.psk.trim();
if (!label || !name || !psk) {
throw new Error('Please fill in all the fields');
Expand Down
9 changes: 5 additions & 4 deletions src/components/home/LeaveWorkspaceModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<div class="title is-5 mb-4">Leave Workspace</div>
<div class="field">
<p>
You are about to leave the workspace "{{ target }}" from your dashboard. This is a local
You are about to leave the workspace "{{ displayTarget }}" from your dashboard. This is a local
action, your data will not be deleted.
</p>
</div>
Expand All @@ -18,7 +18,7 @@
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { computed, ref } from 'vue';

import ModalComponent from '../ModalComponent.vue';

Expand All @@ -42,6 +42,7 @@ const emit = defineEmits<{
}>();

const loading = ref(false);
const displayTarget = computed(() => utils.stripNdnPrefixForDisplay(props.target));

async function leave() {
try {
Expand All @@ -63,10 +64,10 @@ async function leave() {
emit('leave');
emit('close');

Toast.info(`Left workspace ${props.target}`);
Toast.info(`Left workspace ${displayTarget.value}`);
} catch (err) {
console.error(err);
Toast.error(`Error leaving workspace ${props.target}: ${err}`);
Toast.error(`Error leaving workspace ${displayTarget.value}: ${err}`);
} finally {
loading.value = false;
}
Expand Down
5 changes: 3 additions & 2 deletions src/components/home/WorkspaceCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

<div class="media-content">
<p class="title is-4 has-text-weight-semibold">{{ metadata.label }}</p>
<p class="subtitle is-6 mt-1">{{ metadata.name }}</p>
<p class="subtitle is-6 mt-1">{{ displayName }}</p>
</div>

<button
Expand Down Expand Up @@ -60,7 +60,7 @@
</template>

<script setup lang="ts">
import { onMounted, ref, useTemplateRef } from 'vue';
import { computed, onMounted, ref, useTemplateRef } from 'vue';

import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
import { faEllipsisV } from '@fortawesome/free-solid-svg-icons';
Expand All @@ -87,6 +87,7 @@ const emit = defineEmits(['open', 'leave']);

const avatar = ref<string>(utils.makeAvatar(props.metadata.name ?? 'wksp', 'shapes'));
const wkspMenu = useTemplateRef('wkspMenu');
const displayName = computed(() => utils.stripNdnPrefixForDisplay(props.metadata.name ?? ''));

onMounted(() => {
try {
Expand Down
2 changes: 1 addition & 1 deletion src/services/svs-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,7 @@ class NdnAwareness extends awareProto.Awareness {

// Set the local user state
const userState: AwarenessLocalState['user'] = {
name: username, // common
name: utils.stripNdnPrefixForDisplay(username), // common
color: `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`, // milkdown+monaco
};
me.setLocalStateField('user', userState);
Expand Down
3 changes: 2 additions & 1 deletion src/services/workspace-chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { nanoid } from 'nanoid';

import { GlobalBus } from '@/services/event-bus';
import { SvsProvider } from '@/services/svs-provider';
import * as utils from '@/utils';

import type { IChatChannel, IChatMessage } from '@/services/types';
import type TypedEmitter from 'typed-emitter';
Expand Down Expand Up @@ -91,7 +92,7 @@ export class WorkspaceChat {
uuid: String(), // auto
user: 'ownly-bot',
ts: Date.now(),
message: `#${channel.name} was created by ${this.api.name}`,
message: `#${channel.name} was created by ${utils.stripNdnPrefixForDisplay(this.api.name)}`,
});
}

Expand Down
4 changes: 3 additions & 1 deletion src/services/workspace-invite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ export class WorkspaceInviteManager {
public async tryInvite(invitee: IProfile): Promise<void> {
// Check if the name is already in the list
if (this.inviteeProfiles.has(invitee.name)) {
throw new Error(`Invitation for ${invitee.name} already exists`);
throw new Error(
`Invitation for ${utils.stripNdnPrefixForDisplay(invitee.name)} already exists`,
);
}

// Add invitee
Expand Down
4 changes: 3 additions & 1 deletion src/services/workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,9 @@ export class Workspace {
// Get workspace configuration from storage
const metadata = await _o.stats.get(space);
if (!metadata) {
throw new Error(`Workspace not found, have you joined it? <br/> [${space}]`);
throw new Error(
`Workspace not found, have you joined it? <br/> [${utils.stripNdnPrefixForDisplay(space)}]`,
);
}

// Store last access time
Expand Down
22 changes: 22 additions & 0 deletions src/utils/url.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,28 @@ export function escapeUrlName(input: string) {
return input.replace(/-/g, '--').replace(/\//g, '-');
}

/**
* Remove the standard /ndn prefix from a workspace or user name for display.
* The underlying stored or routed value should remain untouched.
*/
export function stripNdnPrefixForDisplay(input: string): string {
if (!input) return input;

const stripped = input.replace(/^\/ndn(?=\/|$)/, '');
return stripped || '/';
}

/**
* Restore the hidden /ndn prefix for workspace or user names that are entered
* in display form.
*/
export function restoreNdnPrefixFromDisplay(input: string): string {
if (!input) return input;
if (input === '/ndn' || input.startsWith('/ndn/')) return input;
if (input.startsWith('/')) return `/ndn${input === '/' ? '' : input}`;
return input;
}

/**
* Unescape URL parameter to NDN name.
* @param name Escaped NDN name
Expand Down
Loading
Loading