Skip to content
This repository has been archived by the owner on Apr 25, 2023. It is now read-only.

feat: public settings page #32

Merged
merged 16 commits into from
Jul 16, 2021
Merged
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
2 changes: 2 additions & 0 deletions src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import AssetSettings from "@reearth/components/pages/Settings/Workspace/Asset";
import ProjectSettings from "@reearth/components/pages/Settings/Project";
import SettingsProjectList from "@reearth/components/pages/Settings/ProjectList";
import WorkspaceList from "@reearth/components/pages/Settings/WorkspaceList";
import PublicSettings from "@reearth/components/pages/Settings/Project/Public";
import DatasetSettings from "@reearth/components/pages/Settings/Project/Dataset";
import PluginSettings from "@reearth/components/pages/Settings/Project/Plugin";
import Preview from "./components/pages/Preview";
Expand Down Expand Up @@ -62,6 +63,7 @@ const App: React.FC = () => {
<SettingsProjectList path="/settings/workspace/:teamId/projects" />
<AssetSettings path="/settings/workspace/:teamId/asset" />
<ProjectSettings path="/settings/project/:projectId" />
<PublicSettings path="/settings/project/:projectId/public" />
<DatasetSettings path="/settings/project/:projectId/dataset" />
<PluginSettings path="/settings/project/:projectId/plugins" />
<NotFound default />
Expand Down
7 changes: 6 additions & 1 deletion src/components/molecules/Settings/Navigation/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type Team = {
type Project = {
id?: string;
name?: string;
isArchived?: boolean;
};

type Props = {
Expand Down Expand Up @@ -55,8 +56,12 @@ const Navigation: React.FC<Props> = ({ team, project }) => {
<NavigationItem
to={`/settings/workspace/${team?.id}/projects`}
name={intl.formatMessage({ defaultMessage: "Project List" })}>
{project && (
{project && !project.isArchived && (
<NavigationItem to={`/settings/project/${project.id}`} name={project.name as string}>
<NavigationItem
to={`/settings/project/${project.id}/public`}
name={intl.formatMessage({ defaultMessage: "Public" })}
/>
<NavigationItem
to={`/settings/project/${project.id}/dataset`}
name={intl.formatMessage({ defaultMessage: "Dataset" })}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const ArchivedMessage: React.FC = () => {
<Description>
{intl.formatMessage({
defaultMessage:
"Most project settings are hidden for archived repositories. This project mus be unarchived to make changes to them.",
"Most project settings are hidden when the project is archived. Please unarchive the project to view and edit these settings.",
})}
</Description>
</Section>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,13 @@ const DangerSection: React.FC<Props> = ({ project, teamId, archiveProject, delet
}
/>
<Divider /> */}
<Field header={intl.formatMessage({ defaultMessage: "Archive this project" })} />
<Field
header={
project?.isArchived
? intl.formatMessage({ defaultMessage: "Unarchive this project" })
: intl.formatMessage({ defaultMessage: "Archive this project" })
}
/>
<Field
body={
project?.isArchived
Expand All @@ -64,8 +70,8 @@ const DangerSection: React.FC<Props> = ({ project, teamId, archiveProject, delet
large
text={
project?.isArchived
? intl.formatMessage({ defaultMessage: "Unarchive this project" })
: intl.formatMessage({ defaultMessage: "Archive this project" })
? intl.formatMessage({ defaultMessage: "Unarchive project" })
: intl.formatMessage({ defaultMessage: "Archive project" })
}
onClick={() => openModal(project?.isArchived ? "unarchive" : "archive")}
buttonType="danger"
Expand All @@ -76,12 +82,12 @@ const DangerSection: React.FC<Props> = ({ project, teamId, archiveProject, delet
<Field header={intl.formatMessage({ defaultMessage: "Delete this project" })} />
<Field
body={intl.formatMessage({
defaultMessage: `Once you delete a project, there is no going back. Please be certain.`,
defaultMessage: `Once you delete a project, there is no going back. Please be sure.`,
})}
action={
<Button
large
text={intl.formatMessage({ defaultMessage: "Delete this project" })}
text={intl.formatMessage({ defaultMessage: "Delete project" })}
buttonType="danger"
onClick={() => openModal("delete")}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,17 @@ import DatasetList, {

type Props = {
datasetSchemas: Item[];
importDataset: (file: FileList) => void;
removeDatasetSchema: (schemaId: string) => void;
onDatasetImport?: (file: File, datasetSchemaId: string | null) => void | Promise<void>;
};

const DatasetSection: React.FC<Props> = ({
datasetSchemas,
importDataset,
removeDatasetSchema,
onDatasetImport,
}) => {
const intl = useIntl();
const handleFileSelect = useFileInput(files => importDataset?.(files), {
const handleFileSelect = useFileInput(files => onDatasetImport?.(files[0], null), {
multiple: false,
accept: "text/csv",
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import React, { useCallback, useState } from "react";
import Section from "@reearth/components/molecules/Settings/Section";
import EditableItem from "@reearth/components/molecules/Settings/Project/EditableItem";
import AssetModal, { Asset as AssetType } from "@reearth/components/molecules/Common/AssetModal";
import { styled } from "@reearth/theme";
import { useIntl } from "react-intl";

export type Asset = AssetType;

export type Props = {
currentProject?: {
id: string;
publicTitle: string;
publicDescription: string;
publicImageUrl?: string;
};
updatePublicTitle?: (title: string) => void;
updatePublicDescription?: (description: string) => void;
updatePublicImage?: (imageUrl: string | null) => void;
assets?: Asset[];
createAssets?: (files: FileList) => Promise<void>;
};

const PublicSection: React.FC<Props> = ({
currentProject,
updatePublicTitle,
updatePublicDescription,
updatePublicImage,
assets,
createAssets,
}) => {
const intl = useIntl();
const [isAssetModalOpen, setAssetModalOpen] = useState(false);
const openAssetModal = useCallback(() => setAssetModalOpen(true), []);
const closeAssetModal = useCallback(() => setAssetModalOpen(false), []);

return (
<Wrapper>
<Section
title={intl.formatMessage({ defaultMessage: "Public Info" })}
subtitle={intl.formatMessage({
defaultMessage:
"(These fields will be used for OGP as well as metadata for the public project)",
})}>
<EditableItem
title={intl.formatMessage({ defaultMessage: "Title" })}
body={currentProject?.publicTitle}
onSubmit={updatePublicTitle}
/>
<EditableItem
title={intl.formatMessage({ defaultMessage: "Description" })}
body={currentProject?.publicDescription}
multilineTextBox={true}
onSubmit={updatePublicDescription}
/>
<EditableItem
title={intl.formatMessage({ defaultMessage: "Thumbnail" })}
onSubmit={updatePublicImage}
imageSrc={currentProject?.publicImageUrl as string}
isImage
onEditStart={() => openAssetModal()}
onEditCancel={() => closeAssetModal()}
/>
</Section>
<AssetModal
isOpen={isAssetModalOpen}
onClose={closeAssetModal}
assets={assets}
fileType="image"
onCreateAsset={createAssets}
onSelect={updatePublicImage}
value={currentProject?.publicImageUrl as string | undefined}
/>
</Wrapper>
);
};

const Wrapper = styled.div`
background-color: ${props => props.theme.colors.bg[3]};
`;

export default PublicSection;
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ const PublishSection: React.FC<Props> = ({
}) => {
const url = window.REEARTH_CONFIG?.published?.split("{}");

// const [customUrlState, setCustomUrlState] = useState("");
const [showDModal, setDModal] = useState(false);
const intl = useIntl();
const theme = useTheme();
Expand Down Expand Up @@ -76,10 +75,14 @@ const PublishSection: React.FC<Props> = ({
{intl.formatMessage({ defaultMessage: "Site name" })}
</StyledText>
<Text size="s">
{intl.formatMessage({
defaultMessage:
"By default, once published your project will be accessible via the URL below.",
})}
{alias
? intl.formatMessage({
defaultMessage: "Access your project, copy or edit the URL below.",
})
: intl.formatMessage({
defaultMessage:
"Once your project is published from the editor page the URL details will be shown here.",
})}
</Text>
{alias && (
<StyledItem
Expand Down
40 changes: 23 additions & 17 deletions src/components/molecules/Settings/Section/index.tsx
Original file line number Diff line number Diff line change
@@ -1,47 +1,53 @@
import React from "react";
import { styled, useTheme } from "@reearth/theme";
import Text from "@reearth/components/atoms/Text";
import Flex from "@reearth/components/atoms/Flex";
import Divider from "@reearth/components/atoms/Divider";
import { metricsSizes } from "@reearth/theme/metrics";

export type Props = {
title?: string;
subtitle?: string;
actions?: React.ReactNode;
};

const Section: React.FC<Props> = ({ title, actions, children }) => {
const Section: React.FC<Props> = ({ title, subtitle, actions, children }) => {
const theme = useTheme();
return (
<div>
{title && (
<>
<SectionHeader>
<Text size="l" weight="normal" color={theme.main.strongText}>
{title}
</Text>
<SectionHeader justify="space-between">
<Flex direction="column">
<Text size="l" weight="normal" color={theme.main.strongText}>
{title}
</Text>
{subtitle && (
<Text
size="s"
weight="normal"
color={theme.main.text}
otherProperties={{ marginTop: metricsSizes["2xs"] + "px" }}>
{subtitle}
</Text>
)}
</Flex>
{actions}
</SectionHeader>
<Divider />
<Divider margin="0" />
</>
)}
<SectionItem>{children}</SectionItem>
<SectionItem direction="column">{children}</SectionItem>
</div>
);
};

const SectionHeader = styled.div`
const SectionHeader = styled(Flex)`
padding: ${metricsSizes["l"]}px ${metricsSizes["2xl"]}px;
display: flex;
justify-content: space-between;
`;

const SectionItem = styled.div`
const SectionItem = styled(Flex)`
padding: ${metricsSizes["l"]}px ${metricsSizes["2xl"]}px;
display: flex;
flex-direction: column;
`;

const Divider = styled.div`
border-bottom: ${props => `solid 1px ${props.theme.colors.outline.weak}`};
`;

export default Section;
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const DangerSection: React.FC<Props> = ({ team, deleteTeam }) => {
action={
<Button
large
text={intl.formatMessage({ defaultMessage: "Delete this workspace" })}
text={intl.formatMessage({ defaultMessage: "Delete workspace" })}
buttonType="danger"
onClick={() => setIsOpen(true)}
/>
Expand Down
51 changes: 37 additions & 14 deletions src/components/organisms/Settings/Project/Dataset/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
useImportDatasetMutation,
useRemoveDatasetMutation,
} from "@reearth/gql";
import { useApolloClient } from "@apollo/client";

type Nodes = NonNullable<DatasetSchemasQuery["scene"]>["datasetSchemas"]["nodes"];

Expand All @@ -25,33 +26,55 @@ export default (projectId: string) => {

const sceneId = sceneData?.scene?.id;

const { data, refetch } = useDatasetSchemasQuery({
const { data } = useDatasetSchemasQuery({
variables: { projectId: projectId ?? "" },
skip: !projectId,
});

const nodes = data?.scene?.datasetSchemas.nodes ?? [];

const datasetSchemas = nodes.filter(Boolean) as DatasetSchemas;
const client = useApolloClient();

const [importDatasetMutation] = useImportDatasetMutation();

const importDataset = useCallback(
(file: FileList) => {
sceneId && importDatasetMutation({ variables: { file, sceneId } });
const [removeDatasetSchema] = useRemoveDatasetMutation();
const handleRemoveDataset = useCallback(
async (schemaId: string) => {
await removeDatasetSchema({
variables: {
schemaId,
force: true,
},
});
// re-render
await client.resetStore();
},
[sceneId, importDatasetMutation],
[client, removeDatasetSchema],
);

const [removeDatasetSchemaMutation] = useRemoveDatasetMutation();
// Add
const [importData] = useImportDatasetMutation();

const removeDatasetSchema = useCallback(
async (schemaId: string) => {
await removeDatasetSchemaMutation({ variables: { schemaId } });
await refetch();
const handleDatasetImport = useCallback(
async (file: File, schemeId: string | null) => {
if (!sceneId) return;
await importData({
variables: {
file,
sceneId,
datasetSchemaId: schemeId,
},
});
// re-render
await client.resetStore();
},
[removeDatasetSchemaMutation, refetch],
[client, importData, sceneId],
);

return { currentTeam, currentProject, datasetSchemas, importDataset, removeDatasetSchema };
return {
currentTeam,
currentProject,
datasetSchemas,
handleDatasetImport,
handleRemoveDataset,
};
};
Loading