mirror of
https://github.com/revoltchat/revite.git
synced 2024-11-25 16:40:58 -05:00
feat(categories): autosave category changes
This commit is contained in:
parent
da47348273
commit
bb5509f660
5 changed files with 371 additions and 214 deletions
|
@ -48,11 +48,11 @@ export type UploadState =
|
||||||
| { type: "none" }
|
| { type: "none" }
|
||||||
| { type: "attached"; files: File[] }
|
| { type: "attached"; files: File[] }
|
||||||
| {
|
| {
|
||||||
type: "uploading";
|
type: "uploading";
|
||||||
files: File[];
|
files: File[];
|
||||||
percent: number;
|
percent: number;
|
||||||
cancel: CancelTokenSource;
|
cancel: CancelTokenSource;
|
||||||
}
|
}
|
||||||
| { type: "sending"; files: File[] }
|
| { type: "sending"; files: File[] }
|
||||||
| { type: "failed"; files: File[]; error: string };
|
| { type: "failed"; files: File[]; error: string };
|
||||||
|
|
||||||
|
@ -173,9 +173,9 @@ export default observer(({ channel }: Props) => {
|
||||||
const text =
|
const text =
|
||||||
action === "quote"
|
action === "quote"
|
||||||
? `${content
|
? `${content
|
||||||
.split("\n")
|
.split("\n")
|
||||||
.map((x) => `> ${x}`)
|
.map((x) => `> ${x}`)
|
||||||
.join("\n")}\n\n`
|
.join("\n")}\n\n`
|
||||||
: `${content} `;
|
: `${content} `;
|
||||||
|
|
||||||
if (!draft || draft.length === 0) {
|
if (!draft || draft.length === 0) {
|
||||||
|
@ -225,8 +225,8 @@ export default observer(({ channel }: Props) => {
|
||||||
toReplace == ""
|
toReplace == ""
|
||||||
? msg.content.toString() + newText
|
? msg.content.toString() + newText
|
||||||
: msg.content
|
: msg.content
|
||||||
.toString()
|
.toString()
|
||||||
.replace(new RegExp(toReplace, flags), newText);
|
.replace(new RegExp(toReplace, flags), newText);
|
||||||
|
|
||||||
if (newContent != msg.content) {
|
if (newContent != msg.content) {
|
||||||
if (newContent.length == 0) {
|
if (newContent.length == 0) {
|
||||||
|
@ -305,10 +305,10 @@ export default observer(({ channel }: Props) => {
|
||||||
files,
|
files,
|
||||||
percent: Math.round(
|
percent: Math.round(
|
||||||
(i * 100 + (100 * e.loaded) / e.total) /
|
(i * 100 + (100 * e.loaded) / e.total) /
|
||||||
Math.min(
|
Math.min(
|
||||||
files.length,
|
files.length,
|
||||||
CAN_UPLOAD_AT_ONCE,
|
CAN_UPLOAD_AT_ONCE,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
cancel,
|
cancel,
|
||||||
}),
|
}),
|
||||||
|
@ -398,6 +398,7 @@ export default observer(({ channel }: Props) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: change to useDebounceCallback
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
const debouncedStopTyping = useCallback(
|
const debouncedStopTyping = useCallback(
|
||||||
debounce(stopTyping as (...args: unknown[]) => void, 1000),
|
debounce(stopTyping as (...args: unknown[]) => void, 1000),
|
||||||
|
@ -553,13 +554,13 @@ export default observer(({ channel }: Props) => {
|
||||||
placeholder={
|
placeholder={
|
||||||
channel.channel_type === "DirectMessage"
|
channel.channel_type === "DirectMessage"
|
||||||
? translate("app.main.channel.message_who", {
|
? translate("app.main.channel.message_who", {
|
||||||
person: channel.recipient?.username,
|
person: channel.recipient?.username,
|
||||||
})
|
})
|
||||||
: channel.channel_type === "SavedMessages"
|
: channel.channel_type === "SavedMessages"
|
||||||
? translate("app.main.channel.message_saved")
|
? translate("app.main.channel.message_saved")
|
||||||
: translate("app.main.channel.message_where", {
|
: translate("app.main.channel.message_where", {
|
||||||
channel_name: channel.name ?? undefined,
|
channel_name: channel.name ?? undefined,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
disabled={
|
disabled={
|
||||||
uploadState.type === "uploading" ||
|
uploadState.type === "uploading" ||
|
||||||
|
|
32
src/components/ui/SaveStatus.tsx
Normal file
32
src/components/ui/SaveStatus.tsx
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
import { Check, CloudUpload } from "@styled-icons/boxicons-regular";
|
||||||
|
import { Pencil } from "@styled-icons/boxicons-solid";
|
||||||
|
import styled from "styled-components";
|
||||||
|
|
||||||
|
const StatusBase = styled.div`
|
||||||
|
gap: 4px;
|
||||||
|
padding: 4px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
text-transform: capitalize;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export type EditStatus = "saved" | "editing" | "saving";
|
||||||
|
interface Props {
|
||||||
|
status: EditStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function SaveStatus({ status }: Props) {
|
||||||
|
return (
|
||||||
|
<StatusBase>
|
||||||
|
{status === "saved" ? (
|
||||||
|
<Check size={20} />
|
||||||
|
) : status === "editing" ? (
|
||||||
|
<Pencil size={20} />
|
||||||
|
) : (
|
||||||
|
<CloudUpload size={20} />
|
||||||
|
)}
|
||||||
|
{/* FIXME: add i18n */}
|
||||||
|
<span>{status}</span>
|
||||||
|
</StatusBase>
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,3 +1,7 @@
|
||||||
|
import isEqual from "lodash.isequal";
|
||||||
|
|
||||||
|
import { Inputs, useCallback, useEffect, useRef } from "preact/hooks";
|
||||||
|
|
||||||
export function debounce(cb: (...args: unknown[]) => void, duration: number) {
|
export function debounce(cb: (...args: unknown[]) => void, duration: number) {
|
||||||
// Store the timer variable.
|
// Store the timer variable.
|
||||||
let timer: NodeJS.Timeout;
|
let timer: NodeJS.Timeout;
|
||||||
|
@ -13,3 +17,60 @@ export function debounce(cb: (...args: unknown[]) => void, duration: number) {
|
||||||
}, duration);
|
}, duration);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useDebounceCallback(
|
||||||
|
cb: (...args: unknown[]) => void,
|
||||||
|
inputs: Inputs,
|
||||||
|
duration = 1000,
|
||||||
|
) {
|
||||||
|
// eslint-disable-next-line
|
||||||
|
return useCallback(
|
||||||
|
debounce(cb as (...args: unknown[]) => void, duration),
|
||||||
|
inputs,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useAutosaveCallback(
|
||||||
|
cb: (...args: unknown[]) => void,
|
||||||
|
inputs: Inputs,
|
||||||
|
duration = 1000,
|
||||||
|
) {
|
||||||
|
const ref = useRef(cb);
|
||||||
|
|
||||||
|
// eslint-disable-next-line
|
||||||
|
const callback = useCallback(
|
||||||
|
debounce(() => ref.current(), duration),
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
ref.current = cb;
|
||||||
|
callback();
|
||||||
|
// eslint-disable-next-line
|
||||||
|
}, [cb, callback, ...inputs]);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useAutosave<T>(
|
||||||
|
cb: () => void,
|
||||||
|
dependency: T,
|
||||||
|
initialValue: T,
|
||||||
|
onBeginChange?: () => void,
|
||||||
|
duration?: number,
|
||||||
|
) {
|
||||||
|
if (onBeginChange) {
|
||||||
|
// eslint-disable-next-line
|
||||||
|
useEffect(
|
||||||
|
() => {
|
||||||
|
!isEqual(dependency, initialValue) && onBeginChange();
|
||||||
|
},
|
||||||
|
// eslint-disable-next-line
|
||||||
|
[dependency],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return useAutosaveCallback(
|
||||||
|
() => !isEqual(dependency, initialValue) && cb(),
|
||||||
|
[dependency],
|
||||||
|
duration,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -50,6 +50,7 @@ export default observer(() => {
|
||||||
title: (
|
title: (
|
||||||
<Text id="app.settings.server_pages.categories.title" />
|
<Text id="app.settings.server_pages.categories.title" />
|
||||||
),
|
),
|
||||||
|
hideTitle: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "members",
|
id: "members",
|
||||||
|
|
|
@ -1,17 +1,22 @@
|
||||||
|
import { Check } from "@styled-icons/boxicons-regular";
|
||||||
import isEqual from "lodash.isequal";
|
import isEqual from "lodash.isequal";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { DragDropContext, Draggable, Droppable } from "react-beautiful-dnd";
|
import { DragDropContext, Draggable, Droppable } from "react-beautiful-dnd";
|
||||||
import { Category } from "revolt-api/types/Servers";
|
import { Category } from "revolt-api/types/Servers";
|
||||||
import { Server } from "revolt.js/dist/maps/Servers";
|
import { Server } from "revolt.js/dist/maps/Servers";
|
||||||
import styled from "styled-components";
|
import styled, { css } from "styled-components";
|
||||||
import { ulid } from "ulid";
|
import { ulid } from "ulid";
|
||||||
|
|
||||||
import { useState } from "preact/hooks";
|
import { Text } from "preact-i18n";
|
||||||
|
import { useEffect, useErrorBoundary, useState } from "preact/hooks";
|
||||||
|
|
||||||
|
import { useAutosave, useAutosaveCallback } from "../../../lib/debounce";
|
||||||
|
|
||||||
import ChannelIcon from "../../../components/common/ChannelIcon";
|
import ChannelIcon from "../../../components/common/ChannelIcon";
|
||||||
import Button from "../../../components/ui/Button";
|
import Button from "../../../components/ui/Button";
|
||||||
import ComboBox from "../../../components/ui/ComboBox";
|
import ComboBox from "../../../components/ui/ComboBox";
|
||||||
import InputBox from "../../../components/ui/InputBox";
|
import InputBox from "../../../components/ui/InputBox";
|
||||||
|
import SaveStatus, { EditStatus } from "../../../components/ui/SaveStatus";
|
||||||
import Tip from "../../../components/ui/Tip";
|
import Tip from "../../../components/ui/Tip";
|
||||||
|
|
||||||
/* interface CreateCategoryProps {
|
/* interface CreateCategoryProps {
|
||||||
|
@ -25,42 +30,52 @@ function CreateCategory({ callback }: CreateCategoryProps) {
|
||||||
} */
|
} */
|
||||||
|
|
||||||
const KanbanEntry = styled.div`
|
const KanbanEntry = styled.div`
|
||||||
display: flex;
|
padding: 2px 4px;
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
gap: 4px;
|
> .inner {
|
||||||
margin: 4px;
|
display: flex;
|
||||||
height: 40px;
|
align-items: center;
|
||||||
padding: 8px;
|
|
||||||
flex-shrink: 0;
|
|
||||||
font-size: 0.9em;
|
|
||||||
background: var(--primary-background);
|
|
||||||
|
|
||||||
img {
|
gap: 4px;
|
||||||
|
height: 40px;
|
||||||
|
padding: 8px;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
font-size: 0.9em;
|
||||||
|
background: var(--primary-background);
|
||||||
|
|
||||||
span {
|
img {
|
||||||
min-width: 0;
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
overflow: hidden;
|
span {
|
||||||
white-space: nowrap;
|
min-width: 0;
|
||||||
text-overflow: ellipsis;
|
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const KanbanList = styled.div`
|
const KanbanList = styled.div<{ last: boolean }>`
|
||||||
gap: 8px;
|
${(props) =>
|
||||||
width: 180px;
|
!props.last &&
|
||||||
display: flex;
|
css`
|
||||||
flex-shrink: 0;
|
padding-inline-end: 4px;
|
||||||
overflow-y: auto;
|
`}
|
||||||
flex-direction: column;
|
|
||||||
background: var(--secondary-background);
|
|
||||||
|
|
||||||
> [data-rbd-droppable-id] {
|
> .inner {
|
||||||
min-height: 24px;
|
width: 180px;
|
||||||
|
display: flex;
|
||||||
|
flex-shrink: 0;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding-bottom: 2px;
|
||||||
|
flex-direction: column;
|
||||||
|
background: var(--secondary-background);
|
||||||
|
|
||||||
|
> [data-rbd-droppable-id] {
|
||||||
|
min-height: 24px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
@ -71,13 +86,13 @@ const KanbanListTitle = styled.div`
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const KanbanBoard = styled.div`
|
const KanbanBoard = styled.div`
|
||||||
gap: 8px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const FullSize = styled.div`
|
const FullSize = styled.div`
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
|
min-height: 0;
|
||||||
|
|
||||||
> * {
|
> * {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -85,191 +100,238 @@ const FullSize = styled.div`
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const Header = styled.div`
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
server: Server;
|
server: Server;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Categories = observer(({ server }: Props) => {
|
export const Categories = observer(({ server }: Props) => {
|
||||||
|
const [status, setStatus] = useState<EditStatus>("saved");
|
||||||
const [categories, setCategories] = useState<Category[]>(
|
const [categories, setCategories] = useState<Category[]>(
|
||||||
server.categories ?? [],
|
server.categories ?? [],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
useAutosave(
|
||||||
|
async () => {
|
||||||
|
setStatus("saving");
|
||||||
|
await server.edit({ categories });
|
||||||
|
setStatus("saved");
|
||||||
|
},
|
||||||
|
categories,
|
||||||
|
server.categories,
|
||||||
|
() => setStatus("editing"),
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DragDropContext
|
<>
|
||||||
onDragEnd={(target) => {
|
<Header>
|
||||||
const { destination, source, draggableId, type } = target;
|
<h1>
|
||||||
|
<Text id={`app.settings.server_pages.categories.title`} />
|
||||||
|
</h1>
|
||||||
|
<SaveStatus status={status} />
|
||||||
|
</Header>
|
||||||
|
<DragDropContext
|
||||||
|
onDragEnd={(target) => {
|
||||||
|
const { destination, source, draggableId, type } = target;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!destination ||
|
!destination ||
|
||||||
(destination.droppableId === source.droppableId &&
|
(destination.droppableId === source.droppableId &&
|
||||||
destination.index === source.index)
|
destination.index === source.index)
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === "column") {
|
if (type === "column") {
|
||||||
// Remove from array.
|
// Remove from array.
|
||||||
const cat = categories.find((x) => x.id === draggableId);
|
const cat = categories.find(
|
||||||
const arr = categories.filter((x) => x.id !== draggableId);
|
(x) => x.id === draggableId,
|
||||||
|
);
|
||||||
|
const arr = categories.filter(
|
||||||
|
(x) => x.id !== draggableId,
|
||||||
|
);
|
||||||
|
|
||||||
// Insert at new position.
|
// Insert at new position.
|
||||||
arr.splice(destination.index, 0, cat!);
|
arr.splice(destination.index, 0, cat!);
|
||||||
setCategories(arr);
|
setCategories(arr);
|
||||||
} else {
|
} else {
|
||||||
setCategories(
|
setCategories(
|
||||||
categories.map((category) => {
|
categories.map((category) => {
|
||||||
if (category.id === destination.droppableId) {
|
if (category.id === destination.droppableId) {
|
||||||
const channels = category.channels.filter(
|
const channels = category.channels.filter(
|
||||||
(x) => x !== draggableId,
|
|
||||||
);
|
|
||||||
|
|
||||||
channels.splice(
|
|
||||||
destination.index,
|
|
||||||
0,
|
|
||||||
draggableId,
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
...category,
|
|
||||||
channels,
|
|
||||||
};
|
|
||||||
} else if (category.id === source.droppableId) {
|
|
||||||
return {
|
|
||||||
...category,
|
|
||||||
channels: category.channels.filter(
|
|
||||||
(x) => x !== draggableId,
|
(x) => x !== draggableId,
|
||||||
),
|
);
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return category;
|
channels.splice(
|
||||||
}),
|
destination.index,
|
||||||
);
|
0,
|
||||||
}
|
draggableId,
|
||||||
}}>
|
);
|
||||||
<FullSize>
|
|
||||||
<Droppable
|
return {
|
||||||
droppableId="categories"
|
...category,
|
||||||
direction="horizontal"
|
channels,
|
||||||
type="column">
|
};
|
||||||
{(provided) =>
|
} else if (category.id === source.droppableId) {
|
||||||
(
|
return {
|
||||||
<div
|
...category,
|
||||||
ref={provided.innerRef}
|
channels: category.channels.filter(
|
||||||
{...provided.droppableProps}>
|
(x) => x !== draggableId,
|
||||||
<KanbanBoard>
|
),
|
||||||
{categories.map((category, index) => (
|
};
|
||||||
<Draggable
|
}
|
||||||
key={category.id}
|
|
||||||
draggableId={category.id}
|
return category;
|
||||||
index={index}>
|
}),
|
||||||
{(provided) =>
|
);
|
||||||
(
|
}
|
||||||
<div
|
}}>
|
||||||
{...(provided.draggableProps as any)}
|
<FullSize>
|
||||||
ref={provided.innerRef}>
|
<Droppable
|
||||||
<KanbanList
|
droppableId="categories"
|
||||||
key={category.id}>
|
direction="horizontal"
|
||||||
<KanbanListTitle
|
type="column">
|
||||||
{...(provided.dragHandleProps as any)}>
|
{(provided) =>
|
||||||
<span>
|
(
|
||||||
{
|
<div
|
||||||
category.title
|
ref={provided.innerRef}
|
||||||
}
|
{...provided.droppableProps}>
|
||||||
</span>
|
<KanbanBoard>
|
||||||
</KanbanListTitle>
|
{categories.map((category, index) => (
|
||||||
<Droppable
|
<Draggable
|
||||||
droppableId={
|
key={category.id}
|
||||||
category.id
|
draggableId={category.id}
|
||||||
|
index={index}>
|
||||||
|
{(provided) =>
|
||||||
|
(
|
||||||
|
<div
|
||||||
|
{...(provided.draggableProps as any)}
|
||||||
|
ref={
|
||||||
|
provided.innerRef
|
||||||
|
}>
|
||||||
|
<KanbanList
|
||||||
|
last={
|
||||||
|
index ===
|
||||||
|
categories.length -
|
||||||
|
1
|
||||||
}
|
}
|
||||||
key={
|
key={
|
||||||
category.id
|
category.id
|
||||||
}>
|
}>
|
||||||
{(provided) =>
|
<div class="inner">
|
||||||
(
|
<KanbanListTitle
|
||||||
<div
|
{...(provided.dragHandleProps as any)}>
|
||||||
ref={
|
<span>
|
||||||
provided.innerRef
|
|
||||||
}
|
|
||||||
{...provided.droppableProps}>
|
|
||||||
{category.channels.map(
|
|
||||||
(
|
|
||||||
x,
|
|
||||||
index,
|
|
||||||
) => {
|
|
||||||
const channel =
|
|
||||||
server.client.channels.get(
|
|
||||||
x,
|
|
||||||
);
|
|
||||||
if (
|
|
||||||
!channel
|
|
||||||
)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Draggable
|
|
||||||
key={
|
|
||||||
x
|
|
||||||
}
|
|
||||||
draggableId={
|
|
||||||
x
|
|
||||||
}
|
|
||||||
index={
|
|
||||||
index
|
|
||||||
}>
|
|
||||||
{(
|
|
||||||
provided,
|
|
||||||
) =>
|
|
||||||
(
|
|
||||||
<div
|
|
||||||
{...(provided.draggableProps as any)}
|
|
||||||
{...provided.dragHandleProps}
|
|
||||||
ref={
|
|
||||||
provided.innerRef
|
|
||||||
}>
|
|
||||||
<KanbanEntry>
|
|
||||||
<ChannelIcon
|
|
||||||
target={
|
|
||||||
channel
|
|
||||||
}
|
|
||||||
size={
|
|
||||||
24
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<span>
|
|
||||||
{
|
|
||||||
channel.name
|
|
||||||
}
|
|
||||||
</span>
|
|
||||||
</KanbanEntry>
|
|
||||||
</div>
|
|
||||||
) as any
|
|
||||||
}
|
|
||||||
</Draggable>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
)}
|
|
||||||
{
|
{
|
||||||
provided.placeholder
|
category.title
|
||||||
}
|
}
|
||||||
</div>
|
</span>
|
||||||
) as any
|
</KanbanListTitle>
|
||||||
}
|
<Droppable
|
||||||
</Droppable>
|
droppableId={
|
||||||
</KanbanList>
|
category.id
|
||||||
</div>
|
}
|
||||||
) as any
|
key={
|
||||||
}
|
category.id
|
||||||
</Draggable>
|
}>
|
||||||
))}
|
{(
|
||||||
{provided.placeholder}
|
provided,
|
||||||
</KanbanBoard>
|
) =>
|
||||||
</div>
|
(
|
||||||
) as any
|
<div
|
||||||
}
|
ref={
|
||||||
</Droppable>
|
provided.innerRef
|
||||||
</FullSize>
|
}
|
||||||
</DragDropContext>
|
{...provided.droppableProps}>
|
||||||
|
{category.channels.map(
|
||||||
|
(
|
||||||
|
x,
|
||||||
|
index,
|
||||||
|
) => {
|
||||||
|
const channel =
|
||||||
|
server.client.channels.get(
|
||||||
|
x,
|
||||||
|
);
|
||||||
|
if (
|
||||||
|
!channel
|
||||||
|
)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Draggable
|
||||||
|
key={
|
||||||
|
x
|
||||||
|
}
|
||||||
|
draggableId={
|
||||||
|
x
|
||||||
|
}
|
||||||
|
index={
|
||||||
|
index
|
||||||
|
}>
|
||||||
|
{(
|
||||||
|
provided,
|
||||||
|
) =>
|
||||||
|
(
|
||||||
|
<div
|
||||||
|
{...(provided.draggableProps as any)}
|
||||||
|
{...provided.dragHandleProps}
|
||||||
|
ref={
|
||||||
|
provided.innerRef
|
||||||
|
}>
|
||||||
|
<KanbanEntry>
|
||||||
|
<div class="inner">
|
||||||
|
<ChannelIcon
|
||||||
|
target={
|
||||||
|
channel
|
||||||
|
}
|
||||||
|
size={
|
||||||
|
24
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<span>
|
||||||
|
{
|
||||||
|
channel.name
|
||||||
|
}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</KanbanEntry>
|
||||||
|
</div>
|
||||||
|
) as any
|
||||||
|
}
|
||||||
|
</Draggable>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)}
|
||||||
|
{
|
||||||
|
provided.placeholder
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
) as any
|
||||||
|
}
|
||||||
|
</Droppable>
|
||||||
|
</div>
|
||||||
|
</KanbanList>
|
||||||
|
</div>
|
||||||
|
) as any
|
||||||
|
}
|
||||||
|
</Draggable>
|
||||||
|
))}
|
||||||
|
{provided.placeholder}
|
||||||
|
</KanbanBoard>
|
||||||
|
</div>
|
||||||
|
) as any
|
||||||
|
}
|
||||||
|
</Droppable>
|
||||||
|
</FullSize>
|
||||||
|
</DragDropContext>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue