Skip to content

Commit

Permalink
馃┕ Patch 3 (#2790)
Browse files Browse the repository at this point in the history
* Fix unable to preview migrated files, fix error when switching workspaces

* Fix missing events and tasks, remove email invitation calendar

* Put back link-files
  • Loading branch information
RomaricMourgues authored and Labels Bot committed Apr 5, 2023
1 parent aeacc54 commit 06f5327
Show file tree
Hide file tree
Showing 15 changed files with 214 additions and 10 deletions.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions twake/frontend/src/app/atoms/icons-colored/index.tsx
Expand Up @@ -9,6 +9,7 @@ import { ReactComponent as FileTypeSpreadsheetSvg } from './assets/file-type-spr
import { ReactComponent as FileTypeUnknownSvg } from './assets/file-type-unknown.svg';
import { ReactComponent as FileTypeMediaSvg } from './assets/file-type-media.svg';
import { ReactComponent as FileTypeSlidesSvg } from './assets/file-type-slides.svg';
import { ReactComponent as FileTypeLinkSvg } from './assets/file-type-link.svg';
import { ReactComponent as RemoveSvg } from './assets/remove.svg';
import { ReactComponent as SentSvg } from './assets/sent.svg';

Expand All @@ -34,6 +35,8 @@ export const FileTypeSlidesIcon = (props: ComponentProps<'svg'>) => (
<FileTypeSlidesSvg {...props} />
);

export const FileTypeLinkIcon = (props: ComponentProps<'svg'>) => <FileTypeLinkSvg {...props} />;

export const RemoveIcon = (props: ComponentProps<'svg'>) => <RemoveSvg {...props} />;

export const SentIcon = (props: ComponentProps<'svg'>) => <SentSvg {...props} />;
Expand Up @@ -153,7 +153,8 @@ export default class Collection extends Observable {
if (
routes.length === 0 ||
(options.http_options || {})._http_force_load ||
!waiting_one_route
!waiting_one_route ||
true //Keep it working after making it highly deprecated
) {
initHttp();
}
Expand Down
Expand Up @@ -11,7 +11,10 @@ export const useDrivePreviewModal = () => {
const [status, setStatus] = useRecoilState(DriveViewerState);

const open: (item: DriveItem) => void = (item: DriveItem) => {
if (item.last_version_cache?.file_metadata?.source === 'internal') {
if (
!item.last_version_cache?.file_metadata?.source ||
item.last_version_cache?.file_metadata?.source === 'internal'
) {
setStatus({ item, loading: true });
}
};
Expand Down Expand Up @@ -79,5 +82,5 @@ export const useDrivePreviewDisplayData = () => {
fileId: status.details?.item.last_version_cache.file_metadata.external_id || '',
});

return { download, id, name, type, extension };
return { download, id, name, type, extension, size: status.details?.item.size };
};
Expand Up @@ -105,7 +105,8 @@ class FileUploadAPIClient {
}

public mimeToType(mime: string, extension?: string): FileTypes {
const { archives, images, pdf, slides, audio, spreadsheets, videos, documents } = fileTypeMimes;
const { archives, images, pdf, slides, audio, spreadsheets, videos, documents, links } =
fileTypeMimes;

if (images.includes(mime)) return 'image';
if (videos.includes(mime)) return 'video';
Expand All @@ -115,6 +116,7 @@ class FileUploadAPIClient {
if (archives.includes(mime)) return 'archive';
if (spreadsheets.includes(mime)) return 'spreadsheet';
if (documents.includes(mime)) return 'document';
if (links.includes(mime)) return 'link';

if (extension && AceModeList.getMode(extension) !== 'text') {
return 'code';
Expand Down
2 changes: 2 additions & 0 deletions twake/frontend/src/app/features/files/utils/type-mimes.ts
Expand Up @@ -151,6 +151,7 @@ export const fileTypeMimes: FileTypeMimes = {
'text/csv',
'application/vnd.ms-excel.sheet.macroEnabled.12',
],
links: ['text/uri-list'],
};

export type FileTypeMimes = {
Expand All @@ -162,4 +163,5 @@ export type FileTypeMimes = {
archives: string[];
pdf: string[];
documents: string[];
links: string[];
};
Expand Up @@ -207,7 +207,7 @@ class WebSocketService extends EventEmitter {
* @param tag
*/
public leave(path: string, tag: string) {
const name = path.replace(/\/$/, '');
const name = path ? path.replace(/\/$/, '') : '';

this.wsListeners[name] = this.wsListeners[name] || {};
delete this.wsListeners[name][tag];
Expand Down
3 changes: 2 additions & 1 deletion twake/frontend/src/app/features/viewer/hooks/use-viewer.ts
Expand Up @@ -24,7 +24,8 @@ export const useFileViewerModal = () => {

return {
open: (file: MessageFileType) => {
if (file.metadata?.source === 'internal') setStatus({ file, loading: true });
if (!file.metadata?.source || file.metadata?.source === 'internal')
setStatus({ file, loading: true });
},
close: () => setStatus({ file: null, loading: true }),
isOpen: !!status?.file,
Expand Down
Expand Up @@ -26,7 +26,6 @@ export default class Participants extends Component {
return { id: participant.user_id_or_mail };
})}
scope="workspace"
allowMails
onUpdate={ids_mails => {
this.props.onChange &&
this.props.onChange(
Expand Down
Expand Up @@ -3,6 +3,7 @@ import { Button } from 'app/atoms/button/button';
import {
FileTypeArchiveIcon,
FileTypeDocumentIcon,
FileTypeLinkIcon,
FileTypeMediaIcon,
FileTypePdfIcon,
FileTypeSlidesIcon,
Expand Down Expand Up @@ -89,6 +90,8 @@ export const DocumentRow = ({
<FileTypeSpreadsheetIcon className={'h-5 w-5 shrink-0 text-gray-400'} />
) : fileType === 'slides' ? (
<FileTypeSlidesIcon className={'h-5 w-5 shrink-0 text-gray-400'} />
) : fileType === 'link' ? (
<FileTypeLinkIcon className={'h-5 w-5 shrink-0 text-gray-400'} />
) : (
<FileTypeUnknownIcon className={'h-5 w-5 shrink-0 text-gray-400'} />
)}
Expand Down
@@ -0,0 +1,80 @@
import { Button } from 'app/atoms/button/button';
import { Input } from 'app/atoms/input/input-text';
import { Info } from 'app/atoms/text';
import { useDriveActions } from 'app/features/drive/hooks/use-drive-actions';
import { useState } from 'react';
import { useRecoilState } from 'recoil';
import { CreateModalAtom } from '.';
import FileUploadService from 'features/files/services/file-upload-service';

export const CreateLink = () => {
const [name, setName] = useState<string>('');
const [link, setLink] = useState<string>('');
const [loading] = useState<boolean>(false);
const [state, setState] = useRecoilState(CreateModalAtom);
const { create } = useDriveActions();

const createLink = async () => {
let finalLink = link.trim();
if (!/^https?:\/\//i.test(finalLink)) finalLink = 'http://' + finalLink;
const file = new File(['[InternetShortcut]\nURL=' + finalLink], name?.trim() + '.url', {
type: 'text/uri-list',
});

await FileUploadService.upload([file], {
context: {
parentId: state.parent_id,
},
callback: (file, context) => {
if (file)
create(
{ name, parent_id: context.parentId, size: file.upload_data?.size },
{
provider: 'internal',
application_id: '',
file_metadata: {
name: file.metadata?.name,
size: file.upload_data?.size,
mime: file.metadata?.mime,
thumbnails: file?.thumbnails,
source: 'internal',
external_id: file.id,
},
},
);
},
});
};

return (
<>
<Info>Create a link</Info>

<Input
disabled={loading}
placeholder="Link name"
className="w-full mt-4"
onChange={e => setName(e.target.value)}
/>

<Input
disabled={loading}
placeholder="https://example.com"
className="w-full mt-4"
onChange={e => setLink(e.target.value)}
/>

<Button
disabled={!name || !link}
loading={loading}
className="mt-4 float-right"
onClick={async () => {
await createLink();
setState({ ...state, open: false });
}}
>
Create link
</Button>
</>
);
};
@@ -1,17 +1,17 @@
import { Transition } from '@headlessui/react';
import { ChevronLeftIcon, DesktopComputerIcon } from '@heroicons/react/outline';
import { FolderIcon } from '@heroicons/react/solid';
import { FolderIcon, LinkIcon } from '@heroicons/react/solid';
import Avatar from 'app/atoms/avatar';
import A from 'app/atoms/link';
import { Modal, ModalContent } from 'app/atoms/modal';
import { Base } from 'app/atoms/text';
import { useApplications } from 'app/features/applications/hooks/use-applications';
import { useCompanyApplications } from 'app/features/applications/hooks/use-company-applications';
import { Application } from 'app/features/applications/types/application';
import { ReactNode } from 'react';
import { atom, useRecoilState } from 'recoil';
import { slideXTransition, slideXTransitionReverted } from 'src/utils/transitions';
import { CreateFolder } from './create-folder';
import { CreateLink } from './create-link';

export type CreateModalAtomType = {
open: boolean;
Expand Down Expand Up @@ -81,6 +81,11 @@ export const CreateModal = ({
text="Upload document from device"
onClick={() => selectFromDevice()}
/>
<CreateModalOption
icon={<LinkIcon className="w-5 h-5" />}
text="Create a link file"
onClick={() => setState({ ...state, type: 'link' })}
/>

{(applications || [])
.filter(app => app.display?.twake?.files?.editor?.empty_files?.length)
Expand Down Expand Up @@ -136,6 +141,18 @@ export const CreateModal = ({
>
<CreateFolder />
</Transition>

<Transition
style={{
gridColumn: '1 / 1',
gridRow: '1 / 1',
}}
show={state.type === 'link'}
as="div"
{...(!state.type ? slideXTransitionReverted : slideXTransition)}
>
<CreateLink />
</Transition>
</div>
</ModalContent>
</Modal>
Expand Down
10 changes: 9 additions & 1 deletion twake/frontend/src/app/views/applications/viewer/display.tsx
Expand Up @@ -20,7 +20,7 @@ export default () => {
}

if (type === 'image') {
return <ImageDisplay loading={loading} setLoading={setLoading} download={download} />;
return <ImageDisplay loading={loading} setLoading={setLoading} download={download} />;
}

if (type === 'video' || type === 'audio') {
Expand All @@ -39,6 +39,14 @@ export default () => {
return <ArchiveDisplay download={download} name={name} />;
}

if (type === 'link') {
return (
<div className="text-white m-auto w-full text-center block h-full flex items-center">
<span className="block w-full text-center">Opening link...</span>
</div>
);
}

// /* Uncomment after https://github.com/linagora/Twake/issues/2453 is done
if (type) {
return <OtherDisplay download={download} name={name} id={id} />;
Expand Down
Expand Up @@ -9,6 +9,7 @@ import PdfDisplay from './pdf/display';
import CodeDisplay from './code/display';
import ArchiveDisplay from './archive/display';
import OtherDisplay from './other/display';
import LinkDisplay from './link/display';

export default (): React.ReactElement => {
const { download, type, name, id } = useDrivePreviewDisplayData();
Expand Down Expand Up @@ -39,6 +40,8 @@ export default (): React.ReactElement => {
return <ArchiveDisplay download={download} name={name} />;
case 'pdf':
return <PdfDisplay download={download} name={name} />;
case 'link':
return <LinkDisplay download={download} name={name} />;
default:
return <OtherDisplay download={download} name={name} id={id} />;
}
Expand Down
71 changes: 71 additions & 0 deletions twake/frontend/src/app/views/applications/viewer/link/display.tsx
@@ -0,0 +1,71 @@
import { Button } from 'app/atoms/button/button';
import { useDrivePreviewDisplayData } from 'app/features/drive/hooks/use-drive-preview';
import { useEffect, useState } from 'react';

export default (props: { download: string; name: string }) => {
const { size } = useDrivePreviewDisplayData();
const [error, setError] = useState(false);
const [loading, setLoading] = useState(true);

const openLink = async () => {
if ((size || 10000000) < 10000) {
setLoading(true);
//Download file content and extract link from url props.download
try {
const response = await fetch(props.download);
const blob = await response.blob();
const reader = new FileReader();
reader.readAsText(blob);
reader.onloadend = () => {
const result = reader.result as string;
const link = result.match(/URL=(.*)/);
if (link && link[1]) {
if (!link[1].match(/^(http|https):\/\//)) throw new Error('Invalid link');
window.open(link[1], '_blank');
} else {
setError(true);
}
setLoading(false);
};
} catch (e) {
setError(true);
setLoading(false);
}
return;
}
setError(true);
};

useEffect(() => {
openLink();
}, []);

if (loading) {
return (
<div className="text-white m-auto w-full text-center h-full flex items-center">
<span className="block w-full text-center">Opening link...</span>
</div>
);
}

if (error) {
return (
<div className="text-white m-auto w-full text-center h-full flex items-center">
<span className="block w-full text-center">
We can't open '{props.name}' as a link. You can download it instead.
</span>
</div>
);
}

return (
<div className="text-white m-auto w-full text-center h-full flex items-center">
<span className="block w-full text-center">
Link was open on another tab.
<br />
<br />
<Button onClick={() => openLink()}>Open again</Button>
</span>
</div>
);
};

0 comments on commit 06f5327

Please sign in to comment.