Skip to content

Commit

Permalink
refactor: config schemas
Browse files Browse the repository at this point in the history
  • Loading branch information
rharkor committed Sep 16, 2024
1 parent 066f065 commit b6f7c93
Show file tree
Hide file tree
Showing 20 changed files with 265 additions and 215 deletions.
2 changes: 2 additions & 0 deletions packages/cli-app/src/api/_app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ import { router } from "@/lib/trpc/init"

import { configurationRouter } from "./configuration/_router"
import { pluginsRouter } from "./plugins/_router"
import { storesRouter } from "./stores/_router"
import { templatesRouter } from "./templates/_router"

export const appRouter = router({
configuration: configurationRouter,
plugins: pluginsRouter,
templates: templatesRouter,
stores: storesRouter,
})

export type AppRouter = typeof appRouter
23 changes: 23 additions & 0 deletions packages/cli-app/src/api/stores/_router.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { publicProcedure, router } from "@/lib/trpc/init"

import { deleteStore, installOrUpdateStore } from "./mutations"
import { getStoresQuery } from "./queries"
import {
deleteStoreRequestSchema,
deleteStoreResponseSchema,
getStoresResponseSchema,
installOrUpdateStoreRequestSchema,
installOrUpdateStoreResponseSchema,
} from "./schemas"

export const storesRouter = router({
getStores: publicProcedure.output(getStoresResponseSchema()).query(getStoresQuery),
installOrUpdateStore: publicProcedure
.input(installOrUpdateStoreRequestSchema())
.output(installOrUpdateStoreResponseSchema())
.mutation(installOrUpdateStore),
deleteStore: publicProcedure
.input(deleteStoreRequestSchema())
.output(deleteStoreResponseSchema())
.mutation(deleteStore),
})
47 changes: 47 additions & 0 deletions packages/cli-app/src/api/stores/mutations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { z } from "zod"

import { getConfiguration, setConfiguration } from "@/lib/configuration"
import { handleDeleteStore, handleDownloadStore } from "@/lib/stores"
import { handleApiError } from "@/lib/utils/server-utils"
import { apiInputFromSchema } from "@/types"

import {
deleteStoreRequestSchema,
deleteStoreResponseSchema,
installOrUpdateStoreRequestSchema,
installOrUpdateStoreResponseSchema,
} from "./schemas"

export const installOrUpdateStore = async ({
input: { store },
}: apiInputFromSchema<typeof installOrUpdateStoreRequestSchema>) => {
try {
await handleDownloadStore(store, true)

const data: z.infer<ReturnType<typeof installOrUpdateStoreResponseSchema>> = { success: true }
return data
} catch (error: unknown) {
return handleApiError(error)
}
}

export const deleteStore = async ({ input: { store } }: apiInputFromSchema<typeof deleteStoreRequestSchema>) => {
try {
const configuration = await getConfiguration()

// Remove store from configuration
await setConfiguration({
...configuration,
plugins: configuration.plugins?.filter((p) => p.name !== store.name),
stores: configuration.stores?.filter((s) => s.name !== store.name),
})

// Delete form store folder
await handleDeleteStore(store)

const data: z.infer<ReturnType<typeof deleteStoreResponseSchema>> = { success: true }
return data
} catch (error: unknown) {
return handleApiError(error)
}
}
18 changes: 18 additions & 0 deletions packages/cli-app/src/api/stores/queries.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { z } from "zod"

import { getStores } from "@/lib/stores"
import { handleApiError } from "@/lib/utils/server-utils"
import { apiInputFromSchema } from "@/types"

import { getStoresResponseSchema } from "./schemas"

export const getStoresQuery = async ({}: apiInputFromSchema<typeof undefined>) => {
try {
const stores = await getStores()

const data: z.infer<ReturnType<typeof getStoresResponseSchema>> = { stores }
return data
} catch (error: unknown) {
return handleApiError(error)
}
}
20 changes: 20 additions & 0 deletions packages/cli-app/src/api/stores/schemas.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { z } from "zod"

import { fullStoreSchema } from "@/lib/stores"
import { storeConfigSchema } from "@next-boilerplate/scripts/utils/template-config/index.js"

export const getStoresResponseSchema = () => z.object({ stores: z.array(fullStoreSchema) })

export const installOrUpdateStoreRequestSchema = () =>
z.object({
store: storeConfigSchema,
})

export const installOrUpdateStoreResponseSchema = () => z.object({ success: z.boolean() })

export const deleteStoreRequestSchema = () =>
z.object({
store: storeConfigSchema,
})

export const deleteStoreResponseSchema = () => z.object({ success: z.boolean() })
2 changes: 1 addition & 1 deletion packages/cli-app/src/app/plugins/content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export default function PluginsContent({
? [...Array(5)].map((_, i) => (
<Plugin
key={i}
plugin={{ id: "", name: "", description: "", sourcePath: "", paths: [] }}
plugin={{ id: "", name: "", store: "", description: "", sourcePath: "", paths: [] }}
dictionary={dictionary}
ssrConfiguration={ssrConfiguration}
isLoading
Expand Down
1 change: 1 addition & 0 deletions packages/cli-app/src/app/stores/content.dr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export const StoresContentDr = dictionaryRequirements(
doNotTrustExternalStores: true,
remove: true,
update: true,
download: true,
},
HeaderDr
)
76 changes: 62 additions & 14 deletions packages/cli-app/src/app/stores/content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,19 @@ const formSchema = updateConfigurationRequestSchema().shape.configuration.shape.

export default function StoresContent({
ssrConfiguration,
ssrStores,
dictionary,
}: {
ssrConfiguration: RouterOutputs["configuration"]["getConfiguration"]
ssrStores: RouterOutputs["stores"]["getStores"]
dictionary: TDictionary<typeof StoresContentDr>
}) {
const configuration = trpc.configuration.getConfiguration.useQuery(undefined, {
initialData: ssrConfiguration,
})
const stores = trpc.stores.getStores.useQuery(undefined, {
initialData: ssrStores,
})

const [isAddStoreOpen, setIsAddStoreOpen] = useState(false)

Expand Down Expand Up @@ -66,7 +71,30 @@ export default function StoresContent({
setIsAddStoreOpen(false)
})

const isPending = updateConfigurationMutation.isPending
const installOrUpdateStoreMutation = trpc.stores.installOrUpdateStore.useMutation({
onSuccess: async () => {
await Promise.all([
utils.configuration.invalidate(),
utils.stores.invalidate(),
utils.plugins.invalidate(),
utils.templates.invalidate(),
])
},
})

const deleteStoreMutation = trpc.stores.deleteStore.useMutation({
onSuccess: async () => {
await Promise.all([
utils.configuration.invalidate(),
utils.stores.invalidate(),
utils.plugins.invalidate(),
utils.templates.invalidate(),
])
},
})

const isPending =
updateConfigurationMutation.isPending || installOrUpdateStoreMutation.isPending || deleteStoreMutation.isPending

return (
<>
Expand All @@ -86,24 +114,44 @@ export default function StoresContent({
notClickable
actions={
<>
<Button
variant="light"
color="warning"
onPress={() => {
//TODO
}}
isLoading={isPending}
>
<Download className="size-5" />
{dictionary.update}
</Button>
{stores.data.stores.some((s) => s.name === store.name && s.version === store.version) ? (
<Button
variant="light"
color="warning"
onPress={() => {
installOrUpdateStoreMutation.mutate({
store,
})
}}
isLoading={isPending}
>
<Download className="size-5" />
{dictionary.update}
</Button>
) : (
<Button
variant="light"
color="success"
onPress={() => {
installOrUpdateStoreMutation.mutate({
store,
})
}}
isLoading={isPending}
>
<Download className="size-5" />
{dictionary.download}
</Button>
)}
<Button
variant="light"
className="size-[40px] min-w-0 p-1"
color="danger"
aria-label={dictionary.remove}
onPress={() => {
//TODO
deleteStoreMutation.mutate({
store,
})
}}
isLoading={isPending}
>
Expand All @@ -114,7 +162,7 @@ export default function StoresContent({
key={store.name}
id={store.name}
title={store.name}
description={store.version}
description={dictionary.storeVersion + ": " + store.version}
/>
))}
</ul>
Expand Down
3 changes: 2 additions & 1 deletion packages/cli-app/src/app/stores/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ export default async function Stores() {
const locale = extractLocale()
const dictionary = await getDictionary(locale, dictionaryRequirements(StoresContentDr))
const ssrConfiguration = await trpc.configuration.getConfiguration()
const ssrStores = await trpc.stores.getStores()

return (
<Section>
<StoresContent ssrConfiguration={ssrConfiguration} dictionary={dictionary} />
<StoresContent ssrConfiguration={ssrConfiguration} ssrStores={ssrStores} dictionary={dictionary} />
</Section>
)
}
3 changes: 2 additions & 1 deletion packages/cli-app/src/langs/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -245,5 +245,6 @@
"storeNameExample": "@next-boilerplate/store",
"storeVersion": "Store version",
"storeVersionExample": "latest",
"doNotTrustExternalStores": "Do not trust external stores, make sure to check the code before adding it to your configuration."
"doNotTrustExternalStores": "Do not trust external stores, make sure to check the code before adding it to your configuration.",
"download": "Download"
}
3 changes: 2 additions & 1 deletion packages/cli-app/src/langs/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -245,5 +245,6 @@
"storeNameExample": "@next-boilerplate/store",
"storeVersion": "Version du magasin",
"storeVersionExample": "latest",
"doNotTrustExternalStores": "Ne faites pas confiance aux magasins externes, assurez-vous de vérifier le code avant de l'ajouter à votre configuration."
"doNotTrustExternalStores": "Ne faites pas confiance aux magasins externes, assurez-vous de vérifier le code avant de l'ajouter à votre configuration.",
"download": "Télécharger"
}
11 changes: 4 additions & 7 deletions packages/cli-app/src/lib/configuration/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,12 @@ const webConfigToApiConfig = (webConfig: TConfiguration): z.infer<typeof optiona
plugins: (webConfig.plugins ?? []).map((plugin) => {
const fullP = {
name: plugin.sourcePath,
store: plugin.store,
paths: plugin.paths.map((p) => ({
from: p.from,
to: p.overridedTo || p.to,
})),
}
//? If there's no override, or the override is the same as the original path, return the name
if (!plugin.paths.some((p) => p.overridedTo) || plugin.paths.every((p) => p.to === p.overridedTo)) {
return fullP.name
}
return fullP
}),
stores: webConfig.stores ?? [
Expand Down Expand Up @@ -77,17 +74,17 @@ const apiConfigToWebConfig = async (apiConfig: z.infer<typeof optionalConfigSche
const content: TConfiguration = {
name: apiConfig.name,
plugins: apiConfig.plugins?.map((plugin) => {
const pluginSP = typeof plugin === "string" ? plugin : plugin.name
const foundPlugin = plugins.find((p) => p.sourcePath === pluginSP)
const foundPlugin = plugins.find((p) => p.name === plugin.name && p.store === plugin.store)
if (!foundPlugin) {
throw new TRPCError({
message: `The plugin ${pluginSP} is not valid`,
message: `The plugin ${plugin.name} not found (store: ${plugin.store})`,
code: "INTERNAL_SERVER_ERROR",
})
}

return {
name: foundPlugin.name,
store: foundPlugin.store,
description: foundPlugin.description,
id: foundPlugin.id,
sourcePath: foundPlugin.sourcePath,
Expand Down
Loading

0 comments on commit b6f7c93

Please sign in to comment.