Use a key that doesn't change to avoid re-render issues; closes #2203
This commit is contained in:
parent
21a4ce8043
commit
b92c97060b
|
@ -2,7 +2,7 @@ import http from '@/api/http';
|
||||||
import { rawDataToFileObject } from '@/api/transformers';
|
import { rawDataToFileObject } from '@/api/transformers';
|
||||||
|
|
||||||
export interface FileObject {
|
export interface FileObject {
|
||||||
uuid: string;
|
key: string;
|
||||||
name: string;
|
name: string;
|
||||||
mode: string;
|
mode: string;
|
||||||
size: number;
|
size: number;
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { Allocation } from '@/api/server/getServer';
|
import { Allocation } from '@/api/server/getServer';
|
||||||
import { FractalResponseData } from '@/api/http';
|
import { FractalResponseData } from '@/api/http';
|
||||||
import { FileObject } from '@/api/server/files/loadDirectory';
|
import { FileObject } from '@/api/server/files/loadDirectory';
|
||||||
import v4 from 'uuid/v4';
|
|
||||||
|
|
||||||
export const rawDataToServerAllocation = (data: FractalResponseData): Allocation => ({
|
export const rawDataToServerAllocation = (data: FractalResponseData): Allocation => ({
|
||||||
id: data.attributes.id,
|
id: data.attributes.id,
|
||||||
|
@ -13,7 +12,7 @@ export const rawDataToServerAllocation = (data: FractalResponseData): Allocation
|
||||||
});
|
});
|
||||||
|
|
||||||
export const rawDataToFileObject = (data: FractalResponseData): FileObject => ({
|
export const rawDataToFileObject = (data: FractalResponseData): FileObject => ({
|
||||||
uuid: v4(),
|
key: `${data.attributes.is_file ? 'file' : 'dir'}_${data.attributes.name}`,
|
||||||
name: data.attributes.name,
|
name: data.attributes.name,
|
||||||
mode: data.attributes.mode,
|
mode: data.attributes.mode,
|
||||||
size: Number(data.attributes.size),
|
size: Number(data.attributes.size),
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useRef, useState } from 'react';
|
import React, { memo, useRef, useState } from 'react';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import {
|
import {
|
||||||
faBoxOpen,
|
faBoxOpen,
|
||||||
|
@ -29,6 +29,7 @@ import styled from 'styled-components/macro';
|
||||||
import useEventListener from '@/plugins/useEventListener';
|
import useEventListener from '@/plugins/useEventListener';
|
||||||
import compressFiles from '@/api/server/files/compressFiles';
|
import compressFiles from '@/api/server/files/compressFiles';
|
||||||
import decompressFiles from '@/api/server/files/decompressFiles';
|
import decompressFiles from '@/api/server/files/decompressFiles';
|
||||||
|
import isEqual from 'react-fast-compare';
|
||||||
|
|
||||||
type ModalType = 'rename' | 'move';
|
type ModalType = 'rename' | 'move';
|
||||||
|
|
||||||
|
@ -50,7 +51,7 @@ const Row = ({ icon, title, ...props }: RowProps) => (
|
||||||
</StyledRow>
|
</StyledRow>
|
||||||
);
|
);
|
||||||
|
|
||||||
export default ({ file }: { file: FileObject }) => {
|
const FileDropdownMenu = ({ file }: { file: FileObject }) => {
|
||||||
const onClickRef = useRef<DropdownMenu>(null);
|
const onClickRef = useRef<DropdownMenu>(null);
|
||||||
const [ showSpinner, setShowSpinner ] = useState(false);
|
const [ showSpinner, setShowSpinner ] = useState(false);
|
||||||
const [ modal, setModal ] = useState<ModalType | null>(null);
|
const [ modal, setModal ] = useState<ModalType | null>(null);
|
||||||
|
@ -60,7 +61,7 @@ export default ({ file }: { file: FileObject }) => {
|
||||||
const { clearAndAddHttpError, clearFlashes } = useFlash();
|
const { clearAndAddHttpError, clearFlashes } = useFlash();
|
||||||
const directory = ServerContext.useStoreState(state => state.files.directory);
|
const directory = ServerContext.useStoreState(state => state.files.directory);
|
||||||
|
|
||||||
useEventListener(`pterodactyl:files:ctx:${file.uuid}`, (e: CustomEvent) => {
|
useEventListener(`pterodactyl:files:ctx:${file.key}`, (e: CustomEvent) => {
|
||||||
if (onClickRef.current) {
|
if (onClickRef.current) {
|
||||||
onClickRef.current.triggerMenu(e.detail);
|
onClickRef.current.triggerMenu(e.detail);
|
||||||
}
|
}
|
||||||
|
@ -71,7 +72,7 @@ export default ({ file }: { file: FileObject }) => {
|
||||||
|
|
||||||
// For UI speed, immediately remove the file from the listing before calling the deletion function.
|
// For UI speed, immediately remove the file from the listing before calling the deletion function.
|
||||||
// If the delete actually fails, we'll fetch the current directory contents again automatically.
|
// If the delete actually fails, we'll fetch the current directory contents again automatically.
|
||||||
mutate(files => files.filter(f => f.uuid !== file.uuid), false);
|
mutate(files => files.filter(f => f.key !== file.key), false);
|
||||||
|
|
||||||
deleteFiles(uuid, directory, [ file.name ]).catch(error => {
|
deleteFiles(uuid, directory, [ file.name ]).catch(error => {
|
||||||
mutate();
|
mutate();
|
||||||
|
@ -166,3 +167,5 @@ export default ({ file }: { file: FileObject }) => {
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default memo(FileDropdownMenu, isEqual);
|
||||||
|
|
|
@ -65,7 +65,7 @@ export default () => {
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
sortFiles(files.slice(0, 250)).map(file => (
|
sortFiles(files.slice(0, 250)).map(file => (
|
||||||
<FileObjectRow key={file.uuid} file={file}/>
|
<FileObjectRow key={file.key} file={file}/>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
<MassActionsBar/>
|
<MassActionsBar/>
|
||||||
|
|
|
@ -39,7 +39,7 @@ const FileObjectRow = ({ file }: { file: FileObject }) => {
|
||||||
key={file.name}
|
key={file.name}
|
||||||
onContextMenu={e => {
|
onContextMenu={e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
window.dispatchEvent(new CustomEvent(`pterodactyl:files:ctx:${file.uuid}`, { detail: e.clientX }));
|
window.dispatchEvent(new CustomEvent(`pterodactyl:files:ctx:${file.key}`, { detail: e.clientX }));
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<SelectFileCheckbox name={file.name}/>
|
<SelectFileCheckbox name={file.name}/>
|
||||||
|
|
|
@ -6,7 +6,6 @@ import Field from '@/components/elements/Field';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import { object, string } from 'yup';
|
import { object, string } from 'yup';
|
||||||
import createDirectory from '@/api/server/files/createDirectory';
|
import createDirectory from '@/api/server/files/createDirectory';
|
||||||
import v4 from 'uuid/v4';
|
|
||||||
import tw from 'twin.macro';
|
import tw from 'twin.macro';
|
||||||
import Button from '@/components/elements/Button';
|
import Button from '@/components/elements/Button';
|
||||||
import { mutate } from 'swr';
|
import { mutate } from 'swr';
|
||||||
|
@ -24,7 +23,7 @@ const schema = object().shape({
|
||||||
});
|
});
|
||||||
|
|
||||||
const generateDirectoryData = (name: string): FileObject => ({
|
const generateDirectoryData = (name: string): FileObject => ({
|
||||||
uuid: v4(),
|
key: `dir_${name}`,
|
||||||
name: name,
|
name: name,
|
||||||
mode: '0644',
|
mode: '0644',
|
||||||
size: 0,
|
size: 0,
|
||||||
|
|
Loading…
Reference in New Issue