Skip to content

Commit

Permalink
Merge pull request #25 from prtcl/spike/project-previews
Browse files Browse the repository at this point in the history
spike/project previews
  • Loading branch information
prtcl authored Nov 5, 2024
2 parents ad8abe2 + f86ce27 commit 897e162
Show file tree
Hide file tree
Showing 33 changed files with 2,098 additions and 449 deletions.
3 changes: 2 additions & 1 deletion .env
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
CONVEX_DEPLOYMENT=""
VITE_CONVEX_URL=""
VITE_CONVEX_URL=""
UPLOAD_TOKEN=""
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,7 @@ dist

## Panda
styled-system
styled-system-studio
styled-system-studio

# Generated files
previews
5 changes: 4 additions & 1 deletion convex/_generated/api.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
*
* THIS CODE IS AUTOMATICALLY GENERATED.
*
* Generated by [email protected].
* To regenerate, run `npx convex dev`.
* @module
*/
Expand All @@ -14,6 +13,8 @@ import type {
FilterApi,
FunctionReference,
} from "convex/server";
import type * as features from "../features.js";
import type * as previews from "../previews.js";
import type * as projects from "../projects.js";

/**
Expand All @@ -25,6 +26,8 @@ import type * as projects from "../projects.js";
* ```
*/
declare const fullApi: ApiFromModules<{
features: typeof features;
previews: typeof previews;
projects: typeof projects;
}>;
export declare const api: FilterApi<
Expand Down
1 change: 0 additions & 1 deletion convex/_generated/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
*
* THIS CODE IS AUTOMATICALLY GENERATED.
*
* Generated by [email protected].
* To regenerate, run `npx convex dev`.
* @module
*/
Expand Down
1 change: 0 additions & 1 deletion convex/_generated/dataModel.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
*
* THIS CODE IS AUTOMATICALLY GENERATED.
*
* Generated by [email protected].
* To regenerate, run `npx convex dev`.
* @module
*/
Expand Down
1 change: 0 additions & 1 deletion convex/_generated/server.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
*
* THIS CODE IS AUTOMATICALLY GENERATED.
*
* Generated by [email protected].
* To regenerate, run `npx convex dev`.
* @module
*/
Expand Down
1 change: 0 additions & 1 deletion convex/_generated/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
*
* THIS CODE IS AUTOMATICALLY GENERATED.
*
* Generated by [email protected].
* To regenerate, run `npx convex dev`.
* @module
*/
Expand Down
30 changes: 30 additions & 0 deletions convex/features.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { internalMutation, query } from './_generated/server';

export const loadFeatureFlags = query({
args: {},
handler: async (ctx) => {
return await ctx.db.query('features').collect();
},
});

export const populateFeatureFlags = internalMutation({
args: {},
handler: async (ctx) => {
const initialFlags = ['isProjectPreviewsEnabled'];
const existingFeatures = await ctx.db.query('features').collect();
const existingKeys = new Set(existingFeatures.map((f) => f.key));
const res: string[] = [];

for (const flag of initialFlags) {
if (!existingKeys.has(flag)) {
const insertedId = await ctx.db.insert('features', {
key: flag,
value: false,
});
res.push(insertedId);
}
}

return res;
},
});
84 changes: 84 additions & 0 deletions convex/previews.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { ConvexError, v } from 'convex/values';
import { mutation, query } from './_generated/server';

export const loadProjectPreview = query({
args: {
projectId: v.id('projects'),
},
handler: async (ctx, { projectId }) => {
const project = await ctx.db.get(projectId);

if (!project) {
throw new ConvexError({
message: 'Project not found',
code: 404,
});
}

const preview = await ctx.db
.query('previews')
.withIndex('project', (q) => q.eq('projectId', project._id))
.filter((q) => q.eq(q.field('deletedAt'), null))
.unique();

if (!preview) {
throw new ConvexError({
message: 'Preview not found',
code: 404,
});
}

const publicUrl = await ctx.storage.getUrl(preview.storageId);

if (publicUrl) {
return {
...preview,
publicUrl,
};
}

return null;
},
});

export const generateUploadUrl = mutation({
args: { token: v.string() },
handler: async (ctx, { token }) => {
if (token !== process.env.UPLOAD_TOKEN) {
throw new Error('Unauthorized');
}

const uploadUrl = await ctx.storage.generateUploadUrl();

return { uploadUrl };
},
});

export const createPreview = mutation({
args: {
projectId: v.id('projects'),
storageId: v.id('_storage'),
token: v.string(),
},
handler: async (ctx, { projectId, storageId, token }) => {
if (token !== process.env.UPLOAD_TOKEN) {
throw new Error('Unauthorized');
}

const existingPreview = await ctx.db
.query('previews')
.withIndex('project', (q) => q.eq('projectId', projectId))
.filter((q) => q.eq(q.field('deletedAt'), null))
.unique();

if (existingPreview) {
return await ctx.db.patch(existingPreview._id, { storageId });
}

return await ctx.db.insert('previews', {
deletedAt: null,
projectId,
storageId,
});
},
});
8 changes: 8 additions & 0 deletions convex/projects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,19 @@ export const loadProjects = query({
return await ctx.db
.query('projects')
.withIndex('deletedByOrder', (q) => q.eq('deletedAt', null))
.filter((q) => q.neq(q.field('publishedAt'), null))
.order('asc')
.paginate(paginationOpts);
},
});

export const loadAllProjects = query({
args: {},
handler: async (ctx) => {
return await ctx.db.query('projects').order('asc').collect();
},
});

export const reorderProjects = internalMutation({
args: {
id: v.id('projects'),
Expand Down
14 changes: 14 additions & 0 deletions convex/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,20 @@ const projects = defineTable({
url: v.string(),
}).index('deletedByOrder', ['deletedAt', 'order']);

const previews = defineTable({
deletedAt: v.union(v.number(), v.null()),
projectId: v.id('projects'),
storageId: v.id('_storage'),
}).index('project', ['projectId']);

export const features = defineTable({
description: v.optional(v.string()),
key: v.string(),
value: v.boolean(),
});

export default defineSchema({
features,
previews,
projects,
});
Loading

0 comments on commit 897e162

Please sign in to comment.