Skip to content

Commit

Permalink
feat(web): project recycle bin (#1181)
Browse files Browse the repository at this point in the history
Co-authored-by: tomokazu tantaka <[email protected]>
  • Loading branch information
mkumbobeaty and tomokazu tantaka authored Oct 24, 2024
1 parent b922fbb commit 0fde95b
Show file tree
Hide file tree
Showing 36 changed files with 990 additions and 203 deletions.
82 changes: 50 additions & 32 deletions server/e2e/gql_project_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,10 +210,15 @@ func TestFindStarredByWorkspace(t *testing.T) {
project2ID := createProject(e, "Project 2")
project3ID := createProject(e, "Project 3")
project4ID := createProject(e, "Project 4")
project5ID := createProject(e, "Project 5")

starProject(e, project1ID)
starProject(e, project3ID)

// star and deleted 'Project 5'
starProject(e, project5ID)
deleteProject(e, project5ID)

requestBody := GraphQLRequest{
OperationName: "GetStarredProjects",
Query: `
Expand Down Expand Up @@ -251,6 +256,8 @@ func TestFindStarredByWorkspace(t *testing.T) {
nodeCount := int(nodes.Length().Raw())
assert.Equal(t, 2, nodeCount, "Expected 2 nodes in the response")

nodes.Length().Equal(2) // 'Project 1' and 'Project 3'

starredProjectsMap := make(map[string]bool)
for _, node := range nodes.Iter() {
obj := node.Object()
Expand All @@ -275,7 +282,6 @@ func TestFindStarredByWorkspace(t *testing.T) {
assert.True(t, starredProjectsMap[project3ID], "Project 3 should be starred")
assert.False(t, starredProjectsMap[project2ID], "Project 2 should not be starred")
assert.False(t, starredProjectsMap[project4ID], "Project 4 should not be starred")

}

func starProject(e *httpexpect.Expect, projectID string) {
Expand Down Expand Up @@ -467,39 +473,10 @@ func TestDeleteProjects(t *testing.T) {
createProject(e, "project3-test")

// Deleted 'project2'
requestBody := GraphQLRequest{
OperationName: "UpdateProject",
Query: `mutation UpdateProject($input: UpdateProjectInput!) {
updateProject(input: $input) {
project {
id
name
isDeleted
updatedAt
__typename
}
__typename
}
}`,
Variables: map[string]any{
"input": map[string]any{
"projectId": project2ID,
"deleted": true,
},
},
}

e.POST("/api/graphql").
WithHeader("Origin", "https://example.com").
WithHeader("X-Reearth-Debug-User", uID.String()).
WithHeader("Content-Type", "application/json").
WithJSON(requestBody).
Expect().
Status(http.StatusOK).
JSON()
deleteProject(e, project2ID)

// check
requestBody = GraphQLRequest{
requestBody := GraphQLRequest{
OperationName: "GetDeletedProjects",
Query: `
query GetDeletedProjects($teamId: ID!) {
Expand Down Expand Up @@ -530,3 +507,44 @@ func TestDeleteProjects(t *testing.T) {
deletedProjects.Value("nodes").Array().Length().Equal(1)
deletedProjects.Value("nodes").Array().First().Object().Value("name").Equal("project2-test")
}

func deleteProject(e *httpexpect.Expect, projectID string) {

updateProjectMutation := GraphQLRequest{
OperationName: "UpdateProject",
Query: `mutation UpdateProject($input: UpdateProjectInput!) {
updateProject(input: $input) {
project {
id
name
isDeleted
updatedAt
__typename
}
__typename
}
}`,
Variables: map[string]any{
"input": map[string]any{
"projectId": projectID,
"deleted": true,
},
},
}

response := e.POST("/api/graphql").
WithHeader("Origin", "https://example.com").
WithHeader("X-Reearth-Debug-User", uID.String()).
WithHeader("Content-Type", "application/json").
WithJSON(updateProjectMutation).
Expect().
Status(http.StatusOK).
JSON().
Object().
Value("data").Object().
Value("updateProject").Object().
Value("project").Object()

response.ValueEqual("id", projectID).
ValueEqual("isDeleted", true)
}
1 change: 1 addition & 0 deletions server/internal/adapter/gql/gqlmodel/convert_project.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ func ToProject(p *project.Project) *Project {
EnableGa: p.EnableGA(),
TrackingID: p.TrackingID(),
Starred: p.Starred(),
IsDeleted: p.IsDeleted(),
}
}

Expand Down
1 change: 1 addition & 0 deletions server/internal/infrastructure/mongo/mongodoc/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,5 +128,6 @@ func (d *ProjectDocument) Model() (*project.Project, error) {
TrackingID(d.TrackingID).
// Scene(scene).
Starred(d.Starred).
Deleted(d.Deleted).
Build()
}
4 changes: 4 additions & 0 deletions server/internal/infrastructure/mongo/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ func (r *Project) FindStarredByWorkspace(ctx context.Context, id accountdomain.W
filter := bson.M{
"team": id.String(),
"starred": true,
"$or": []bson.M{
{"deleted": false},
{"deleted": bson.M{"$exists": false}},
},
}

return r.find(ctx, filter)
Expand Down
5 changes: 5 additions & 0 deletions server/pkg/project/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,3 +161,8 @@ func (b *Builder) Starred(starred bool) *Builder {
b.p.starred = starred
return b
}

func (b *Builder) Deleted(deleted bool) *Builder {
b.p.isDeleted = deleted
return b
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { Button, PopupMenu, TextInput } from "@reearth/beta/lib/reearth-ui";
import { styled, useTheme } from "@reearth/services/theme";
import { FC } from "react";

import ProjectRemoveModal from "../ProjectRemoveModal";

import useHooks from "./hooks";
import { ProjectProps } from "./types";

Expand All @@ -10,7 +12,8 @@ const ProjectGridViewItem: FC<ProjectProps> = ({
selectedProjectId,
onProjectOpen,
onProjectSelect,
onProjectUpdate
onProjectUpdate,
onProjectRemove
}) => {
const theme = useTheme();

Expand All @@ -21,19 +24,23 @@ const ProjectGridViewItem: FC<ProjectProps> = ({
isHovered,
isStarred,
hasMapOrStoryPublished,
projectRemoveModalVisible,
handleProjectNameChange,
handleProjectNameBlur,
handleProjectHover,
handleProjectNameDoubleClick,
handleProjectStarClick
handleProjectStarClick,
handleProjectRemoveModal,
handleProjectRemove
// exportModalVisible,
// closeExportModal,
// handleExportProject
} = useHooks({
project,
selectedProjectId,
onProjectUpdate,
onProjectSelect
onProjectSelect,
onProjectRemove
});

return (
Expand Down Expand Up @@ -87,6 +94,13 @@ const ProjectGridViewItem: FC<ProjectProps> = ({
/>
</CardFooter>
</Card>
{projectRemoveModalVisible && (
<ProjectRemoveModal
isVisible={projectRemoveModalVisible}
onClose={() => handleProjectRemoveModal(false)}
onProjectRemove={() => handleProjectRemove(project.id)}
/>
)}
{/* MEMO: this modal will be used in the future */}
{/* <Modal visible={exportModalVisible} size="small">
<ModalPanel
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { formatRelativeTime } from "@reearth/beta/utils/time";
import { styled, useTheme } from "@reearth/services/theme";
import { FC, MouseEvent, useMemo } from "react";

import ProjectRemoveModal from "../ProjectRemoveModal";

import useHooks from "./hooks";
import { ProjectProps } from "./types";

Expand All @@ -16,7 +18,8 @@ const ProjectListViewItem: FC<ProjectProps> = ({
selectedProjectId,
onProjectOpen,
onProjectSelect,
onProjectUpdate
onProjectUpdate,
onProjectRemove
}) => {
const theme = useTheme();

Expand All @@ -38,19 +41,23 @@ const ProjectListViewItem: FC<ProjectProps> = ({
isHovered,
isStarred,
hasMapOrStoryPublished,
projectRemoveModalVisible,
handleProjectNameChange,
handleProjectNameBlur,
handleProjectHover,
handleProjectNameDoubleClick,
handleProjectStarClick
handleProjectStarClick,
handleProjectRemoveModal,
handleProjectRemove
// exportModalVisible,
// closeExportModal,
// handleExportProject
} = useHooks({
project,
selectedProjectId,
onProjectUpdate,
onProjectSelect
onProjectSelect,
onProjectRemove
});

return (
Expand Down Expand Up @@ -116,6 +123,13 @@ const ProjectListViewItem: FC<ProjectProps> = ({
/>
</ActionCol>
</ListWrapper>
{projectRemoveModalVisible && (
<ProjectRemoveModal
isVisible={projectRemoveModalVisible}
onClose={() => handleProjectRemoveModal(false)}
onProjectRemove={() => handleProjectRemove(project.id)}
/>
)}
{/* MEMO: this modal will be used in the future */}
{/* <Modal visible={exportModalVisible} size="small">
<ModalPanel
Expand Down
Loading

0 comments on commit 0fde95b

Please sign in to comment.