Files
plane/web/core/components/integration/github/single-user-select.tsx
T
7e334203f1 [WEB-310] dev: private bucket implementation (#5793)
* chore: migrations and backmigration to move attachments to file asset

* chore: move attachments to file assets

* chore: update migration file to include created by and updated by and size

* chore: remove uninmport errors

* chore: make size as float field

* fix: file asset uploads

* chore: asset uploads migration changes

* chore: v2 assets endpoint

* chore: remove unused imports

* chore: issue attachments

* chore: issue attachments

* chore: workspace logo endpoints

* chore: private bucket changes

* chore: user asset endpoint

* chore: add logo_url validation

* chore: cover image urlk

* chore: change asset max length

* chore: pages endpoint

* chore: store the storage_metadata only when none

* chore: attachment asset apis

* chore: update create private bucket

* chore: make bucket private

* chore: fix response of user uploads

* fix: response of user uploads

* fix: job to fix file asset uploads

* fix: user asset endpoints

* chore: avatar for user profile

* chore: external apis user url endpoint

* chore: upload workspace and user asset actions updated

* chore: analytics endpoint

* fix: analytics export

* chore: avatar urls

* chore: update user avatar instances

* chore: avatar urls for assignees and creators

* chore: bucket permission script

* fix: all user avatr instances in the web app

* chore: update project cover image logic

* fix: issue attachment endpoint

* chore: patch endpoint for issue attachment

* chore: attachments

* chore: change attachment storage class

* chore: update issue attachment endpoints

* fix: issue attachment

* chore: update issue attachment implementation

* chore: page asset endpoints

* fix: web build errors

* chore: attachments

* chore: page asset urls

* chore: comment and issue asset endpoints

* chore: asset endpoints

* chore: attachment endpoints

* chore: bulk asset endpoint

* chore: restore endpoint

* chore: project assets endpoints

* chore: asset url

* chore: add delete asset endpoints

* chore: fix asset upload endpoint

* chore: update patch endpoints

* chore: update patch endpoint

* chore: update editor image handling

* chore: asset restore endpoints

* chore: avatar url for space assets

* chore: space app assets migration

* fix: space app urls

* chore: space endpoints

* fix: old editor images rendering logic

* fix: issue archive and attachment activity

* chore: asset deletes

* chore: attachment delete

* fix: issue attachment

* fix: issue attachment get

* chore: cover image url for projects

* chore: remove duplicate py file

* fix: url check function

* chore: chore project cover asset delete

* fix: migrations

* chore: delete migration files

* chore: update bucket

* fix: build errors

* chore: add asset url in intake attachment

* chore: project cover fix

* chore: update next.config

* chore: delete old workspace logos

* chore: workspace assets

* chore: asset get for space

* chore: update project modal

* chore: remove unused imports

* fix: space app editor helper

* chore: update rich-text read-only editor

* chore: create multiple column for entity identifiers

* chore: update migrations

* chore: remove entity identifier

* fix: issue assets

* chore: update maximum file size logic

* chore: update editor max file size logic

* fix: close modal after removing workspace logo

* chore: update uploaded asstes' status post issue creation

* chore: added file size limit to the space app

* dev: add file size limit restriction on all endpoints

* fix: remove old workspace logo and user avatar

---------

Co-authored-by: pablohashescobar <[email protected]>
2024-10-11 20:13:38 +05:30

136 lines
3.9 KiB
TypeScript

"use client";
import { useParams } from "next/navigation";
import useSWR from "swr";
// plane types
import { IGithubRepoCollaborator } from "@plane/types";
// plane ui
import { Avatar, CustomSelect, CustomSearchSelect, Input } from "@plane/ui";
// constants
import { WORKSPACE_MEMBERS } from "@/constants/fetch-keys";
// helpers
import { getFileURL } from "@/helpers/file.helper";
// plane web services
import { WorkspaceService } from "@/plane-web/services";
// types
import { IUserDetails } from "./root";
type Props = {
collaborator: IGithubRepoCollaborator;
index: number;
users: IUserDetails[];
setUsers: React.Dispatch<React.SetStateAction<IUserDetails[]>>;
};
const importOptions = [
{
key: "map",
label: "Map to existing",
},
{
key: "invite",
label: "Invite by email",
},
{
key: false,
label: "Do not import",
},
];
// services
const workspaceService = new WorkspaceService();
export const SingleUserSelect: React.FC<Props> = ({ collaborator, index, users, setUsers }) => {
const { workspaceSlug } = useParams();
const { data: members } = useSWR(
workspaceSlug ? WORKSPACE_MEMBERS(workspaceSlug.toString()) : null,
workspaceSlug ? () => workspaceService.fetchWorkspaceMembers(workspaceSlug.toString()) : null
);
const options = members
?.map((member) => {
if (!member?.member) return;
return {
value: member.member?.display_name,
query: member.member?.display_name ?? "",
content: (
<div className="flex items-center gap-2">
<Avatar name={member?.member?.display_name} src={getFileURL(member?.member?.avatar_url)} />
{member.member?.display_name}
</div>
),
};
})
.filter((member) => !!member) as
| {
value: string;
query: string;
content: JSX.Element;
}[]
| undefined;
return (
<div className="grid grid-cols-3 items-center gap-2 rounded-md bg-custom-background-80 px-2 py-3">
<div className="flex items-center gap-2">
<div className="relative h-8 w-8 flex-shrink-0 rounded">
<img
src={collaborator.avatar_url}
className="absolute left-0 top-0 h-full w-full rounded object-cover"
alt={`${collaborator.login} GitHub user`}
/>
</div>
<p className="text-sm">{collaborator.login}</p>
</div>
<div>
<CustomSelect
value={users[index].import}
label={<div className="text-xs">{importOptions.find((o) => o.key === users[index].import)?.label}</div>}
onChange={(val: any) => {
const newUsers = [...users];
newUsers[index].import = val;
newUsers[index].email = "";
setUsers(newUsers);
}}
optionsClassName="w-full"
noChevron
>
{importOptions.map((option) => (
<CustomSelect.Option key={option.label} value={option.key}>
<div>{option.label}</div>
</CustomSelect.Option>
))}
</CustomSelect>
</div>
{users[index].import === "invite" && (
<Input
id="email"
type="email"
name={`userEmail${index}`}
value={users[index].email}
onChange={(e) => {
const newUsers = [...users];
newUsers[index].email = e.target.value;
setUsers(newUsers);
}}
placeholder="Enter email of the user"
className="w-full py-1 text-xs"
/>
)}
{users[index].import === "map" && members && (
<CustomSearchSelect
value={users[index].email}
label={users[index].email !== "" ? users[index].email : "Select user from project"}
options={options}
onChange={(val: string) => {
const newUsers = [...users];
newUsers[index].email = val;
setUsers(newUsers);
}}
optionsClassName="w-48"
/>
)}
</div>
);
};