Skip to content
Draft
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
6 changes: 3 additions & 3 deletions client/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
"file-type": "^21.3.2",
"ionicons": "^8.0.9",
"luxon": "^3.5.0",
"megashark-lib": "git+https://github.com/Scille/megashark-lib.git#c7c5ab0be1ebe514a6cb163da597ef2bd8056e1a",
"megashark-lib": "git+https://github.com/Scille/megashark-lib.git#10ff7deb13133688ebb030c5d6e13b721faca797",
"native-file-system-adapter": "^3.0.1",
"pdfjs-dist": "^5.4.624",
"qrcode-vue3": "^1.7.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,24 +62,13 @@
<ion-text class="server-address-value__text body">
{{ orgInfo.organizationAddr }}
</ion-text>
<ion-button
<ms-feedback-button
fill="clear"
size="small"
id="copy-link-btn"
@click="copyAddress(orgInfo.organizationAddr)"
v-if="!addressCopiedToClipboard"
>
<ion-icon
class="icon-copy"
:icon="copy"
/>
</ion-button>
<ion-text
v-if="addressCopiedToClipboard"
class="server-address-value__copied body copied"
>
{{ $msTranslate('OrganizationPage.configuration.copyPath') }}
</ion-text>
:callback="copyAddress"
:normal-state="{ icon: copy }"
/>
</div>
</div>
</div>
Expand All @@ -90,35 +79,16 @@
<script setup lang="ts">
import { formatWorkspaceDeletionDelay } from '@/components/workspaces/utils';
import { OrganizationInfo } from '@/parsec';
import { Information, InformationLevel, InformationManager, InformationManagerKey, PresentationMode } from '@/services/informationManager';
import { IonButton, IonIcon, IonLabel, IonText, IonTitle } from '@ionic/vue';
import { IonLabel, IonText, IonTitle } from '@ionic/vue';
import { copy } from 'ionicons/icons';
import { Clipboard } from 'megashark-lib';
import { inject, ref, Ref } from 'vue';

const informationManager: Ref<InformationManager> = inject(InformationManagerKey)!;
const addressCopiedToClipboard = ref(false);
import { Clipboard, MsFeedbackButton } from 'megashark-lib';

defineProps<{
const props = defineProps<{
orgInfo: OrganizationInfo;
}>();

async function copyAddress(address: string): Promise<void> {
const result = await Clipboard.writeText(address);
if (result) {
addressCopiedToClipboard.value = true;
setTimeout(() => {
addressCopiedToClipboard.value = false;
}, 5000);
} else {
informationManager.value.present(
new Information({
message: 'OrganizationPage.configuration.copyFailed',
level: InformationLevel.Error,
}),
PresentationMode.Toast,
);
}
async function copyAddress(): Promise<boolean | undefined> {
return await Clipboard.writeText(props.orgInfo.organizationAddr);
}
</script>

Expand Down Expand Up @@ -219,20 +189,6 @@ async function copyAddress(address: string): Promise<void> {
color: var(--parsec-color-light-success-700);
}
}

#copy-link-btn {
color: var(--parsec-color-light-secondary-text);
margin: 0;

&::part(native) {
padding: 0.5rem;
border-radius: var(--parsec-radius-6);
}

&:hover {
color: var(--parsec-color-light-primary-600);
}
}
}
}
</style>
63 changes: 18 additions & 45 deletions client/src/components/users/InvitationPopoverItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,32 +25,18 @@
<div class="invitation-footer">
<div class="invitation-footer-manage">
<ion-text class="manage-text button-medium">{{ $msTranslate('UsersPage.invitation.manageInvitation') }}</ion-text>
<ion-button
<ms-feedback-button
fill="clear"
class="manage-button copy-link"
:class="copyLinkActive ? 'active' : ''"
@click.stop="copyLink(invitation)"
:callback="copyLink"
:normal-state="{ icon: link }"
ref="copyLinkButton"
>
<ion-icon
:icon="copyLinkActive ? checkmarkCircle : link"
class="button-icon"
/>
</ion-button>

<ion-button
/>
<ms-feedback-button
fill="clear"
class="manage-button send-email"
:disabled="sendEmailDisabled"
@click.stop="sendEmail(invitation)"
:class="sendEmailDisabled ? 'active' : ''"
:callback="sendEmail"
:normal-state="{ icon: mail }"
ref="sendEmailButton"
>
<ion-icon
:icon="mail"
class="button-icon"
/>
</ion-button>
/>

<ion-button
size="default"
Expand All @@ -74,23 +60,20 @@
import { ClientNewUserInvitationErrorTag, InvitationEmailSentStatus, UserInvitation, inviteUser } from '@/parsec';
import { Information, InformationLevel, InformationManager, PresentationMode } from '@/services/informationManager';
import { IonButton, IonIcon, IonItem, IonLabel, IonText } from '@ionic/vue';
import { checkmarkCircle, link, mail, trash } from 'ionicons/icons';
import { Answer, Clipboard, Translatable, askQuestion, attachMouseOverTooltip, formatTimeSince } from 'megashark-lib';
import { onMounted, ref, useTemplateRef } from 'vue';
import { link, mail, trash } from 'ionicons/icons';
import { Answer, Clipboard, MsFeedbackButton, Translatable, askQuestion, attachMouseOverTooltip, formatTimeSince } from 'megashark-lib';
import { onMounted, useTemplateRef } from 'vue';

const props = defineProps<{
invitation: UserInvitation;
informationManager: InformationManager;
}>();

const copyLinkActive = ref(false);

defineEmits<{
(e: 'cancel', invitation: UserInvitation): void;
(e: 'greetUser', invitation: UserInvitation): void;
}>();

const sendEmailDisabled = ref(false);
const sendEmailButtonRef = useTemplateRef<InstanceType<typeof IonButton>>('sendEmailButton');
const copyLinkButtonRef = useTemplateRef<InstanceType<typeof IonButton>>('copyLinkButton');

Expand All @@ -99,13 +82,9 @@ onMounted(async () => {
attachMouseOverTooltip(copyLinkButtonRef.value?.$el, 'UsersPage.invitation.copyLink');
});

async function copyLink(invitation: UserInvitation): Promise<void> {
const [_, invitationAddrAsHttpRedirection] = invitation.addr;
async function copyLink(): Promise<boolean> {
const [_, invitationAddrAsHttpRedirection] = props.invitation.addr;
const result = await Clipboard.writeText(invitationAddrAsHttpRedirection);
copyLinkActive.value = true;
setTimeout(() => {
copyLinkActive.value = false;
}, 5000);
if (result) {
props.informationManager.present(
new Information({
Expand All @@ -123,35 +102,31 @@ async function copyLink(invitation: UserInvitation): Promise<void> {
PresentationMode.Toast,
);
}
return result;
}

async function sendEmail(invitation: UserInvitation): Promise<void> {
sendEmailDisabled.value = true;
async function sendEmail(): Promise<boolean | undefined> {
const answer = await askQuestion('UsersPage.invitation.sendEmailTitle', 'UsersPage.invitation.sendEmailMessage', {
yesText: 'UsersPage.invitation.sendEmail',
});

if (answer === Answer.No) {
sendEmailDisabled.value = false;
return;
}
const result = await inviteUser(invitation.claimerEmail);
const result = await inviteUser(props.invitation.claimerEmail);
if (result.ok && result.value.emailSentStatus === InvitationEmailSentStatus.Success) {
props.informationManager.present(
new Information({
message: {
key: 'UsersPage.invitation.inviteSuccessMailSent',
data: {
email: invitation.claimerEmail,
email: props.invitation.claimerEmail,
},
},
level: InformationLevel.Success,
}),
PresentationMode.Toast,
);
setTimeout(() => {
sendEmailDisabled.value = false;
}, 5000);
} else {
let message: Translatable = '';
if (result.ok) {
Expand Down Expand Up @@ -181,10 +156,8 @@ async function sendEmail(invitation: UserInvitation): Promise<void> {
}),
PresentationMode.Toast,
);
setTimeout(() => {
sendEmailDisabled.value = false;
}, 2000);
}
return result.ok;
}
</script>

Expand Down
61 changes: 15 additions & 46 deletions client/src/views/files/FileDetailsModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -98,32 +98,15 @@
{{ showFullPath ? entry.path : shortenFileName(entry.path, { maxLength: 60, prefixLength: 20, suffixLength: 30 }) }}
</span>
</ion-text>
<template v-if="isDesktop()">
<ion-button
fill="clear"
size="small"
id="copy-link-btn"
@click="copyPath"
v-show="copyStatus === CopyStatus.NotCopied"
>
<ion-icon
class="icon-copy"
:icon="copy"
/>
</ion-button>
<ion-text
v-show="copyStatus === CopyStatus.Copied"
class="file-info-path-value__copied body copied"
>
{{ $msTranslate('FileDetails.stats.linkCopied') }}
</ion-text>
<ion-text
v-show="copyStatus === CopyStatus.FailedToCopy"
class="file-info-path-value__not-copied body"
>
{{ $msTranslate('FileDetails.stats.failedToCopy') }}
</ion-text>
</template>
<ms-feedback-button
v-if="isDesktop()"
:callback="copyPath"
fill="clear"
size="small"
:normal-state="{ icon: copy }"
:failure-state="{ text: 'FileDetails.stats.failedToCopy' }"
:success-state="{ text: 'FailedDetails.stats.linkCopied' }"
/>
</div>
<ion-text
class="file-info-path__full button-small"
Expand All @@ -142,25 +125,18 @@
import { formatFileSize, getFileIcon, shortenFileName } from '@/common/file';
import { TechnicalId } from '@/components/misc';
import { EntryStat, EntryStatFile, getSystemPath, isDesktop, UserProfile, WorkspaceHandle } from '@/parsec';
import { IonButton, IonIcon, IonLabel, IonPage, IonText } from '@ionic/vue';
import { IonIcon, IonLabel, IonPage, IonText } from '@ionic/vue';
import { cloudDone, cloudOffline, copy } from 'ionicons/icons';
import { Clipboard, Folder, I18n, MsImage, MsModal, openTooltip } from 'megashark-lib';
import { Clipboard, Folder, I18n, MsFeedbackButton, MsImage, MsModal, openTooltip } from 'megashark-lib';
import { ref } from 'vue';

enum CopyStatus {
NotCopied,
Copied,
FailedToCopy,
}

const props = defineProps<{
entry: EntryStat;
workspaceHandle: WorkspaceHandle;
ownProfile: UserProfile;
}>();

const showFullPath = ref(false);
const copyStatus = ref(CopyStatus.NotCopied);

function getSyncString(): string {
if (props.entry.isFile()) {
Expand All @@ -170,25 +146,18 @@ function getSyncString(): string {
}
}

async function copyPath(): Promise<void> {
async function copyPath(): Promise<boolean | undefined> {
const fullPathResult = await getSystemPath(props.workspaceHandle, props.entry.path);

if (fullPathResult.ok) {
if (await Clipboard.writeText(fullPathResult.value)) {
copyStatus.value = CopyStatus.Copied;
setTimeout(() => {
copyStatus.value = CopyStatus.NotCopied;
}, 4000);
return;
return true;
} else {
copyStatus.value = CopyStatus.FailedToCopy;
return false;
}
} else {
copyStatus.value = CopyStatus.FailedToCopy;
return false;
}
setTimeout(() => {
copyStatus.value = CopyStatus.NotCopied;
}, 4000);
}
</script>

Expand Down
4 changes: 1 addition & 3 deletions client/src/views/invitations/InvitationsPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -311,9 +311,7 @@ onMounted(async (): Promise<void> => {

watch(copyJoinRequestLinkRef, (button) => {
if (button?.$el) {
setTimeout(() => {
attachMouseOverTooltip(button.$el, 'InvitationsPage.asyncEnrollmentRequest.tooltips.copyLinkInfo');
}, 500);
attachMouseOverTooltip(button.$el, 'InvitationsPage.asyncEnrollmentRequest.tooltips.copyLinkInfo');
}
});
});
Expand Down
Loading
Loading