Skip to content

Commit

Permalink
Feat: add a top-right share-button on the repo page (#152)
Browse files Browse the repository at this point in the history
  • Loading branch information
li-xin-yi authored Dec 16, 2022
1 parent aa68a9e commit a03da22
Show file tree
Hide file tree
Showing 13 changed files with 592 additions and 92 deletions.
7 changes: 7 additions & 0 deletions api/src/resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@ import {
createRepo,
deletePod,
deleteRepo,
deleteCollaborator,
myRepos,
myCollabRepos,
getVisibility,
updateVisibility,
addCollaborator,
pod,
repo,
Expand Down Expand Up @@ -50,7 +53,9 @@ export const resolvers = {
repo,
pod,
listAllRuntimes,
getVisibility,
myCollabRepos,

...(process.env.RUNTIME_SPAWNER === "k8s"
? {
infoRuntime: infoRuntime_k8s,
Expand All @@ -72,6 +77,8 @@ export const resolvers = {
updatePod,
deletePod,
addCollaborator,
updateVisibility,
deleteCollaborator,
...(process.env.RUNTIME_SPAWNER === "k8s"
? {
spawnRuntime: spawnRuntime_k8s,
Expand Down
57 changes: 57 additions & 0 deletions api/src/resolver_repo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,41 @@ export async function createRepo(_, { id, name, isPublic }, { userId }) {
return repo;
}

export async function getVisibility(_, { repoId }, { userId }) {
if (!userId) throw Error("Unauthenticated");
const repo = await prisma.repo.findFirst({
where: {
id: repoId,
owner: { id: userId || "undefined" }
},
include: {
collaborators: true,
},
});
if (!repo) throw Error("Repo not found");
return {collaborators: repo.collaborators, isPublic: repo.public};
}

export async function updateVisibility(_, { repoId, isPublic }, { userId }) {
if (!userId) throw Error("Unauthenticated");
const repo = await prisma.repo.findFirst({
where: {
id: repoId,
owner: { id: userId || "undefined" }
},
});
if (!repo) throw Error("Repo not found");
await prisma.repo.update({
where: {
id: repoId,
},
data: {
public: isPublic,
},
});
return true;
}

export async function updateRepo(_, { id, name }, { userId }) {
if (!userId) throw Error("Unauthenticated");
const repo = await prisma.repo.findFirst({
Expand Down Expand Up @@ -223,6 +258,28 @@ export async function addCollaborator(_, { repoId, email }, { userId }) {
return true;
}

export async function deleteCollaborator(_, { repoId, collaboratorId }, { userId }) {
if(!userId) throw new Error("Not authenticated.")
// 1. find the repo
const repo = await prisma.repo.findFirst({
where: {
id: repoId,
owner: { id: userId },
},
});
// 2. delete the user from the repo
if (!repo) throw new Error("Repo not found or you are not the owner.");
const res = await prisma.repo.update({
where: {
id: repoId,
},
data: {
collaborators: { disconnect: { id: collaboratorId } },
}
})
return true;
}

export async function addPod(_, { repoId, parent, index, input }, { userId }) {
// make sure the repo is writable by this user
if (!userId) throw new Error("Not authenticated.");
Expand Down
8 changes: 8 additions & 0 deletions api/src/typedefs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ export const typeDefs = gql`
lastname: String!
}
type Visibility {
collaborators: [User]
isPublic: Boolean
}
type Repo {
id: ID!
name: String
Expand Down Expand Up @@ -92,6 +97,7 @@ export const typeDefs = gql`
pod(id: ID!): Pod
myRepos: [Repo]
activeSessions: [String]
getVisibility(repoId: String): Visibility
listAllRuntimes: [RuntimeInfo]
myCollabRepos: [Repo]
infoRuntime(sessionId: String!): RuntimeInfo
Expand All @@ -118,6 +124,8 @@ export const typeDefs = gql`
clearPod: Boolean
spawnRuntime(sessionId: String): Boolean
killRuntime(sessionId: String!): Boolean
updateVisibility(repoId: String, isPublic: Boolean): Boolean
addCollaborator(repoId: String, email: String): Boolean
deleteCollaborator(repoId: String, collaboratorId: String): Boolean
}
`;
2 changes: 2 additions & 0 deletions ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"net": "^1.0.2",
"notistack": "^2.0.8",
"react": "^18.2.0",
"react-copy-to-clipboard": "^5.1.0",
"react-dom": "^18.2.0",
"react-icons": "^4.6.0",
"react-monaco-editor": "^0.50.1",
Expand Down Expand Up @@ -85,6 +86,7 @@
]
},
"devDependencies": {
"@types/react-copy-to-clipboard": "^5.0.4",
"@types/react-resizable": "^3.0.3",
"babel-plugin-named-exports-order": "^0.0.2",
"prop-types": "^15.8.1",
Expand Down
13 changes: 4 additions & 9 deletions ui/src/components/Canvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -739,12 +739,12 @@ export function Canvas() {
// const pods = useStore(store, (state) => state.pods);
const getPod = useStore(store, (state) => state.getPod);
const nodesMap = useStore(store, (state) => state.ydoc.getMap<Node>("pods"));
const [showShareDialog, setShowShareDialog] = useState(false);
const repoId = useStore(store, (state) => state.repoId);
const repoName = useStore(store, (state) => state.repoName);
const role = useStore(store, (state) => state.role);
const provider = useStore(store, (state) => state.provider);
const isMac = navigator.platform.toUpperCase().indexOf("MAC") >= 0;
const shareOpen = useStore(store, (state) => state.shareOpen);
const setShareOpen = useStore(store, (state) => state.setShareOpen);

const getRealNodes = useCallback(
(id: string, level: number) => {
Expand Down Expand Up @@ -1163,16 +1163,11 @@ export function Canvas() {
addCode={() => addNode(client.x, client.y, "code")}
addScope={() => addNode(client.x, client.y, "scope")}
onShareClick={() => {
setShowShareDialog(true);
setShareOpen(true);
}}
/>
)}
<ShareProjDialog
open={showShareDialog}
onClose={() => setShowShareDialog(false)}
title={repoName || ""}
id={repoId || ""}
/>
{shareOpen && <ShareProjDialog open={shareOpen} id={repoId || ""} />}
</Box>
</Box>
);
Expand Down
9 changes: 0 additions & 9 deletions ui/src/components/CanvasContextMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import React, { useContext } from "react";
import CodeIcon from "@mui/icons-material/Code";
import PostAddIcon from "@mui/icons-material/PostAdd";
import FormatListNumberedIcon from "@mui/icons-material/FormatListNumbered";
import ShareOutlinedIcon from "@mui/icons-material/ShareOutlined";

const paneMenuStyle = (left, top) => {
return {
Expand Down Expand Up @@ -68,14 +67,6 @@ export function CanvasContextMenu(props) {
{showLineNumbers ? "Hide " : "Show "} Line Numbers
</ListItemText>
</MenuItem>
{role === RoleType.OWNER && (
<MenuItem onClick={props.onShareClick} sx={ItemStyle}>
<ListItemIcon>
<ShareOutlinedIcon />
</ListItemIcon>
<ListItemText> Share with Collaborators </ListItemText>
</MenuItem>
)}
</MenuList>
</Box>
);
Expand Down
12 changes: 12 additions & 0 deletions ui/src/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,15 @@ type HeaderProps = {
drawerWidth?: number;
currentPage?: string | null;
breadcrumbItem?: React.ReactNode;
shareButton?: React.ReactNode;
};

export const Header: React.FC<HeaderProps> = ({
open = false,
drawerWidth = 0,
currentPage = null,
breadcrumbItem = null,
shareButton = null,
}) => {
const [anchorElNav, setAnchorElNav] = useState(null);
const [anchorElUser, setAnchorElUser] = useState(null);
Expand Down Expand Up @@ -94,6 +96,16 @@ export const Header: React.FC<HeaderProps> = ({
{breadcrumbItem}
</Breadcrumbs>

<Box
sx={{
display: { xs: "none", md: "flex" },
alignItems: "center",
paddingRight: "10px",
}}
>
{shareButton}
</Box>

{/* The navigation on desktop */}
<Box
sx={{
Expand Down
Loading

0 comments on commit a03da22

Please sign in to comment.