diff --git a/bun.lockb b/bun.lockb index ffb6975..9e6de21 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index af1544c..b5558b7 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "@emotion/react": "^11.14.0", "@emotion/server": "^11.11.0", "@emotion/styled": "^11.14.0", + "@monaco-editor/react": "^4.6.0", "@mui/icons-material": "^6.3.1", "@mui/material": "^6.3.1", "@mui/material-nextjs": "^6.3.1", @@ -37,7 +38,7 @@ "remark-parse": "^11.0.0", "remark-rehype": "^11.1.1", "sitemap": "^8.0.0", - "solar-js-sdk": "^0.0.2", + "solar-js-sdk": "0.0.8", "unified": "^11.0.5", "zustand": "^5.0.3" }, diff --git a/packages/sn/package.json b/packages/sn/package.json index 4c1271f..fd9585d 100644 --- a/packages/sn/package.json +++ b/packages/sn/package.json @@ -8,7 +8,7 @@ "name": "LittleSheep", "email": "littlesheep.code@hotmail.com" }, - "version": "0.0.5", + "version": "0.0.8", "tsup": { "entry": [ "src/index.ts" diff --git a/packages/sn/src/matrix/release.ts b/packages/sn/src/matrix/release.ts index b609089..c73ca9d 100644 --- a/packages/sn/src/matrix/release.ts +++ b/packages/sn/src/matrix/release.ts @@ -6,7 +6,8 @@ export interface MaRelease { version: string type: number channel: string - assets: Record + assets: Record + installers: Record product_id: number meta: MaReleaseMeta } @@ -22,3 +23,19 @@ export interface MaReleaseMeta { attachments: string[] release_id: number } + +export interface MaReleaseAsset { + uri: string + contentType: string +} + +export interface MaReleaseInstallerPatch { + action: string + glob: string +} + +export interface MaReleaseInstaller { + workdir?: string + script?: string + patches: MaReleaseInstallerPatch[] +} diff --git a/src/components/matrix/MaReleaseForm.tsx b/src/components/matrix/MaReleaseForm.tsx index 37d65b5..8adb27d 100644 --- a/src/components/matrix/MaReleaseForm.tsx +++ b/src/components/matrix/MaReleaseForm.tsx @@ -11,15 +11,16 @@ import { Typography, Grid2 as Grid, IconButton, + Card, } from '@mui/material' import { useRouter } from 'next-nprogress-bar' import { useEffect, useState } from 'react' import { useForm } from 'react-hook-form' +import { MaProduct, MaRelease, MaReleaseAsset, MaReleaseInstaller, MaReleaseInstallerPatch } from 'solar-js-sdk' +import MonacoEditor from '@monaco-editor/react' import ErrorIcon from '@mui/icons-material/Error' import CloseIcon from '@mui/icons-material/Close' -import { MaProduct } from 'solar-js-sdk' -import { version } from 'node:os' export interface MatrixReleaseForm { version: string @@ -28,7 +29,8 @@ export interface MatrixReleaseForm { title: string description: string content: string - assets: Record + assets: Record + installers: Record attachments: string[] } @@ -41,7 +43,7 @@ export default function MaReleaseForm({ onSubmit: (data: MatrixReleaseForm) => Promise onSuccess?: () => void parent: Partial - defaultValue?: any + defaultValue?: MaRelease }) { const { handleSubmit, register } = useForm({ defaultValues: { @@ -56,17 +58,25 @@ export default function MaReleaseForm({ }) useEffect(() => { - if (defaultValue) { + if (defaultValue?.assets) { setAssets(Object.keys(defaultValue.assets).map((k) => ({ k, v: defaultValue.assets[k] }))) } + if (defaultValue?.installers) { + setInstallers(Object.keys(defaultValue.installers).map((k) => ({ k, v: defaultValue.installers[k] }))) + } }, []) const router = useRouter() - const [assets, setAssets] = useState<{ k: string; v: string }[]>([]) + const [assets, setAssets] = useState<{ k: string; v: MaReleaseAsset }[]>([]) + const [installers, setInstallers] = useState<{ k: string; v: MaReleaseInstaller }[]>([]) function addAsset() { - setAssets((val) => [...val, { k: '', v: '' }]) + setAssets((val) => [...val, { k: '', v: { uri: '', contentType: '' } }]) + } + + function addInstaller() { + setInstallers((val) => [...val, { k: '', v: { workdir: '', script: '', patches: [] } }]) } const [error, setError] = useState(null) @@ -83,7 +93,11 @@ export default function MaReleaseForm({ async function submit(data: MatrixReleaseForm) { try { setBusy(true) - await onSubmit({ ...data, assets: assets.reduce((a, { k, v }) => ({ ...a, [k]: v }), {}) }) + await onSubmit({ + ...data, + assets: assets.reduce((a, { k, v }) => ({ ...a, [k]: v }), {}), + installers: installers.reduce((a, { k, v }) => ({ ...a, [k]: v }), {}), + }) callback() } catch (err: any) { setError(err.toString()) @@ -105,7 +119,12 @@ export default function MaReleaseForm({ Type - Full Release Patch Release @@ -120,44 +139,64 @@ export default function MaReleaseForm({ - Assets + Assets {assets.map(({ k, v }, idx) => ( - - - { - setAssets((data) => - data.map((ele, index) => (index == idx ? { k: val.target.value, v: ele.v } : ele)), - ) - }} - /> - - - { - setAssets((data) => - data.map((ele, index) => (index == idx ? { v: val.target.value, k: ele.k } : ele)), - ) - }} - /> - - - { - setAssets((data) => data.filter((_, index) => index != idx)) - }} - > - - - - + + + + + { + setAssets((data) => + data.map((ele, index) => (index == idx ? { k: val.target.value, v: ele.v } : ele)), + ) + }} + /> + + + { + setAssets((data) => data.filter((_, index) => index != idx)) + }} + > + + + + + { + setAssets((data) => + data.map((ele, index) => + index == idx ? { v: { ...ele.v, uri: val.target.value }, k: ele.k } : ele, + ), + ) + }} + /> + + + { + setAssets((data) => + data.map((ele, index) => + index == idx ? { v: { ...ele.v, contentType: val.target.value }, k: ele.k } : ele, + ), + ) + }} + /> + + + + ))} @@ -167,6 +206,109 @@ export default function MaReleaseForm({ + + Installers + + {installers.map(({ k, v }, idx) => ( + + + + + { + setInstallers((data) => + data.map((ele, index) => (index == idx ? { k: val.target.value, v: ele.v } : ele)), + ) + }} + /> + + + { + setInstallers((data) => + data.map((ele, index) => + index == idx ? { k: ele.k, v: { ...ele.v, workdir: val.target.value } } : ele, + ), + ) + }} + /> + + + { + setInstallers((data) => data.filter((_, index) => index != idx)) + }} + > + + + + + + Script + + + + setInstallers((data) => + data.map((ele, index) => (index == idx ? { v: { ...ele.v, script: val }, k: ele.k } : ele)), + ) + } + /> + + + + + Patches + + + `${p.action}:${p.glob}`).join('\n')} + onChange={(val) => + setInstallers((data) => + data.map((ele, index) => + index == idx + ? { + v: { + ...ele.v, + patches: val?.split('\n')?.map((p) => ({ + action: p.split(':')[0], + glob: p.split(':')[1], + })) as MaReleaseInstallerPatch[], + }, + k: ele.k, + } + : ele, + ), + ) + } + /> + + + + + + ))} + + + + + + - - - - - - - - - ))} - - - - - + + Matrix Marketplace + + + The new way to release your app, implement version check and auto updating. + + + + + + + + + + + + {products.map((p) => ( + + + + + {p.name} + + {p.description} + + + + + + + + + + + + + ))} + diff --git a/src/pages/console/matrix/products/[id]/index.tsx b/src/pages/console/matrix/products/[id]/index.tsx index a5548c1..2fd4d97 100644 --- a/src/pages/console/matrix/products/[id]/index.tsx +++ b/src/pages/console/matrix/products/[id]/index.tsx @@ -1,7 +1,8 @@ import { ConsoleLayout, getConsoleStaticProps } from '@/components/layouts/ConsoleLayout' import { Box, Button, Container, Typography, Grid2 as Grid, Card, CardContent, CardActions } from '@mui/material' import { GetServerSideProps, InferGetServerSidePropsType } from 'next' -import { sni, MaProduct } from 'solar-js-sdk' +import { sni, MaProduct, MaRelease } from 'solar-js-sdk' +import { useEffect, useState } from 'react' import NextLink from 'next/link' export const getServerSideProps: GetServerSideProps = (async (context) => { @@ -9,28 +10,37 @@ export const getServerSideProps: GetServerSideProps = (async (context) => { const { data } = await sni.get('/cgi/ma/products/' + id) - const { data: resp } = await sni.get<{ data: any[] }>('/cgi/ma/products/' + id + '/releases', { - params: { - take: 10, - }, - }) - return getConsoleStaticProps({ props: { title: `Product "${data.name}"`, product: data, - releases: resp.data, }, }) -}) satisfies GetServerSideProps<{ product: MaProduct; releases: any[] }> +}) satisfies GetServerSideProps<{ product: MaProduct }> + +export default function ProductDetails({ product }: InferGetServerSidePropsType) { + const [releases, setReleases] = useState([]) + + async function fetchReleases() { + const { data: resp } = await sni.get<{ data: MaRelease[] }>('/cgi/ma/products/' + product.id + '/releases', { + params: { + take: 10, + }, + }) + + setReleases(resp.data) + } + + useEffect(() => { + fetchReleases() + }, []) -export default function ProductDetails({ product, releases }: InferGetServerSidePropsType) { async function deleteRelease(id: number) { const yes = confirm(`Are you sure you want to delete this release #${id}?`) if (!yes) return await sni.delete('/cgi/ma/products/' + product.id + '/releases/' + id) - window.location.reload() + await fetchReleases() } return (