mirror of
https://github.com/filecoin-project/slate.git
synced 2024-11-08 23:51:22 +03:00
finished with retractable upload sidebar
This commit is contained in:
parent
e936391d66
commit
ac3d970c47
@ -4,22 +4,53 @@ import * as Constants from "~/common/constants";
|
||||
|
||||
import { error } from "~/common/messages";
|
||||
import { css } from "@emotion/react";
|
||||
import { LoaderSpinner } from "~/components/system/components/Loaders";
|
||||
|
||||
const STYLES_ALERT = css`
|
||||
const STYLES_ALERT = `
|
||||
box-sizing: border-box;
|
||||
z-index: ${Constants.zindex.alert};
|
||||
position: fixed;
|
||||
top: 56px;
|
||||
width: calc(100% - ${Constants.sizes.navigation}px);
|
||||
min-height: 48px;
|
||||
background-color: ${Constants.system.red};
|
||||
color: ${Constants.system.white};
|
||||
min-height: 48px;
|
||||
padding: 12px 48px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
const STYLES_WARNING = css`
|
||||
${STYLES_ALERT}
|
||||
background-color: ${Constants.system.red};
|
||||
|
||||
@supports (
|
||||
(-webkit-backdrop-filter: blur(25px)) or (backdrop-filter: blur(25px))
|
||||
) {
|
||||
-webkit-backdrop-filter: blur(25px);
|
||||
backdrop-filter: blur(25px);
|
||||
background-color: rgba(255, 212, 201, 0.75);
|
||||
color: ${Constants.system.red};
|
||||
}
|
||||
`;
|
||||
|
||||
const STYLES_INFO = css`
|
||||
${STYLES_ALERT}
|
||||
@supports (
|
||||
(-webkit-backdrop-filter: blur(25px)) or (backdrop-filter: blur(25px))
|
||||
) {
|
||||
-webkit-backdrop-filter: blur(25px);
|
||||
backdrop-filter: blur(25px);
|
||||
background-color: rgba(212, 233, 250, 0.75);
|
||||
color: ${Constants.system.brand};
|
||||
}
|
||||
`;
|
||||
|
||||
const STYLES_MESSAGE_BOX = css`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
export class Alert extends React.Component {
|
||||
state = {
|
||||
message: null,
|
||||
@ -61,16 +92,36 @@ export class Alert extends React.Component {
|
||||
|
||||
render() {
|
||||
if (!this.state.message) {
|
||||
return null;
|
||||
if (
|
||||
!this.props.fileLoading ||
|
||||
!Object.keys(this.props.fileLoading).length
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<div
|
||||
css={STYLES_INFO}
|
||||
style={{ cursor: "pointer" }}
|
||||
onClick={() =>
|
||||
this.props.onAction({
|
||||
type: "SIDEBAR",
|
||||
value: "SIDEBAR_ADD_FILE_TO_BUCKET",
|
||||
})
|
||||
}
|
||||
>
|
||||
<div css={STYLES_MESSAGE_BOX}>
|
||||
<LoaderSpinner style={{ height: 16, width: 16, marginRight: 16 }} />
|
||||
{Object.keys(this.props.fileLoading).length} file
|
||||
{Object.keys(this.props.fileLoading).length === 1 ? "" : "s"}{" "}
|
||||
uploading
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div
|
||||
css={STYLES_ALERT}
|
||||
style={{
|
||||
backgroundColor:
|
||||
this.state.status === "INFO" ? Constants.system.brand : "auto",
|
||||
...this.props.style,
|
||||
}}
|
||||
css={this.state.status === "INFO" ? STYLES_INFO : STYLES_WARNING}
|
||||
style={this.props.style}
|
||||
>
|
||||
{this.state.message}
|
||||
</div>
|
||||
|
@ -55,7 +55,7 @@ import Cookies from "universal-cookie";
|
||||
|
||||
import { GlobalViewerCID } from "~/components/core/viewers/GlobalViewerCID";
|
||||
import { dispatchCustomEvent } from "~/common/custom-events";
|
||||
import { Alert } from "~/components/core/Alert";
|
||||
import { Alert, UploadingAlert } from "~/components/core/Alert";
|
||||
|
||||
const cookies = new Cookies();
|
||||
|
||||
@ -147,6 +147,7 @@ export default class ApplicationPage extends React.Component {
|
||||
};
|
||||
|
||||
_handleDrop = async (e) => {
|
||||
this._handleDismissSidebar();
|
||||
// NOTE(jim): If this is true, then drag and drop came from a slate object.
|
||||
const data = e.dataTransfer.getData("slate-object-drag-data");
|
||||
if (data) {
|
||||
@ -155,8 +156,6 @@ export default class ApplicationPage extends React.Component {
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
this.setState({ fileLoading: true });
|
||||
|
||||
// TODO(jim): Refactor later
|
||||
const navigation = NavigationData.generate(this.state.viewer);
|
||||
const next = this.state.history[this.state.currentIndex];
|
||||
@ -169,20 +168,20 @@ export default class ApplicationPage extends React.Component {
|
||||
|
||||
const files = [];
|
||||
let fileLoading = {};
|
||||
let sidebarOpen = false;
|
||||
// let sidebarOpen = false;
|
||||
if (e.dataTransfer.items && e.dataTransfer.items.length) {
|
||||
for (var i = 0; i < e.dataTransfer.items.length; i++) {
|
||||
if (e.dataTransfer.items[i].kind === "file") {
|
||||
var file = e.dataTransfer.items[i].getAsFile();
|
||||
|
||||
if (!sidebarOpen) {
|
||||
this._handleAction({
|
||||
type: "SIDEBAR",
|
||||
value: "SIDEBAR_ADD_FILE_TO_BUCKET",
|
||||
data: slate,
|
||||
});
|
||||
sidebarOpen = true;
|
||||
}
|
||||
// if (!sidebarOpen) {
|
||||
// this._handleAction({
|
||||
// type: "SIDEBAR",
|
||||
// value: "SIDEBAR_ADD_FILE_TO_BUCKET",
|
||||
// data: slate,
|
||||
// });
|
||||
// sidebarOpen = true;
|
||||
// }
|
||||
|
||||
files.push(file);
|
||||
fileLoading[`${file.lastModified}-${file.name}`] = {
|
||||
@ -209,7 +208,7 @@ export default class ApplicationPage extends React.Component {
|
||||
// NOTE(jim): Stages each file.
|
||||
this._handleRegisterFileLoading({ fileLoading });
|
||||
|
||||
this._handleUpload({ files, slate });
|
||||
this._handleUpload({ files, slate, keys: Object.keys(fileLoading) });
|
||||
};
|
||||
|
||||
_handleUploadFiles = async ({ files, slate, bucketName }) => {
|
||||
@ -258,10 +257,15 @@ export default class ApplicationPage extends React.Component {
|
||||
return;
|
||||
}
|
||||
|
||||
this._handleUpload({ files: toUpload, slate, bucketName });
|
||||
this._handleUpload({
|
||||
files: toUpload,
|
||||
slate,
|
||||
bucketName,
|
||||
keys: Object.keys(fileLoading),
|
||||
});
|
||||
};
|
||||
|
||||
_handleUpload = async ({ files, slate, bucketName }) => {
|
||||
_handleUpload = async ({ files, slate, bucketName, keys }) => {
|
||||
if (!files || !files.length) {
|
||||
return null;
|
||||
}
|
||||
@ -284,67 +288,70 @@ export default class ApplicationPage extends React.Component {
|
||||
return null;
|
||||
}
|
||||
|
||||
Promise.allSettled(resolvedFiles)
|
||||
.then((responses) => {
|
||||
let succeeded = responses
|
||||
.filter((res) => {
|
||||
return res.status === "fulfilled" && res.value && !res.value.error;
|
||||
})
|
||||
.map((res) => res.value);
|
||||
if (slate && slate.id && succeeded && succeeded.length) {
|
||||
FileUtilities.uploadToSlate({ responses: succeeded, slate });
|
||||
}
|
||||
let responses = await Promise.allSettled(resolvedFiles);
|
||||
let succeeded = responses
|
||||
.filter((res) => {
|
||||
return res.status === "fulfilled" && res.value && !res.value.error;
|
||||
})
|
||||
.then(async () => {
|
||||
return await Actions.processPendingFiles();
|
||||
})
|
||||
.then(async (response) => {
|
||||
if (!response) {
|
||||
dispatchCustomEvent({
|
||||
name: "create-alert",
|
||||
detail: {
|
||||
alert: {
|
||||
message:
|
||||
"We encountered issues updating your uploaded files. Please try again",
|
||||
},
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (response.error) {
|
||||
dispatchCustomEvent({
|
||||
name: "create-alert",
|
||||
detail: {
|
||||
alert: {
|
||||
decorator: response.decorator,
|
||||
},
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
await this.rehydrate({ resetFiles: true });
|
||||
|
||||
dispatchCustomEvent({
|
||||
name: "remote-update-slate-screen",
|
||||
detail: {},
|
||||
});
|
||||
|
||||
const { added, skipped } = response.data;
|
||||
if (!added && !skipped) return;
|
||||
let message = `${added || 0} file${added !== 1 ? "s" : ""} uploaded. `;
|
||||
if (skipped) {
|
||||
message += `${skipped || 0} duplicate / existing file${
|
||||
added !== 1 ? "s were" : " was"
|
||||
} skipped.`;
|
||||
}
|
||||
dispatchCustomEvent({
|
||||
name: "create-alert",
|
||||
detail: {
|
||||
alert: { message, status: !added ? null : "INFO" },
|
||||
.map((res) => res.value);
|
||||
if (slate && slate.id && succeeded && succeeded.length) {
|
||||
await FileUtilities.uploadToSlate({ responses: succeeded, slate });
|
||||
}
|
||||
let processResponse = await Actions.processPendingFiles();
|
||||
if (!processResponse) {
|
||||
dispatchCustomEvent({
|
||||
name: "create-alert",
|
||||
detail: {
|
||||
alert: {
|
||||
message:
|
||||
"We encountered issues updating your uploaded files. Please try again",
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (processResponse.error) {
|
||||
dispatchCustomEvent({
|
||||
name: "create-alert",
|
||||
detail: {
|
||||
alert: {
|
||||
decorator: processResponse.decorator,
|
||||
},
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
await this.rehydrate({ resetFiles: true });
|
||||
|
||||
//NOTE(martina): to update the carousel to include the new file if you're on the data view page
|
||||
dispatchCustomEvent({
|
||||
name: "remote-update-carousel",
|
||||
detail: {},
|
||||
});
|
||||
|
||||
//NOTE(martina): to update the slate to include the new file if you're on a slate page
|
||||
dispatchCustomEvent({
|
||||
name: "remote-update-slate-screen",
|
||||
detail: {},
|
||||
});
|
||||
|
||||
if (!slate) {
|
||||
const { added, skipped } = processResponse.data;
|
||||
if (!added && !skipped) return;
|
||||
let message = `${added || 0} file${added !== 1 ? "s" : ""} uploaded. `;
|
||||
if (skipped) {
|
||||
message += `${skipped || 0} duplicate / existing file${
|
||||
added !== 1 ? "s were" : " was"
|
||||
} skipped.`;
|
||||
}
|
||||
dispatchCustomEvent({
|
||||
name: "create-alert",
|
||||
detail: {
|
||||
alert: { message, status: !added ? null : "INFO" },
|
||||
},
|
||||
});
|
||||
}
|
||||
this._handleRegisterLoadingFinished({ keys });
|
||||
};
|
||||
|
||||
_handleRegisterFileLoading = ({ fileLoading }) => {
|
||||
@ -358,6 +365,14 @@ export default class ApplicationPage extends React.Component {
|
||||
});
|
||||
};
|
||||
|
||||
_handleRegisterLoadingFinished = ({ keys }) => {
|
||||
let fileLoading = this.state.fileLoading;
|
||||
for (let key of keys) {
|
||||
delete fileLoading[key];
|
||||
}
|
||||
this.setState({ fileLoading });
|
||||
};
|
||||
|
||||
_handleDragEnter = (e) => {
|
||||
e.preventDefault();
|
||||
if (this.state.sidebar) {
|
||||
@ -411,7 +426,6 @@ export default class ApplicationPage extends React.Component {
|
||||
};
|
||||
|
||||
if (options && options.resetFiles) {
|
||||
updates.fileLoading = null;
|
||||
updates.sidebar = null;
|
||||
}
|
||||
|
||||
@ -767,10 +781,12 @@ export default class ApplicationPage extends React.Component {
|
||||
url={url}
|
||||
>
|
||||
<ApplicationLayout
|
||||
onAction={this._handleAction}
|
||||
header={headerElement}
|
||||
navigation={navigationElement}
|
||||
sidebar={sidebarElement}
|
||||
onDismissSidebar={this._handleDismissSidebar}
|
||||
fileLoading={this.state.fileLoading}
|
||||
>
|
||||
{scene}
|
||||
</ApplicationLayout>
|
||||
|
@ -35,7 +35,15 @@ const STYLES_APPLICATION_HEADER = css`
|
||||
height: 56px;
|
||||
padding: 12px 48px 0 36px;
|
||||
pointer-events: none;
|
||||
background: ${Constants.system.white};
|
||||
background-color: ${Constants.system.white};
|
||||
|
||||
@supports (
|
||||
(-webkit-backdrop-filter: blur(25px)) or (backdrop-filter: blur(25px))
|
||||
) {
|
||||
-webkit-backdrop-filter: blur(25px);
|
||||
backdrop-filter: blur(25px);
|
||||
background-color: rgba(255, 255, 255, 0.75);
|
||||
}
|
||||
|
||||
@media (max-width: ${Constants.sizes.mobile}px) {
|
||||
padding: 12px 24px 0 12px;
|
||||
|
@ -205,6 +205,8 @@ export default class ApplicationLayout extends React.Component {
|
||||
id="slate-client-body"
|
||||
>
|
||||
<Alert
|
||||
fileLoading={this.props.fileLoading}
|
||||
onAction={this.props.onAction}
|
||||
style={{
|
||||
paddingRight: this.props.sidebar
|
||||
? `calc(${Constants.sizes.sidebar}px + 48px`
|
||||
@ -215,6 +217,8 @@ export default class ApplicationLayout extends React.Component {
|
||||
</div>
|
||||
<div css={STYLES_BODY_MOBILE}>
|
||||
<Alert
|
||||
fileLoading={this.props.fileLoading}
|
||||
onAction={this.props.onAction}
|
||||
style={{
|
||||
top: 0,
|
||||
left: 0,
|
||||
|
@ -68,14 +68,15 @@ const STYLES_ICONS = css`
|
||||
`;
|
||||
|
||||
export default class SidebarAddFileToBucket extends React.Component {
|
||||
_handleUpload = async (e) => {
|
||||
await this.props.onUpload({
|
||||
_handleUpload = (e) => {
|
||||
this.props.onUpload({
|
||||
files: e.target.files,
|
||||
slate:
|
||||
this.props.current && this.props.current.slateId
|
||||
? { id: this.props.current.slateId }
|
||||
: null,
|
||||
});
|
||||
this.props.onCancel();
|
||||
};
|
||||
|
||||
render() {
|
||||
@ -142,7 +143,8 @@ export default class SidebarAddFileToBucket extends React.Component {
|
||||
</System.ButtonPrimary>
|
||||
|
||||
<br />
|
||||
{this.props.fileLoading ? (
|
||||
{this.props.fileLoading &&
|
||||
Object.keys(this.props.fileLoading).length ? (
|
||||
<div css={STYLES_BAR_CONTAINER}>
|
||||
<strong css={STYLES_PERFORMANCE}>
|
||||
{Strings.bytesToSize(loaded)} / {Strings.bytesToSize(total)}
|
||||
|
@ -51,6 +51,12 @@ export default class SidebarAddFileToSlate extends React.Component {
|
||||
selected: {},
|
||||
};
|
||||
|
||||
componentDidMount = () => {
|
||||
if (!this.props.sidebarData || !this.props.sidebarData.files) {
|
||||
this.props.onCancel();
|
||||
}
|
||||
};
|
||||
|
||||
_handleCreateSlate = async () => {
|
||||
if (
|
||||
Object.values(this.state.selected).some((value) => {
|
||||
@ -140,8 +146,7 @@ export default class SidebarAddFileToSlate extends React.Component {
|
||||
marginBottom: "64px",
|
||||
}}
|
||||
>
|
||||
Add {this.props.sidebarData.files.length || 0} file
|
||||
{this.props.sidebarData.files.length === 1 ? "" : "s"} to slate
|
||||
Add files to slate
|
||||
</System.P>
|
||||
|
||||
<System.P css={STYLES_HEADER}>Slates</System.P>
|
||||
|
Loading…
Reference in New Issue
Block a user