You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-11-29 22:48:10 +02:00
Mobile: Joplin Cloud/Server: Support publishing notes (#12350)
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
import ShareService from '../../../services/share/ShareService';
|
||||
|
||||
interface UnshareNoteEvent {
|
||||
noteId: string;
|
||||
}
|
||||
|
||||
const onUnshareNoteClick = async (event: UnshareNoteEvent) => {
|
||||
await ShareService.instance().unshareNote(event.noteId);
|
||||
await ShareService.instance().refreshShares();
|
||||
};
|
||||
|
||||
export default onUnshareNoteClick;
|
||||
9
packages/lib/components/shared/ShareNoteDialog/types.ts
Normal file
9
packages/lib/components/shared/ShareNoteDialog/types.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
|
||||
// eslint-disable-next-line import/prefer-default-export -- types file with a single type
|
||||
export enum SharingStatus {
|
||||
Unknown = 'unknown',
|
||||
Synchronizing = 'synchronizing',
|
||||
Creating = 'creating',
|
||||
Idle = 'idle',
|
||||
Created = 'created',
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { _ } from '../../../locale';
|
||||
import { getEncryptionEnabled } from '../../../services/synchronizer/syncInfoUtils';
|
||||
|
||||
const useEncryptionWarningMessage = () => {
|
||||
if (!getEncryptionEnabled()) return null;
|
||||
return _('Note: When a note is shared, it will no longer be encrypted on the server.');
|
||||
};
|
||||
|
||||
export default useEncryptionWarningMessage;
|
||||
@@ -0,0 +1,88 @@
|
||||
import Logger from '@joplin/utils/Logger';
|
||||
import JoplinServerApi from '../../../JoplinServerApi';
|
||||
import { reg } from '../../../registry';
|
||||
import { NoteEntity } from '../../../services/database/types';
|
||||
import ShareService from '../../../services/share/ShareService';
|
||||
import { StateShare } from '../../../services/share/reducer';
|
||||
import shim from '../../../shim';
|
||||
import { SharingStatus } from './types';
|
||||
const { useCallback } = shim.react();
|
||||
|
||||
const logger = Logger.create('useOnShareLinkClick');
|
||||
|
||||
interface Props {
|
||||
notes: NoteEntity[];
|
||||
recursiveShare: boolean;
|
||||
setSharesState(state: SharingStatus): void;
|
||||
onShareUrlsReady(urls: string[]): void;
|
||||
}
|
||||
|
||||
const getShareLinks = (shares: StateShare[]) => {
|
||||
const links = [];
|
||||
for (const share of shares) {
|
||||
if (!share) {
|
||||
throw new Error('Error: Empty share.');
|
||||
}
|
||||
|
||||
links.push(ShareService.instance().shareUrl(ShareService.instance().userId, share));
|
||||
}
|
||||
|
||||
return links;
|
||||
};
|
||||
|
||||
const useOnShareLinkClick = ({
|
||||
setSharesState, onShareUrlsReady, notes, recursiveShare,
|
||||
}: Props) => {
|
||||
|
||||
return useCallback(async () => {
|
||||
const service = ShareService.instance();
|
||||
|
||||
let hasSynced = false;
|
||||
let tryToSync = false;
|
||||
while (true) {
|
||||
try {
|
||||
if (tryToSync) {
|
||||
setSharesState(SharingStatus.Synchronizing);
|
||||
await reg.waitForSyncFinishedThenSync();
|
||||
tryToSync = false;
|
||||
hasSynced = true;
|
||||
}
|
||||
|
||||
setSharesState(SharingStatus.Creating);
|
||||
|
||||
const newShares: StateShare[] = [];
|
||||
|
||||
for (const note of notes) {
|
||||
const share = await service.shareNote(note.id, recursiveShare);
|
||||
newShares.push(share);
|
||||
}
|
||||
|
||||
setSharesState(SharingStatus.Synchronizing);
|
||||
await reg.waitForSyncFinishedThenSync();
|
||||
setSharesState(SharingStatus.Creating);
|
||||
|
||||
onShareUrlsReady(getShareLinks(newShares));
|
||||
|
||||
setSharesState(SharingStatus.Created);
|
||||
|
||||
await ShareService.instance().refreshShares();
|
||||
} catch (error) {
|
||||
if (error.code === 404 && !hasSynced) {
|
||||
logger.info('ShareNoteDialog: Note does not exist on server - trying to sync it.', error);
|
||||
tryToSync = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
console.error(error);
|
||||
logger.error('ShareNoteDialog: Cannot publish note:', error);
|
||||
|
||||
setSharesState(SharingStatus.Idle);
|
||||
void shim.showErrorDialog(JoplinServerApi.connectionErrorMessage(error));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}, [recursiveShare, notes, onShareUrlsReady, setSharesState]);
|
||||
};
|
||||
|
||||
export default useOnShareLinkClick;
|
||||
@@ -0,0 +1,29 @@
|
||||
import { _, _n } from '../../../locale';
|
||||
import shim from '../../../shim';
|
||||
import { SharingStatus } from './types';
|
||||
|
||||
interface Props {
|
||||
sharesState: SharingStatus;
|
||||
noteCount: number;
|
||||
}
|
||||
|
||||
const useShareStatusMessage = ({ sharesState, noteCount }: Props): string => {
|
||||
if (sharesState === SharingStatus.Synchronizing) {
|
||||
return _('Synchronising...');
|
||||
}
|
||||
if (sharesState === SharingStatus.Creating) {
|
||||
return _n('Generating link...', 'Generating links...', noteCount);
|
||||
}
|
||||
if (sharesState === SharingStatus.Created) {
|
||||
// On web, copying text after a long delay (e.g. to sync) fails.
|
||||
// As such, the web UI for copying links is a bit different:
|
||||
if (shim.mobilePlatform() === 'web') {
|
||||
return _n('Link created!', 'Links created!', noteCount);
|
||||
} else {
|
||||
return _n('Link has been copied to clipboard!', 'Links have been copied to clipboard!', noteCount);
|
||||
}
|
||||
}
|
||||
return '';
|
||||
};
|
||||
|
||||
export default useShareStatusMessage;
|
||||
Reference in New Issue
Block a user