problem solved
This commit is contained in:
parent
dc66da7d00
commit
365e2e3982
@ -6,6 +6,7 @@ import { Attributes, where } from "@sequelize/core";
|
|||||||
import { getCookieAuth, userIsAdmin } from '../../actions';
|
import { getCookieAuth, userIsAdmin } from '../../actions';
|
||||||
import { ActionResult } from '../../ActionResult';
|
import { ActionResult } from '../../ActionResult';
|
||||||
import { PostAttributesWithBuckets } from '@/models';
|
import { PostAttributesWithBuckets } from '@/models';
|
||||||
|
import { inspect } from 'util';
|
||||||
|
|
||||||
export async function deletePost(postID: number): Promise<ActionResult<boolean>> {
|
export async function deletePost(postID: number): Promise<ActionResult<boolean>> {
|
||||||
await dbSync;
|
await dbSync;
|
||||||
@ -30,7 +31,7 @@ export type GetPostsAttributes = {
|
|||||||
export async function getPostsWithBucketsAndProject(): Promise<ActionResult<GetPostsAttributes[]>> {
|
export async function getPostsWithBucketsAndProject(): Promise<ActionResult<GetPostsAttributes[]>> {
|
||||||
await dbSync;
|
await dbSync;
|
||||||
if(! await userIsAdmin()) return {error:"Unauthorized, not fetching Posts."}
|
if(! await userIsAdmin()) return {error:"Unauthorized, not fetching Posts."}
|
||||||
const posts = await Post.findAll({
|
const posts:Post[] = await Post.findAll({
|
||||||
include: [
|
include: [
|
||||||
{association: Post.associations.buckets, include: Bucket.associations.attachments},
|
{association: Post.associations.buckets, include: Bucket.associations.attachments},
|
||||||
{association: Post.associations.user},
|
{association: Post.associations.user},
|
||||||
@ -38,22 +39,7 @@ export async function getPostsWithBucketsAndProject(): Promise<ActionResult<GetP
|
|||||||
nest: false
|
nest: false
|
||||||
});
|
});
|
||||||
return {result:JSON.parse(JSON.stringify(posts.map((e:Post)=>{
|
return {result:JSON.parse(JSON.stringify(posts.map((e:Post)=>{
|
||||||
return {
|
return inspect(e)
|
||||||
id: e.id,
|
|
||||||
title: e.title,
|
|
||||||
content: e.content,
|
|
||||||
description: e.description,
|
|
||||||
buckets: e.buckets ? e.buckets : [],
|
|
||||||
user: e.user,
|
|
||||||
project: {
|
|
||||||
id: e.project_id,
|
|
||||||
name: e.project ? e.project.name : "",
|
|
||||||
readableIdentifier: e.project ? e.project.readableIdentifier : "",
|
|
||||||
posts: e.project ? e.project.posts : []
|
|
||||||
},
|
|
||||||
createdAt: e.createdAt,
|
|
||||||
updatedAt: e.updatedAt
|
|
||||||
} as GetPostsAttributes
|
|
||||||
})))};
|
})))};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,296 +1,243 @@
|
|||||||
import { GetPostsAttributes } from "@/app/lib/actions/entityManagement/post/postActions";
|
import { GetPostsAttributes } from "@/app/lib/actions/entitymanagement/post/postActions";
|
||||||
import { Post, Project, Bucket, PostBucket, Attachment } from "@/models";
|
import { Post, Project, Bucket, PostBucket, Attachment } from "@/models";
|
||||||
import { Attributes } from "@sequelize/core";
|
import { Attributes } from "@sequelize/core";
|
||||||
import { UUID } from "crypto";
|
import { UUID } from "crypto";
|
||||||
import { EntityEditorTextArea } from '../input/EntityEditorTextArea';
|
import { EntityEditorTextArea } from "../input/EntityEditorTextArea";
|
||||||
|
import { ChangeEvent, ChangeEventHandler, MouseEventHandler, useState } from "react";
|
||||||
import {
|
import {
|
||||||
ChangeEventHandler,
|
Accordion,
|
||||||
MouseEventHandler,
|
AccordionBody,
|
||||||
useState,
|
AccordionHeader,
|
||||||
} from "react";
|
AccordionItem,
|
||||||
import {
|
|
||||||
Accordion,
|
|
||||||
AccordionBody,
|
|
||||||
AccordionHeader,
|
|
||||||
AccordionItem,
|
|
||||||
} from "react-bootstrap";
|
} from "react-bootstrap";
|
||||||
|
|
||||||
export type PostTableCallbacks = {
|
export type PostTableCallbacks = {
|
||||||
savePost: (p: Partial<Attributes<Post>>) => void;
|
savePost: (p: Partial<Attributes<Post>>) => void;
|
||||||
refetch: () => any;
|
refetch: () => any;
|
||||||
closeEditor: () => any;
|
closeEditor: () => any;
|
||||||
uploadAttachment: () => any;
|
uploadAttachment: () => any;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type EditorState = {
|
export type EditorState = {
|
||||||
isEditorOpen: boolean;
|
isEditorOpen: boolean;
|
||||||
editorPost: GetPostsAttributes;
|
editorPost: GetPostsAttributes;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type EditorProps = {
|
export type EditorProps = {
|
||||||
editorPost: GetPostsAttributes;
|
editorPost: GetPostsAttributes;
|
||||||
projectList: {
|
projectList: {
|
||||||
id: number;
|
id: number;
|
||||||
readableIdentifier: string;
|
readableIdentifier: string;
|
||||||
}[];
|
}[];
|
||||||
callbacks: PostTableCallbacks;
|
callbacks: PostTableCallbacks;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function PostEditor({
|
export default function PostEditor({
|
||||||
editorPost,
|
editorPost,
|
||||||
projectList,
|
projectList,
|
||||||
callbacks,
|
callbacks,
|
||||||
}: EditorProps) {
|
}: EditorProps) {
|
||||||
// Setup State Hooks
|
// Setup State Hooks
|
||||||
let [postContentState, setPostContentState] = useState(editorPost.content);
|
let [postContentState, setPostContentState] = useState(editorPost.content);
|
||||||
let [postTitleState, setPostTitleState] = useState(editorPost.title);
|
let [postTitleState, setPostTitleState] = useState(editorPost.title);
|
||||||
let [postProjectIDState, setPostProjectIDState] = useState(
|
let [postProjectIDState, setPostProjectIDState] = useState(
|
||||||
editorPost.project.id
|
editorPost.project.id
|
||||||
);
|
);
|
||||||
|
|
||||||
// Handle changing the selected project using the dropdown select
|
// Handle changing the selected project using the dropdown select
|
||||||
const projectSelectionChange: ChangeEventHandler<HTMLSelectElement> = (e) =>
|
const projectSelectionChange: ChangeEventHandler<HTMLSelectElement> = (e) =>
|
||||||
setPostProjectIDState(parseInt(e.target.value));
|
setPostProjectIDState(parseInt(e.target.value));
|
||||||
// Handle clicking the save button
|
// Handle clicking the save button
|
||||||
const onClickSaveButton: MouseEventHandler<HTMLButtonElement> = (e) => {
|
const onClickSaveButton: MouseEventHandler<HTMLButtonElement> = (e) => {
|
||||||
callbacks?.savePost({
|
callbacks?.savePost({
|
||||||
id: editorPost?.id as number,
|
id: editorPost?.id as number,
|
||||||
content: postContentState as string,
|
content: postContentState as string,
|
||||||
title: postTitleState as string,
|
title: postTitleState as string,
|
||||||
project_id: postProjectIDState,
|
project_id: postProjectIDState,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
const onClickCancelButton: MouseEventHandler<HTMLButtonElement> = (e) => {
|
const onClickCancelButton: MouseEventHandler<HTMLButtonElement> = (e) => {
|
||||||
callbacks?.closeEditor();
|
callbacks?.closeEditor();
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<form className="bg-light w-[100%] h-content p-1">
|
<form className="bg-light w-[100%] h-content p-1">
|
||||||
<h1 key="heading-editpost" className="m-2">
|
<h1 key="heading-editpost" className="m-2">
|
||||||
Edit Post
|
Edit Post
|
||||||
</h1>
|
</h1>
|
||||||
<h2 key="label-title" className="m-2">
|
<h2 key="label-title" className="m-2">
|
||||||
Title
|
Title
|
||||||
</h2>
|
</h2>
|
||||||
<input
|
<input
|
||||||
key="input-title"
|
key="input-title"
|
||||||
value={postTitleState}
|
value={postTitleState}
|
||||||
onChange={(e) => setPostTitleState(e.target.value)}
|
onChange={(e) => setPostTitleState(e.target.value)}
|
||||||
type="text"
|
type="text"
|
||||||
className="m-2"
|
className="m-2"
|
||||||
/>
|
/>
|
||||||
<h2 key="label-content" className="m-2">
|
<h2 key="label-content" className="m-2">
|
||||||
Content
|
Content
|
||||||
</h2>
|
</h2>
|
||||||
<EntityEditorTextArea
|
<EntityEditorTextArea
|
||||||
contentHook={{
|
contentHook={{
|
||||||
state: postContentState,
|
state: postContentState,
|
||||||
setState: setPostContentState
|
setState: setPostContentState,
|
||||||
}}
|
}}
|
||||||
className={ "w-[100%] min-h-auto h-content align-top text-start text-base line-clamp-6 m-2" }
|
className={
|
||||||
>
|
"w-[100%] min-h-auto h-content align-top text-start text-base line-clamp-6 m-2"
|
||||||
</EntityEditorTextArea>
|
}
|
||||||
<h2 key="label-project" className="m-2">
|
></EntityEditorTextArea>
|
||||||
Project
|
<h2 key="label-project" className="m-2">
|
||||||
</h2>
|
Project
|
||||||
<select
|
</h2>
|
||||||
key="input-project"
|
<select
|
||||||
onChange={projectSelectionChange}
|
key="input-project"
|
||||||
name="projects"
|
onChange={projectSelectionChange}
|
||||||
id="projects"
|
name="projects"
|
||||||
defaultValue={editorPost?.project?.id}
|
id="projects"
|
||||||
placeholder={editorPost?.project?.name}
|
defaultValue={editorPost?.project?.id}
|
||||||
value={postProjectIDState}
|
placeholder={editorPost?.project?.name}
|
||||||
className="m-2"
|
value={postProjectIDState}
|
||||||
>
|
className="m-2"
|
||||||
<option key="projectSelectionOpt-0" value={0}>
|
>
|
||||||
unassigned
|
<option key="projectSelectionOpt-0" value={0}>
|
||||||
</option>
|
unassigned
|
||||||
{projectList?.map((p) => (
|
</option>
|
||||||
<option
|
{projectList?.map((p) => (
|
||||||
key={`projectSelectionOpt-${p.id}`}
|
<option key={`projectSelectionOpt-${p.id}`} value={p.id}>
|
||||||
value={p.id}
|
{p.readableIdentifier}
|
||||||
>
|
</option>
|
||||||
{p.readableIdentifier}
|
))}
|
||||||
</option>
|
</select>
|
||||||
))}
|
<h2 key="label-attachments">Attachments</h2>
|
||||||
</select>
|
<table key="table-buckets" className="table table-striped">
|
||||||
<h2 key="label-attachments">Attachments</h2>
|
<thead>
|
||||||
<table key="table-buckets" className="table table-striped">
|
<tr>
|
||||||
<thead>
|
<td>Buckets</td>
|
||||||
<tr>
|
</tr>
|
||||||
<td>Buckets</td>
|
</thead>
|
||||||
</tr>
|
<tbody>
|
||||||
</thead>
|
{editorPost?.buckets ? (
|
||||||
<tbody>
|
(() => {
|
||||||
{editorPost?.buckets ? (
|
let bucketMap: Map<UUID, Attributes<Bucket>> = new Map(
|
||||||
(() => {
|
editorPost.buckets.map((b) => [b.id as UUID, b])
|
||||||
let bucketMap: Map<
|
);
|
||||||
UUID,
|
let bucketList:UUID[] = [...editorPost.buckets.map((b) => b.id)];
|
||||||
Attributes<Bucket>
|
return bucketList.map((bucketID,i) => {
|
||||||
> = new Map(
|
return (
|
||||||
editorPost.buckets.map((b) => [
|
<>
|
||||||
b.id as UUID,
|
<tr
|
||||||
b,
|
key={i}
|
||||||
])
|
>
|
||||||
);
|
<Accordion>
|
||||||
let bucketList = [
|
<AccordionItem
|
||||||
...editorPost.buckets.map((b) => b.id),
|
eventKey={bucketList.indexOf(bucketID).toString()}
|
||||||
];
|
>
|
||||||
return bucketList.map((e) => {
|
<AccordionHeader>{bucketID}</AccordionHeader>
|
||||||
return (
|
<AccordionBody>
|
||||||
<>
|
<ul>
|
||||||
<tr
|
<li>
|
||||||
key={`bucketAccordionRow-${bucketList
|
<input
|
||||||
.indexOf(e)
|
type="file"
|
||||||
.toString()}`}
|
className="btn btn-success"
|
||||||
>
|
onChange={onFileInputChange()}
|
||||||
<Accordion>
|
/>
|
||||||
<AccordionItem
|
</li>
|
||||||
eventKey={bucketList
|
{(() => {
|
||||||
.indexOf(e)
|
const bucket: Attributes<Bucket> | undefined = bucketMap.get(bucketID);
|
||||||
.toString()}
|
return bucket && bucket.attachments && (
|
||||||
>
|
bucket.attachments.map((attachment) => (
|
||||||
<AccordionHeader>
|
<li
|
||||||
{e}
|
key={`listItem-file-${attachment.filename}`}
|
||||||
</AccordionHeader>
|
>
|
||||||
<AccordionBody>
|
{attachment.filename}
|
||||||
<ul>
|
</li>
|
||||||
<li>
|
))
|
||||||
<input
|
);
|
||||||
type="file"
|
})()}
|
||||||
className="btn btn-success"
|
</ul>
|
||||||
onChange={(
|
</AccordionBody>
|
||||||
e
|
</AccordionItem>
|
||||||
) => {
|
</Accordion>
|
||||||
for (
|
</tr>
|
||||||
let index = 0;
|
</>
|
||||||
index <
|
);
|
||||||
((
|
});
|
||||||
e
|
})()
|
||||||
.target
|
) : (
|
||||||
.files as FileList
|
<></>
|
||||||
)
|
)}
|
||||||
.length as number);
|
</tbody>
|
||||||
index++
|
</table>
|
||||||
) {
|
<button type="button" className="m-2 btn btn-primary">
|
||||||
const element =
|
Preview
|
||||||
(
|
</button>
|
||||||
e
|
<button
|
||||||
.target
|
type="button"
|
||||||
.files as FileList
|
className="m-2 btn btn-success"
|
||||||
)[
|
onClick={onClickSaveButton}
|
||||||
index
|
>
|
||||||
];
|
Save
|
||||||
const fReader =
|
</button>
|
||||||
new FileReader();
|
<button
|
||||||
fReader.readAsDataURL(
|
type="button"
|
||||||
element
|
className="m-2 btn btn-danger"
|
||||||
);
|
onClick={onClickCancelButton}
|
||||||
fReader.onloadend =
|
>
|
||||||
(
|
Cancel
|
||||||
event
|
</button>
|
||||||
) => {
|
</form>
|
||||||
console.log(
|
</>
|
||||||
event
|
);
|
||||||
.target
|
|
||||||
?.result
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</li>
|
|
||||||
{(() => {
|
|
||||||
const bucket =
|
|
||||||
bucketMap.get(
|
|
||||||
e as UUID
|
|
||||||
);
|
|
||||||
return bucket &&
|
|
||||||
bucket.attachments ? (
|
|
||||||
bucket.attachments.map(
|
|
||||||
(
|
|
||||||
attachment
|
|
||||||
) => (
|
|
||||||
<li
|
|
||||||
key={`listItem-file-${attachment.filename}`}
|
|
||||||
>
|
|
||||||
{
|
|
||||||
attachment.filename
|
|
||||||
}
|
|
||||||
</li>
|
|
||||||
)
|
|
||||||
)
|
|
||||||
) : (
|
|
||||||
<></>
|
|
||||||
);
|
|
||||||
})()}
|
|
||||||
</ul>
|
|
||||||
</AccordionBody>
|
|
||||||
</AccordionItem>
|
|
||||||
</Accordion>
|
|
||||||
</tr>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
})()
|
|
||||||
) : (
|
|
||||||
<></>
|
|
||||||
)}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<button type="button" className="m-2 btn btn-primary">
|
|
||||||
Preview
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="m-2 btn btn-success"
|
|
||||||
onClick={onClickSaveButton}
|
|
||||||
>
|
|
||||||
Save
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="m-2 btn btn-danger"
|
|
||||||
onClick={onClickCancelButton}
|
|
||||||
>
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type EditorRendererProps = {
|
type EditorRendererProps = {
|
||||||
editorPost: GetPostsAttributes;
|
editorPost: GetPostsAttributes;
|
||||||
headings: string[];
|
headings: string[];
|
||||||
editorState: EditorState;
|
editorState: EditorState;
|
||||||
editorControls: any;
|
editorControls: any;
|
||||||
callbacks: any;
|
callbacks: any;
|
||||||
projects: any;
|
projects: any;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function EditorRenderer({
|
function onFileInputChange(): ChangeEventHandler<HTMLInputElement> {
|
||||||
editorPost,
|
return (e: ChangeEvent<HTMLInputElement>) => {
|
||||||
headings,
|
for (let index = 0; index <
|
||||||
editorState,
|
((e.target.files as FileList)
|
||||||
callbacks,
|
.length as number); index++) {
|
||||||
projects,
|
const element = (
|
||||||
}: EditorRendererProps) {
|
e.target.files as FileList
|
||||||
return editorState.isEditorOpen &&
|
)[index];
|
||||||
editorState.editorPost &&
|
const fReader = new FileReader();
|
||||||
editorState.editorPost.id == editorPost.id ? (
|
fReader.readAsDataURL(element);
|
||||||
<tr>
|
fReader.onloadend = (event) => {
|
||||||
<th scope="row" colSpan={headings.length}>
|
console.log(event.target?.result);
|
||||||
<PostEditor
|
};
|
||||||
callbacks={callbacks}
|
}
|
||||||
editorPost={editorState.editorPost}
|
};
|
||||||
projectList={projects}
|
}
|
||||||
/>
|
|
||||||
</th>
|
export function EditorRenderer({
|
||||||
</tr>
|
editorPost,
|
||||||
) : (
|
headings,
|
||||||
""
|
editorState,
|
||||||
);
|
callbacks,
|
||||||
|
projects,
|
||||||
|
}: EditorRendererProps) {
|
||||||
|
return editorState.isEditorOpen &&
|
||||||
|
editorState.editorPost &&
|
||||||
|
editorState.editorPost.id == editorPost.id ? (
|
||||||
|
<tr>
|
||||||
|
<th scope="row" colSpan={headings.length}>
|
||||||
|
<PostEditor
|
||||||
|
callbacks={callbacks}
|
||||||
|
editorPost={editorState.editorPost}
|
||||||
|
projectList={projects}
|
||||||
|
/>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
) : (
|
||||||
|
""
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user