From 317cd235dd2e27542230c879a36d573570d058e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20=C5=A0o=C5=A1i=C4=87?= Date: Wed, 22 May 2024 13:16:37 +0200 Subject: [PATCH 1/5] Improved contributing instructions. (#130) --- CONTRIBUTING.md | 46 ++++++++++++++++++++++++---------------------- README.md | 24 +++++++----------------- 2 files changed, 31 insertions(+), 39 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c1a89ab..b1fc64d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,24 +1,34 @@ Thanks so much for considering contributing to Open SaaS πŸ™ ## Considerations before Contributing +Check if there is a GitHub issue already for the thing you would like to work on. If there is no issue yet, create a new one. -### General Considerations -1. If there's something you'd like to add, and the issue doesn't already exist, create a new one and assign yourself to it. Wait until we've agreed on a plan of action before beginning your work. -2. If the issue does already exist, and noone is assigned to it, assign yourself and feel free to begin working on it. +Let us know, in the issue, that you would like to work on it and how you plan to approach it. +This helps, especially with the more complex issues, as it allows us to discuss the solution upfront and make sure it is well planned and fits with the rest of the project. -### How Users Get the Starter Template +## How to Contribute +1. Make sure you understand the basics of how open-saas works (check out [docs](https://docs.opensaas.sh)). +2. Check out this repo (`main` branch) and make sure you are able to get the app in `app/` running (to set it up, follow the same steps as for running a new open-saas app, as explained in the open-saas docs). +3. Create a new git branch for your work (aka feature branch) and do your changes on it. +4. Update e2e tests in [e2e-tests](/e2e-tests/) if needed and make sure they are passing. +5. Create a pull request (towards `main` as a base branch). +6. If docs (also) need updating, check out the `deployed-version` branch, make your own feature branch from it, make changes in [blog/src/content/docs](/blog/src/content/docs/), and submit another PR with those changes (towards `deployed-version` as a base branch). +7. Make a "Da Boi" meme while you wait for us to review your PR(s). +8. If you don't know who "Da Boi" is, head back to the [Wasp Discord](https://discord.gg/aCamt5wCpS) and find out :) -We currently have two ways to pull the template: -1. the `use this template` button on the [repo homepage](https://github.com/wasp-lang/open-saas) -2. the [Wasp CLI's](https://wasp-lang.dev/docs/quick-start) `wasp new` command +## Additional Info -When pulling the template via `wasp new`, the Wasp CLI looks for a tag `wasp-{CURRENT_VERSION}-template` associated with a specific commit on the Open SaaS repo. +### Template Versioning -In order to keep this tag up to date, we've created a github action, `.github/workflows/retag-commit.yml`, that automatically reassigns the tag (defined as `TAG_NAME` in the action) to the most recent commit on `main`. +Whenever a user starts a new Wasp project with `wasp new -t `, Wasp looks for a specific tag on the template repo, and pulls the project at the commit associated with that tag. -**This means, that whenever a user pulls the template, they are getting the version present in the most recent commit on `main`** +In the case of Open SaaS, which is a Wasp template, the tag is `wasp-v{{version}}-template`, where `{{version}}` is the current version of Wasp, e.g. `wasp-v0.13-template`. -Also, If we update Wasp to a new major version, we should also update the `TAG_NAME` in the action. +For simplicity, in Open SaaS, we automatically re-apply the tag to the most recent commit on the `main` branch via the `.github/workflows/retag-commit.yml` workflow. This way, users always get the latest version of the template (as on `main` branch) when they start a new project via `wasp new -t saas`. + +**This means, that whenever a user pulls the template via `wasp new -t saas`, they are getting the version present in the most recent commit on `main`.** + +NOTE: When Wasp releases a new major version, we should also make sure to update Open SaaS to work with this new version. In PR that will bring this update, we should also make sure to update the `TAG_NAME` in the GitHub Workflow that does the tagging, to be the template tag used by the newest version of Wasp. ### The Default Template vs. the Deployed Site / Docs @@ -26,16 +36,8 @@ There are two main branches for development: - `main` - `deployed-version` -The default, clean template that users get when cloning the starter lives on `main`, while `deployed-version` is what you see when you go to [OpenSaaS.sh](https://opensaas.sh) and the [docs](https://docs.opensaas.sh) +The default, clean template that users get when cloning the starter lives on `main`, while `deployed-version` is somewhat modified version of that same template which you see when you go to [OpenSaaS.sh](https://opensaas.sh) and the [docs](https://docs.opensaas.sh). -If you want to make changes to the default starter template, base feature branches and Pull Requests off of `main` -If you want to make changes to the OpenSaaS.sh site or it's Documentation, base feature branches and Pull Requests off of `deployed-version` +If you want to make changes to the default starter template, base feature branches and Pull Requests off of `main`. +If you want to make changes to the OpenSaaS.sh site or it's Documentation, base feature branches and Pull Requests off of `deployed-version`. -## How to contribute -Contributing is simple: -1. Make sure you've installed and run the app. -2. Find something you'd like to work on. Check out the [issues](https://github.com/wasp-lang/open-saas/issues) or contact us on the [Wasp Discord](https://discord.gg/aCamt5wCpS) to discuss. -3. Create a new feature branch for your work. See [above](#the-default-template-vs-the-deployed-site--docs) for which branch to base your feature branch off of. -4. Create a pull request. -5. Make a "Da Boi" meme while you wait for us to review your PR. -6. If you don't know who "Da Boi" is, head back to the [Wasp Discord](https://discord.gg/aCamt5wCpS) and find out :) diff --git a/README.md b/README.md index 6ed515b..072236c 100644 --- a/README.md +++ b/README.md @@ -63,25 +63,15 @@ For everything you need to know about getting started and using this template, c We've documented everything in great detail, including installation instructions, pulling updates to the template, guides for integrating services, SEO, deployment, and more. πŸš€ - -## Changes & Contributions - -### Template Versioning - -Whenever a user starts a new Open SaaS project with `wasp new -t saas`, Wasp looks for a specific tag on the repo, and pulls the project at the commit associated with that tag. In the case of Open SaaS, the tag is `wasp-v{{version}}-template`, where `{{version}}` is the current version of Wasp, e.g. `wasp-v0.13-template`. - -For simplicity, we automatically re-apply the tag to the most recent commit on the `main` branch via the `.github/workflows/retag-commit.yml` workflow. This way, users always get the latest version of the template when they start a new project via `wasp new -t saas`.d - -### Contributing - -Note that we've tried to get as many of the core features of a SaaS app into this template as possible, but there still might be some missing features or functionality. - -We could always use some help tying up loose ends, so consider [contributing](https://github.com/wasp-lang/open-saas/blob/main/CONTRIBUTING.md)! - -As there are a few things to know and consider when contributing, please make sure to read the [CONTRIBUTING.md](https://github.com/wasp-lang/open-saas/blob/main/CONTRIBUTING.md) in this Repo. - ## Getting Help & Providing Feedback There are two ways to get help or provide feedback (and we try to always respond quickly!): 1. [Open an issue](https://github.com/wasp-lang/open-saas/issues) 2. [Wasp Discord](https://discord.gg/aCamt5wCpS) -- please direct questions to the #πŸ™‹questions forum channel + +## Contributing + +Note that we've tried to get as many of the core features of a SaaS app into this template as possible, but there still might be some missing features or functionality. + +We could always use some help tying up loose ends: contributions are welcome! Check out [CONTRIBUTING.md](/CONTRIBUTING.md) for more details. + From 162357503ea6a85720527317b94b1a9e61d2e2db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20=C5=A0o=C5=A1i=C4=87?= Date: Wed, 22 May 2024 13:24:08 +0200 Subject: [PATCH 2/5] main.wasp polish (#134) * Polished small things in main.wasp. * Polished many small things in main.wasp file. --- app/main.wasp | 122 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 78 insertions(+), 44 deletions(-) diff --git a/app/main.wasp b/app/main.wasp index 7412dd4..3b0434a 100644 --- a/app/main.wasp +++ b/app/main.wasp @@ -2,32 +2,37 @@ app OpenSaaS { wasp: { version: "^0.13.2" }, + title: "My Open SaaS App", + head: [ "", "", - "", + "", "", "", - "", + "", "", "", "", - // you can put your analytics scripts here - "", - // plausible has script extension `script.local.js` for local development - "", - // google analytics only needs one script and will automatically detect if you are in dev mode - "" + // TODO: You can put your analytics scripts below (https://docs.opensaas.sh/guides/analytics/): + // If you are going with Plausible: + "", // for production + "", // for development + // If you are going with Google Analytics: + "" // for both production and development ], + // πŸ” Auth out of the box! https://wasp-lang.dev/docs/auth/overview auth: { userEntity: User, methods: { + // NOTE: If you decide to not use email auth, make sure to also delete the related routes and pages below. + // (RequestPasswordReset(Route|Page), PasswordReset(Route|Page), EmailVerification(Route|Page)) email: { fromField: { name: "Open SaaS App", - email: "me@example.com" + email: "me@example.com" }, emailVerification: { clientRoute: EmailVerificationRoute, @@ -39,10 +44,12 @@ app OpenSaaS { }, userSignupFields: import { getEmailUserFields } from "@src/server/auth/setUsername.js", }, - // google: { // Guide for setting up Auth via Google https://wasp-lang.dev/docs/auth/social-auth/overview + // Uncomment to enable Google Auth (check https://wasp-lang.dev/docs/auth/social-auth/google for setup instructions): + // google: { // Guide for setting up Auth via Google // userSignupFields: import { getGoogleUserFields } from "@src/server/auth/setUsername.js", // configFn: import { getGoogleAuthConfig } from "@src/server/auth/setUsername.js", // }, + // Uncomment to enable GitHub Auth (check https://wasp-lang.dev/docs/auth/social-auth/github for setup instructions): // gitHub: { // userSignupFields: import { getGitHubUserFields } from "@src/server/auth/setUsername.js", // configFn: import { getGitHubAuthConfig } from "@src/server/auth/setUsername.js", @@ -51,98 +58,114 @@ app OpenSaaS { onAuthFailedRedirectTo: "/login", onAuthSucceededRedirectTo: "/demo-app", }, - db: { + + db: { system: PostgreSQL, + // Run `wasp db seed` to seed the database with the seed functions below: seeds: [ + // Populates the database with a bunch of fake users to work with during development. import { devSeedUsers } from "@src/server/scripts/usersSeed.js", ] }, + client: { rootComponent: import App from "@src/client/App", }, - + emailSender: { - // Note that the "Dummy" provider is just for local development purposes. - // Make sure to check the server logs for the confirmation email token (it will not be sent to an address)! - // Please use SendGrid in production. See: https://docs.opensaas.sh/guides/email-sending/ - provider: Dummy, + // NOTE: "Dummy" provider is just for local development purposes. + // Make sure to check the server logs for the email confirmation url (it will not be sent to an address)! + // Once you are ready for production, switch to e.g. "SendGrid" or "MailGun" providers. Check out https://docs.opensaas.sh/guides/email-sending/ . + provider: Dummy, defaultFrom: { name: "Open SaaS App", - // When using SendGrid, you must use the same email address that you configured your account to send out emails with! - email: "me@example.com" + // When using a real provider, e.g. SendGrid, you must use the same email address that you configured your account to send out emails with! + email: "me@example.com" }, }, } -/* πŸ’½ Wasp defines DB entities via Prisma Database Models: +/* πŸ’½ Wasp defines DB entities via Prisma Database Models: * https://wasp-lang.dev/docs/data-model/entities */ entity User {=psl id Int @id @default(autoincrement()) + createdAt DateTime @default(now()) + email String? @unique username String? @unique - createdAt DateTime @default(now()) lastActiveTimestamp DateTime @default(now()) isAdmin Boolean @default(false) - stripeId String? + + stripeId String? checkoutSessionId String? subscriptionTier String? subscriptionStatus String? sendEmail Boolean @default(false) datePaid DateTime? credits Int @default(3) + gptResponses GptResponse[] - contactFormMessages ContactFormMessage[] + contactFormMessages ContactFormMessage[] tasks Task[] files File[] psl=} entity GptResponse {=psl id String @id @default(uuid()) - content String - user User @relation(fields: [userId], references: [id]) - userId Int createdAt DateTime @default(now()) updatedAt DateTime @updatedAt + + user User @relation(fields: [userId], references: [id]) + userId Int + + content String psl=} entity Task {=psl id String @id @default(uuid()) + createdAt DateTime @default(now()) + + user User @relation(fields: [userId], references: [id]) + userId Int + description String time String @default("1") isDone Boolean @default(false) - user User @relation(fields: [userId], references: [id]) - userId Int - createdAt DateTime @default(now()) psl=} entity File {=psl id String @id @default(uuid()) + createdAt DateTime @default(now()) + + user User @relation(fields: [userId], references: [id]) + userId Int + name String type String key String uploadUrl String - user User @relation(fields: [userId], references: [id]) - userId Int - createdAt DateTime @default(now()) psl=} // TODO: add functionality to allow users to send messages to admin // and make them accessible via the admin dashboard entity ContactFormMessage {=psl id String @id @default(uuid()) - content String + createdAt DateTime @default(now()) + user User @relation(fields: [userId], references: [id]) userId Int - createdAt DateTime @default(now()) + + content String isRead Boolean @default(false) - repliedAt DateTime? + repliedAt DateTime? psl=} -entity DailyStats {=psl +entity DailyStats {=psl id Int @id @default(autoincrement()) date DateTime @default(now()) @unique + totalViews Int @default(0) prevDayViewsChangePercent String @default("0") userCount Int @default(0) @@ -151,26 +174,31 @@ entity DailyStats {=psl paidUserDelta Int @default(0) totalRevenue Float @default(0) totalProfit Float @default(0) + sources PageViewSource[] psl=} entity PageViewSource {=psl - date DateTime @default(now()) - name String - visitors Int + @@id([date, name]) + name String + date DateTime @default(now()) + dailyStats DailyStats? @relation(fields: [dailyStatsId], references: [id]) dailyStatsId Int? - @@id([date, name]) + + visitors Int psl=} entity Logs {=psl id Int @id @default(autoincrement()) createdAt DateTime @default(now()) + message String level String psl=} -/* πŸ“‘ These are the Wasp Routes (You can protect them easily w/ 'authRequired: true'); +/* πŸ“‘ These are the Wasp client Routes and Pages. + * You can easily make them inaccessible to the unauthenticated user w/ 'authRequired: true'. * https://wasp-lang.dev/docs/tutorial/pages */ @@ -179,6 +207,7 @@ page LandingPage { component: import LandingPage from "@src/client/landing-page/LandingPage" } +//#region Auth Pages route LoginRoute { path: "/login", to: LoginPage } page LoginPage { component: import Login from "@src/client/auth/LoginPage" @@ -203,6 +232,7 @@ route EmailVerificationRoute { path: "/email-verification", to: EmailVerificatio page EmailVerificationPage { component: import { EmailVerification } from "@src/client/auth/EmailVerification", } +//#endregion route DemoAppRoute { path: "/demo-app", to: DemoAppPage } page DemoAppPage { @@ -233,6 +263,7 @@ page FileUploadPage { component: import FileUpload from "@src/client/app/FileUploadPage" } +//#region Admin Pages route AdminRoute { path: "/admin", to: DashboardPage } page DashboardPage { authRequired: true, @@ -292,8 +323,10 @@ page AdminUIButtonsPage { authRequired: true, component: import AdminUI from "@src/client/admin/pages/UiElements/Buttons" } +//#endregion -/* β›‘ These are the Wasp Operations, which allow the client and server to interact: +/* β›‘ These are the Wasp Operations: server code that you can easily call + * from the client. Queries fetch stuff, Actions modify/do stuff. * https://wasp-lang.dev/docs/data-model/operations/overview */ @@ -373,9 +406,10 @@ query getPaginatedUsers { } /* - * πŸ“‘ These are custom Wasp API Endpoints. Use them for callbacks, webhooks, etc. + * πŸ“‘ These are custom Wasp API Endpoints. + * Use them for callbacks, webhooks, API for other services to consume, etc. * https://wasp-lang.dev/docs/advanced/apis - */ + */ api stripeWebhook { fn: import { stripeWebhook } from "@src/server/webhooks/stripe.js", @@ -384,7 +418,7 @@ api stripeWebhook { httpRoute: (POST, "/stripe-webhook") } -/* πŸ•΅οΈβ€β™‚οΈ These are the Wasp Jobs. Use them to set up recurring tasks and/or queues: +/* πŸ•΅οΈβ€β™‚οΈ These are the Wasp Jobs. Use them to set up recurring tasks and/or queues. * https://wasp-lang.dev/docs/advanced/jobs */ From a1395d7b70c5e60494a3b7abc1410c74c912e276 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20=C5=A0o=C5=A1i=C4=87?= Date: Wed, 22 May 2024 13:25:32 +0200 Subject: [PATCH 3/5] Replaced string routes with typed routes. (#135) --- app/src/client/components/AppNavBar.tsx | 10 +++++----- app/src/client/landing-page/contentSections.ts | 3 ++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/app/src/client/components/AppNavBar.tsx b/app/src/client/components/AppNavBar.tsx index 9d64be9..0a44d7e 100644 --- a/app/src/client/components/AppNavBar.tsx +++ b/app/src/client/components/AppNavBar.tsx @@ -1,4 +1,4 @@ -import { Link } from 'wasp/client/router'; +import { Link, routes } from 'wasp/client/router'; import { useAuth } from 'wasp/client/auth'; import { useState } from 'react'; import { Dialog } from '@headlessui/react'; @@ -12,9 +12,9 @@ import DarkModeSwitcher from '../admin/components/DarkModeSwitcher'; import { UserMenuItems } from '../components/UserMenuItems'; const navigation = [ - { name: 'AI Scheduler (Demo App)', href: '/demo-app' }, - { name: 'File Upload (AWS S3)', href: '/file-upload' }, - { name: 'Pricing', href: '/pricing' }, + { name: 'AI Scheduler (Demo App)', href: routes.DemoAppRoute.build() }, + { name: 'File Upload (AWS S3)', href: routes.FileUploadRoute.build() }, + { name: 'Pricing', href: routes.PricingPageRoute.build() }, { name: 'Documentation', href: DOCS_URL }, { name: 'Blog', href: BLOG_URL }, ]; @@ -60,7 +60,7 @@ export default function AppNavBar() { {isUserLoading ? null : !user ? ( - +
Log in
diff --git a/app/src/client/landing-page/contentSections.ts b/app/src/client/landing-page/contentSections.ts index 09eca56..fa505f4 100644 --- a/app/src/client/landing-page/contentSections.ts +++ b/app/src/client/landing-page/contentSections.ts @@ -1,10 +1,11 @@ import { DOCS_URL, BLOG_URL } from '../../shared/constants'; import daBoiAvatar from '../static/da-boi.png'; import avatarPlaceholder from '../static/avatar-placeholder.png'; +import { routes } from 'wasp/client/router'; export const navigation = [ { name: 'Features', href: '#features' }, - { name: 'Pricing', href: '/pricing' }, + { name: 'Pricing', href: routes.PricingPageRoute.build() }, { name: 'Documentation', href: DOCS_URL }, { name: 'Blog', href: BLOG_URL }, ]; From 8490871b6eef3110fc8276cc9f85d5903900d55e Mon Sep 17 00:00:00 2001 From: Vedran Blazenka <1723170+vblazenka@users.noreply.github.com> Date: Wed, 22 May 2024 13:25:59 +0200 Subject: [PATCH 4/5] Remove sticky positioning from AppNavBar (#136) --- app/src/client/components/AppNavBar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/client/components/AppNavBar.tsx b/app/src/client/components/AppNavBar.tsx index 0a44d7e..4436a48 100644 --- a/app/src/client/components/AppNavBar.tsx +++ b/app/src/client/components/AppNavBar.tsx @@ -26,7 +26,7 @@ export default function AppNavBar() { const { data: user, isLoading: isUserLoading } = useAuth(); return ( -
+