full switch to jotai, finishes schema version query fixes
This commit is contained in:
parent
b529445851
commit
84cbea8ce1
2
.gitignore
vendored
2
.gitignore
vendored
@ -43,3 +43,5 @@ temp.json
|
||||
temp.md
|
||||
|
||||
.dragonshoard/
|
||||
|
||||
certificates
|
@ -3,33 +3,70 @@ import { auth } from "@/auth";
|
||||
import { isEmailVerified } from "@/util/isEmailVerified";
|
||||
import { redirect } from "next/navigation";
|
||||
import { prisma } from "@/prisma/prismaClient";
|
||||
import { Schema } from "@/types";
|
||||
|
||||
export const saveSchemaDb = async (s: Schema) => {
|
||||
export const saveSchemaDb = async (s: Schema, version: number) => {
|
||||
const sesh = await auth();
|
||||
if (!sesh?.user?.id) return;
|
||||
|
||||
const { id } = await prisma.schema.upsert({
|
||||
const { id, SchemaRevision } = await prisma.schema.upsert({
|
||||
// data: {
|
||||
// ...s,
|
||||
// },
|
||||
create: {
|
||||
...s,
|
||||
version: 0,
|
||||
name: s.name,
|
||||
SchemaRevision: {
|
||||
create: {
|
||||
fields: s.fields,
|
||||
types: s.types,
|
||||
},
|
||||
},
|
||||
authorId: sesh.user.id,
|
||||
id: undefined,
|
||||
},
|
||||
update: s,
|
||||
update: {
|
||||
name: s.name,
|
||||
},
|
||||
where: {
|
||||
id: s.id,
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
include: {
|
||||
// id: true,
|
||||
SchemaRevision: {
|
||||
where: {
|
||||
version: s.version,
|
||||
},
|
||||
select: {
|
||||
version: true,
|
||||
isFinal: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// const schema2 = await prisma.schema.findUnique({where:{id}})
|
||||
if (
|
||||
!SchemaRevision.at(0) ||
|
||||
SchemaRevision[0].version < version ||
|
||||
SchemaRevision[0].isFinal
|
||||
) {
|
||||
await prisma.schemaRevision.create({
|
||||
data: {
|
||||
schemaId: id,
|
||||
types: s.types,
|
||||
fields: s.fields,
|
||||
version,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
redirect(`/game-systems/${s.gameSystemId}/schema/${id}`);
|
||||
};
|
||||
|
||||
export const findSchema = async (id: string): Promise<Schema | null> => {
|
||||
export const findSchema = async (
|
||||
id: string,
|
||||
version: number,
|
||||
): Promise<Schema | null> => {
|
||||
const schema = await prisma.schema.findFirst({
|
||||
where: {
|
||||
id,
|
||||
@ -42,17 +79,33 @@ export const findSchema = async (id: string): Promise<Schema | null> => {
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
schema: true,
|
||||
types: true,
|
||||
include: {
|
||||
SchemaRevision: {
|
||||
where: {
|
||||
version,
|
||||
},
|
||||
select: {
|
||||
version: true,
|
||||
fields: true,
|
||||
types: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
// select: {
|
||||
// id: true,
|
||||
// name: true,
|
||||
// },
|
||||
});
|
||||
|
||||
if (!schema) return null;
|
||||
if (!schema?.SchemaRevision[0]) return null;
|
||||
|
||||
return schema as Schema;
|
||||
return {
|
||||
fields: schema.SchemaRevision[0].fields,
|
||||
types: schema.SchemaRevision[0].types,
|
||||
id: schema.id,
|
||||
gameSystemId: schema.gameSystemId,
|
||||
name: schema.name,
|
||||
} as Schema;
|
||||
};
|
||||
|
||||
export const createSchema = async (form: FormData) => {
|
||||
@ -67,9 +120,6 @@ export const createSchema = async (form: FormData) => {
|
||||
const { id } = await prisma.schema.create({
|
||||
data: {
|
||||
name,
|
||||
schema: "{}",
|
||||
types: "{}",
|
||||
version: 0,
|
||||
gameSystemId: gsId,
|
||||
authorId: session.user.id,
|
||||
},
|
||||
|
@ -20,6 +20,8 @@ export const { handlers, signIn, signOut, auth } = NextAuth(async () => {
|
||||
Discord({
|
||||
clientId,
|
||||
clientSecret,
|
||||
// redirectProxyUrl:
|
||||
// "https://bottomsurgery.local:3000/api/auth/callback/discord",
|
||||
}),
|
||||
Credentials({
|
||||
credentials: {
|
||||
|
@ -1,15 +1,14 @@
|
||||
// import { useRecoilValue } from "recoil";
|
||||
import { SchemaEditAtom } from "../../recoil/atoms/schema";
|
||||
import { TEMPLATE_TYPES } from "../../constants/TemplateTypes";
|
||||
import { FC, PropsWithChildren } from "react";
|
||||
import { useAtom } from "jotai";
|
||||
import { InputBinder } from "@/types";
|
||||
|
||||
interface IProps {
|
||||
bind: InputBinder;
|
||||
}
|
||||
|
||||
export const FieldTypeInput: FC<PropsWithChildren<IProps>> = ({ bind }) => {
|
||||
// const schema = useRecoilValue(SchemaEditAtom);
|
||||
const [schema] = useAtom(SchemaEditAtom);
|
||||
|
||||
return (
|
||||
|
@ -14,10 +14,10 @@ import { FieldTypes } from "./fieldtypes";
|
||||
import { findSchema, saveSchemaDb } from "@/actions/Schemas/index";
|
||||
import { useToast } from "../toast";
|
||||
import { useAtom } from "jotai";
|
||||
import { Schema } from "@/types";
|
||||
import { Schema, TypeType } from "@/types";
|
||||
|
||||
export const SchemaBuilder: FC = () => {
|
||||
const [schema, setSchema] = useAtom(SchemaEditAtom);
|
||||
const [schema, setSchema] = useAtom<Schema>(SchemaEditAtom);
|
||||
// const resetSchema = useResetRecoilState(SchemaEditAtom);
|
||||
const { createToast } = useToast();
|
||||
const { update: updateSchema, bindProperty: bindSchemaProperty } =
|
||||
@ -30,7 +30,7 @@ export const SchemaBuilder: FC = () => {
|
||||
|
||||
useEffect(() => {
|
||||
if (schemaId !== "create" && schemaId !== schema.id)
|
||||
findSchema(schemaId).then((sc) => {
|
||||
findSchema(schemaId, 0).then((sc) => {
|
||||
if (!sc) return;
|
||||
setSchema(sc);
|
||||
});
|
||||
@ -70,7 +70,7 @@ export const SchemaBuilder: FC = () => {
|
||||
|
||||
const saveSchema = useCallback(async () => {
|
||||
createToast({ msg: "Saving Schema", fading: true });
|
||||
await saveSchemaDb(schema);
|
||||
await saveSchemaDb(schema, schema.version);
|
||||
}, [createToast, schema]);
|
||||
|
||||
const selectTypeForEdit = useCallback((typeKey: string) => {
|
||||
|
@ -17,6 +17,13 @@ export default function SignIn() {
|
||||
type="password"
|
||||
name="password"
|
||||
/>
|
||||
<button
|
||||
role="button"
|
||||
type="submit"
|
||||
className="w-full p-2 rounded-lg bg-primary-500"
|
||||
>
|
||||
Sign In
|
||||
</button>
|
||||
</form>
|
||||
<div className="flex items-center gap-1">
|
||||
<div className="dark:border-dark-500 border-primary-600 flex-grow border-b"></div>
|
||||
@ -24,7 +31,10 @@ export default function SignIn() {
|
||||
<div className="dark:border-dark-500 border-primary-600 flex-grow border-b"></div>
|
||||
</div>
|
||||
<form action={signInWithDiscord}>
|
||||
<button className="w-full p-2 bg-[#816ab1] rounded-lg" type="submit">
|
||||
<button
|
||||
className="w-full p-2 bg-[#816ab1] rounded-lg flex items-center justify-center"
|
||||
type="submit"
|
||||
>
|
||||
<Icon icon="Discord" className="mr-4 inline-block" />
|
||||
Sign in with Discord
|
||||
</button>
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { PublicationAtom } from "@/recoil/atoms/publication";
|
||||
import { useState, useEffect, useCallback, useRef, ReactNode } from "react";
|
||||
import { useRecoilValue } from "recoil";
|
||||
import { TTCQueryResolver } from "../ttcQuery/TTCResolvers";
|
||||
import { useAtom } from "jotai";
|
||||
|
||||
export function Resolver({ resolver }: { resolver: string }) {
|
||||
const parser = useRecoilValue(PublicationAtom);
|
||||
const [parser] = useAtom(PublicationAtom);
|
||||
const [res] = useState(new TTCQueryResolver(parser));
|
||||
const [content, setContent] = useState<ReactNode>("");
|
||||
useEffect(() => {
|
||||
@ -15,7 +15,7 @@ export function Resolver({ resolver }: { resolver: string }) {
|
||||
<resolved.display />
|
||||
) : (
|
||||
resolved?.display
|
||||
)
|
||||
),
|
||||
);
|
||||
}, [resolver, res]);
|
||||
return <span>{content}</span>;
|
||||
@ -31,7 +31,7 @@ export function OnDemandResolver({
|
||||
template: string;
|
||||
title?: string;
|
||||
}) {
|
||||
const parser = useRecoilValue(PublicationAtom);
|
||||
const [parser] = useAtom(PublicationAtom);
|
||||
const res = useRef(new TTCQueryResolver(parser));
|
||||
const [content, setContent] = useState<ReactNode>("");
|
||||
const generateContent = useCallback(() => {
|
||||
|
@ -5,11 +5,13 @@ import { Poppable } from "../poppables/components/poppable";
|
||||
import { Accordion, AccordionContent } from "../accordion";
|
||||
import { OnDemandResolver, Resolver } from "./Resolver";
|
||||
|
||||
// import "crypto";
|
||||
|
||||
export const TokenRenderers = new Map<string, TokenRenderer<any>>();
|
||||
|
||||
export function buildIdentifierMap(): [
|
||||
TokenIdentifierMap,
|
||||
IdentifierRegistration
|
||||
IdentifierRegistration,
|
||||
] {
|
||||
const TokenIdentifiers = new Map<string, TokenIdentifier<any>>();
|
||||
|
||||
@ -17,7 +19,7 @@ export function buildIdentifierMap(): [
|
||||
type: string,
|
||||
match: RegExp,
|
||||
parseFunction: (s: string, rx: RegExp) => IdentifiedToken<M>,
|
||||
renderFunction: TokenRenderer<M>
|
||||
renderFunction: TokenRenderer<M>,
|
||||
): void;
|
||||
function registerIdentifier<M>(
|
||||
type: string,
|
||||
@ -25,7 +27,7 @@ export function buildIdentifierMap(): [
|
||||
parseFunction: (s: string, rx: RegExp) => IdentifiedToken<M>,
|
||||
renderFunction: TokenRenderer<M>,
|
||||
openTagRx: RegExp,
|
||||
closeTagRx: RegExp
|
||||
closeTagRx: RegExp,
|
||||
): void;
|
||||
function registerIdentifier<M = Record<string, string>>(
|
||||
type: string,
|
||||
@ -33,7 +35,7 @@ export function buildIdentifierMap(): [
|
||||
parseFunction: (s: string, rx: RegExp) => IdentifiedToken<M>,
|
||||
renderFunction: TokenRenderer<M>,
|
||||
openTagRx?: RegExp,
|
||||
closeTagRx?: RegExp
|
||||
closeTagRx?: RegExp,
|
||||
) {
|
||||
TokenIdentifiers.set(type, {
|
||||
rx: match,
|
||||
@ -54,7 +56,7 @@ export function buildIdentifierMap(): [
|
||||
start,
|
||||
end,
|
||||
new RegExp(openTagRx, "g"),
|
||||
new RegExp(closeTagRx, "g")
|
||||
new RegExp(closeTagRx, "g"),
|
||||
);
|
||||
}
|
||||
: undefined,
|
||||
@ -125,7 +127,7 @@ export const buildOnlyDefaultElements = () => {
|
||||
);
|
||||
},
|
||||
/(?<![\/\?])(?:\[\])+/g,
|
||||
/\/\[\]/g
|
||||
/\/\[\]/g,
|
||||
);
|
||||
|
||||
// card
|
||||
@ -170,7 +172,7 @@ export const buildOnlyDefaultElements = () => {
|
||||
);
|
||||
},
|
||||
/\[\[/g,
|
||||
/\]\]/g
|
||||
/\]\]/g,
|
||||
);
|
||||
|
||||
// fenced code block
|
||||
@ -192,7 +194,7 @@ export const buildOnlyDefaultElements = () => {
|
||||
{token.content}
|
||||
</pre>
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// list
|
||||
@ -231,7 +233,7 @@ export const buildOnlyDefaultElements = () => {
|
||||
</ul>
|
||||
</>
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// ordered-list
|
||||
@ -271,7 +273,7 @@ export const buildOnlyDefaultElements = () => {
|
||||
</ol>
|
||||
</>
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// ordered list-item
|
||||
@ -300,7 +302,7 @@ export const buildOnlyDefaultElements = () => {
|
||||
))}
|
||||
</li>
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// heading
|
||||
@ -336,7 +338,7 @@ export const buildOnlyDefaultElements = () => {
|
||||
{token.content}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// image
|
||||
@ -373,7 +375,7 @@ export const buildOnlyDefaultElements = () => {
|
||||
}
|
||||
// eslint-disable-next-line @next/next/no-img-element
|
||||
return <img src={metadata.src} alt={token.content} />;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// anchor
|
||||
@ -417,7 +419,7 @@ export const buildOnlyDefaultElements = () => {
|
||||
{token.content}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// inline-code
|
||||
@ -440,7 +442,7 @@ export const buildOnlyDefaultElements = () => {
|
||||
{token.content}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// bold
|
||||
@ -458,7 +460,7 @@ export const buildOnlyDefaultElements = () => {
|
||||
},
|
||||
(token) => {
|
||||
return <span className="font-bold">{token.content}</span>;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// italic
|
||||
@ -477,7 +479,7 @@ export const buildOnlyDefaultElements = () => {
|
||||
},
|
||||
(token) => {
|
||||
return <span className="italic">{token.content}</span>;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// popover
|
||||
@ -513,7 +515,7 @@ export const buildOnlyDefaultElements = () => {
|
||||
</span>
|
||||
</Poppable>
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// accordion
|
||||
@ -543,7 +545,7 @@ export const buildOnlyDefaultElements = () => {
|
||||
</Accordion>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// paragraph
|
||||
@ -569,7 +571,7 @@ export const buildOnlyDefaultElements = () => {
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// horizontal rule
|
||||
@ -587,7 +589,7 @@ export const buildOnlyDefaultElements = () => {
|
||||
},
|
||||
() => {
|
||||
return <div className="w-full border-b border-mixed-500 my-3"></div>;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// comment
|
||||
@ -605,7 +607,7 @@ export const buildOnlyDefaultElements = () => {
|
||||
},
|
||||
() => {
|
||||
return <></>;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// frontmatter
|
||||
@ -624,7 +626,7 @@ export const buildOnlyDefaultElements = () => {
|
||||
},
|
||||
(token) => {
|
||||
return <>{token.raw}</>;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// table
|
||||
@ -655,8 +657,8 @@ export const buildOnlyDefaultElements = () => {
|
||||
r
|
||||
.split("|")
|
||||
.map((c) => c.trim())
|
||||
.filter((c) => !!c)
|
||||
)
|
||||
.filter((c) => !!c),
|
||||
),
|
||||
);
|
||||
|
||||
let headerRows: string[][] = [],
|
||||
@ -679,7 +681,7 @@ export const buildOnlyDefaultElements = () => {
|
||||
}
|
||||
|
||||
const maxColumns = Math.max(
|
||||
...[...headerRows, ...bodyRows, ...footerRows].map((r) => r.length)
|
||||
...[...headerRows, ...bodyRows, ...footerRows].map((r) => r.length),
|
||||
);
|
||||
|
||||
return {
|
||||
@ -770,7 +772,7 @@ export const buildOnlyDefaultElements = () => {
|
||||
)}
|
||||
</table>
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// resolver
|
||||
@ -797,7 +799,7 @@ export const buildOnlyDefaultElements = () => {
|
||||
if (t.content.startsWith("Error"))
|
||||
return <span className="red-500">{t.content}</span>;
|
||||
return <Resolver resolver={t.content} />;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// on-demand resolver
|
||||
@ -839,7 +841,7 @@ export const buildOnlyDefaultElements = () => {
|
||||
title={t.metadata.title}
|
||||
/>
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
return TokenIdentifiers;
|
||||
@ -848,7 +850,7 @@ export const buildOnlyDefaultElements = () => {
|
||||
function findMatchingClosedParenthesis(
|
||||
str: string,
|
||||
openRegex: RegExp,
|
||||
closedRegex: RegExp
|
||||
closedRegex: RegExp,
|
||||
): number | null {
|
||||
let openings = 0;
|
||||
let closings = 0;
|
||||
@ -904,7 +906,7 @@ function search(
|
||||
start: number,
|
||||
end: number,
|
||||
openRx: RegExp,
|
||||
closeRx: RegExp
|
||||
closeRx: RegExp,
|
||||
): SearchResult {
|
||||
const oldEnd = end;
|
||||
|
||||
@ -912,7 +914,7 @@ function search(
|
||||
s,
|
||||
// s.substring(0, end - start),
|
||||
openRx,
|
||||
closeRx
|
||||
closeRx,
|
||||
);
|
||||
|
||||
if (newEnd === null)
|
||||
|
@ -1,9 +1,14 @@
|
||||
import { TTCQueryParser } from "@/lib/ttcQuery/TTCQueryParser";
|
||||
import { atom } from "recoil";
|
||||
import { atom } from "jotai";
|
||||
// import { atom } from "recoil";
|
||||
|
||||
export const PublicationAtom = atom({
|
||||
key: "publication",
|
||||
default: new TTCQueryParser({
|
||||
path: { to: { dice: "2d6" } },
|
||||
}),
|
||||
});
|
||||
// export const PublicationAtom = atom({
|
||||
// key: "publication",
|
||||
// default: new TTCQueryParser({
|
||||
// path: { to: { dice: "2d6" } },
|
||||
// }),
|
||||
// });
|
||||
|
||||
export const PublicationAtom = atom(
|
||||
new TTCQueryParser({ path: { to: { dice: "2d6" } } }),
|
||||
);
|
||||
|
@ -1,5 +1,6 @@
|
||||
// import { atom } from "recoil";
|
||||
|
||||
import { Schema } from "@/types";
|
||||
import { atom } from "jotai";
|
||||
|
||||
// export const SchemaEditAtom = atom<Schema>({
|
||||
@ -12,4 +13,5 @@ export const SchemaEditAtom = atom<Schema>({
|
||||
id: "",
|
||||
types: {},
|
||||
fields: {},
|
||||
version: 0,
|
||||
});
|
||||
|
@ -1,10 +1,6 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
@ -22,23 +18,11 @@
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"./*"
|
||||
]
|
||||
"@/*": ["./*"]
|
||||
},
|
||||
"target": "es2022"
|
||||
},
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
".next/types/**/*.ts",
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
],
|
||||
"files": [
|
||||
"global.d.ts",
|
||||
"./components/mdeditor/TextEditor.tsx"
|
||||
]
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||
"exclude": ["node_modules"],
|
||||
"files": ["global.d.ts", "types.d.ts", "./components/mdeditor/TextEditor.tsx"]
|
||||
}
|
3
types.d.ts
vendored
3
types.d.ts
vendored
@ -87,7 +87,8 @@ type Schema = {
|
||||
name: string;
|
||||
fields: SchemaFields;
|
||||
types: SchemaTypes;
|
||||
gameSystemId?: string;
|
||||
version: number;
|
||||
gameSystemId?: string | null;
|
||||
};
|
||||
|
||||
// Input Binder
|
||||
|
Loading…
x
Reference in New Issue
Block a user