Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

updates #340

Merged
merged 3 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"scripts": {
"quick": "cross-env PGLITE=true tsx scripts/quick.ts && cross-env PGLITE=true pnpm dev",
"start": "tsx dist/index.js",
"dev": "cross-env NODE_ENV=development tsx --watch src/index.ts",
"dev": "tsx scripts/drizzle-studio.ts && cross-env NODE_ENV=development tsx --watch src/index.ts",
"check:types": "tsc",
"build": "cross-env NODE_ENV=production tsup",
"build:dev": "tsup",
Expand Down
26 changes: 12 additions & 14 deletions backend/scripts/drizzle-studio.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
import { spawn } from 'node:child_process';
import chalk from 'chalk';

// Function to start Drizzle Studio
export const startDrizzleStudio = () => {
const startDrizzleStudioInBackground = () => {
const studioProcess = spawn('npx', ['drizzle-kit', 'studio'], {
stdio: 'inherit',
shell: true,
detached: true, // Detach the process
stdio: 'ignore', // Ignore its output to let the parent process exit cleanly
shell: true, // Use shell for compatibility
});

studioProcess.on('close', (code) => {
if (code === 0) {
console.log('Drizzle Studio exited successfully.');
} else {
console.error(`Drizzle Studio exited with code ${code}.`);
}
});
// Detach the child process from the parent
studioProcess.unref();

studioProcess.on('error', (err) => {
console.error('Failed to start Drizzle Studio:', err);
});
console.log(' ');
console.log(`${chalk.greenBright.bold('✔')} Drizzle Studio started in the background`);
console.log(' ');
};

startDrizzleStudioInBackground();
2 changes: 2 additions & 0 deletions backend/scripts/quick.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ await migrate(db, { migrationsFolder: 'drizzle', migrationsSchema: 'drizzle-back
const res = await db.execute(sql`SELECT * FROM users`);

if (res.rows.length > 0) {
console.info(' ');
console.info(`${chalk.greenBright.bold('✔')} Database is already seeded`);
console.info(' ');
process.exit(0);
}

Expand Down
10 changes: 7 additions & 3 deletions backend/scripts/seeds/organizations/seed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ const SYSTEM_ADMIN_MEMBERSHIP_COUNT = 10;

// Seed organizations with data
export const organizationsSeed = async () => {
console.info('Seeding organizations...');
console.info(' ');
console.info('◔ Seeding organizations...');

const organizationsInTable = await db.select().from(organizationsTable).limit(1);

Expand Down Expand Up @@ -53,7 +54,8 @@ export const organizationsSeed = async () => {
});

await db.insert(organizationsTable).values(organizations).onConflictDoNothing();
console.info('Seeding members and memberships, this can take a while...');
console.info(' ');
console.info('◔ Seeding members and memberships, this can take a while...');

const hashedPassword = await hashPasswordWithArgon('12345678');

Expand Down Expand Up @@ -138,5 +140,7 @@ export const organizationsSeed = async () => {
await db.insert(membershipsTable).values(memberships).onConflictDoNothing();
}

console.info(`${chalk.greenBright.bold('✔')} Created ${ORGANIZATIONS_COUNT} organizations with ${MEMBERS_COUNT} members each.`);
console.info(' ');
console.info(`${chalk.greenBright.bold('✔')} Created ${ORGANIZATIONS_COUNT} organizations with ${MEMBERS_COUNT} members each`);
console.info(' ');
};
6 changes: 5 additions & 1 deletion backend/scripts/seeds/user/seed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,9 @@ export const userSeed = async () => {
})
.onConflictDoNothing();

console.info(`${chalk.greenBright.bold('✔')} Created admin user with verified email ${adminUser.email} and password ${adminUser.password}.`);
console.info(' ');
console.info(
`${chalk.greenBright.bold('✔')} Created admin user with verified email ${chalk.greenBright.bold(adminUser.email)} and password ${chalk.greenBright.bold(adminUser.password)}.`,
);
console.info(' ');
};
9 changes: 3 additions & 6 deletions backend/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { migrate as pgliteMigrate } from 'drizzle-orm/pglite/migrator';
import { db } from '#/db/db';
import ascii from '#/utils/ascii';
import { env } from '../env';
import { startDrizzleStudio } from '../scripts/drizzle-studio';
import docs from './lib/docs';
import app from './routes';

Expand All @@ -33,9 +32,6 @@ const main = async () => {
await pgMigrate(db, migrateConfig);
}

// Start Drizzle Studio in development mode
if (config.mode === 'development') startDrizzleStudio();

// Start server
serve(
{
Expand All @@ -45,10 +41,11 @@ const main = async () => {
},
() => {
ascii();
console.info(' ');
console.info(
`Open ${chalk.greenBright.bold(config.name)} on ${chalk.cyanBright(config.frontendUrl)}. Backend on ${chalk.cyanBright(config.backendUrl)}`,
`${chalk.greenBright.bold(config.name)} (Frontend) runs on ${chalk.cyanBright.bold(config.frontendUrl)}. Backend: ${chalk.cyanBright.bold(config.backendUrl)}. Docs: ${chalk.cyanBright(`${config.backendUrl}/docs`)}`,
);
console.info(`Read API docs on ${chalk.cyanBright(`${config.backendUrl}/docs`)}`);
console.info(' ');
},
);
};
Expand Down
11 changes: 10 additions & 1 deletion backend/src/lib/mailer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,21 @@ import { config } from 'config';
import { env } from '../../env';

const sendgrid = new MailService();
// Check if the API key is set
const hasApiKey = !!env.SENDGRID_API_KEY;

sendgrid.setApiKey(env.SENDGRID_API_KEY ?? '');
if (hasApiKey) {
sendgrid.setApiKey(env.SENDGRID_API_KEY ?? '');
}

// Send email, currently hardcoded to use SendGrid but can be changed to any other service
export const emailSender = {
send: async (to: string, subject: string, html: string, replyTo?: string) => {
if (!hasApiKey) {
console.info(`Email to ${to} is not sent because API key is missing.`);
return;
}

await sendgrid.send({
to: env.SEND_ALL_TO_EMAIL || to,
replyTo: replyTo ? replyTo : config.supportEmail,
Expand Down
2 changes: 1 addition & 1 deletion cli/create-cella/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@cellajs/create-cella",
"version": "0.1.0",
"version": "0.1.1",
"private": false,
"license": "MIT",
"description": "Cella is a TypeScript template to create web apps with sync and offline capabilities.",
Expand Down
5 changes: 4 additions & 1 deletion cli/create-cella/src/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,6 @@ export async function create({

if (needsCd) {
// Calculate the relative path between the original working directory and the target folder

console.info('now go to your project using:');
console.info(colors.cyan(` cd ${relativePath}`)); // Adding './' to make it clear it's a relative path
console.info();
Expand All @@ -184,6 +183,10 @@ export async function create({
console.info(colors.cyan(` ${packageManager} seed`));
console.info();

console.info(`You can directly sign in using:`);
console.info(`email: ${colors.greenBright('[email protected]')}`);
console.info(`password: ${colors.greenBright('12345678')}`);
console.info();
console.info(`For more info, check out: ${relativePath}/README.md`);
console.info(`Enjoy building ${projectName} using cella! 🎉`);
console.info();
Expand Down
3 changes: 2 additions & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
},
"scripts": {
"quick": "cross-env VITE_QUICK=true pnpm dev",
"dev": "cross-env NODE_ENV=development vite --mode development && node --trace-warnings",
"start": "cross-env NODE_ENV=production pnpm preview",
"check:types": "tsc",
"dev": "cross-env NODE_ENV=development vite --mode development && node --trace-warnings",
"build": "tsc && vite build",
"build:dev": "cross-env NODE_ENV=development vite build --mode development",
"preview": "vite preview --port 3000",
Expand Down Expand Up @@ -141,6 +141,7 @@
"@vitejs/plugin-react": "^4.3.4",
"autoprefixer": "^10.4.20",
"cross-env": "^7.0.3",
"kill-port": "^2.0.1",
"postcss": "^8.4.49",
"postcss-import": "^16.1.0",
"postcss-preset-env": "^10.1.3",
Expand Down
33 changes: 28 additions & 5 deletions frontend/src/alert-config.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,30 @@
import { config } from 'config';
import { t } from 'i18next';
import { Info } from 'lucide-react';
import type { MainAlert } from '~/modules/common/main-alert';

// Here you can set app-specific global alerts
export const alertsConfig: MainAlert[] = [
{
const alerts = [];

// Explain how to sign in using test account
if (config.mode === 'development') {
alerts.push({
id: 'test-credentials',
Icon: Info,
className: 'rounded-none border-0 border-t z-10 fixed bottom-0 left-0 right-0',
children: (
<>
<strong className="mr-2">Testing credentials</strong>
<p>
Hi there! New developer? Welcome to Cella! Sign in using <strong>[email protected]</strong> and password <strong>12345678</strong>.
</p>
</>
),
});
}

// In production mode, show a notice that the app is a pre-release version
if (config.mode === 'production') {
alerts.push({
id: 'prerelease',
Icon: Info,
className: 'rounded-none border-0 border-b',
Expand All @@ -14,5 +34,8 @@ export const alertsConfig: MainAlert[] = [
{t('common:experiment_notice.text')}
</>
),
},
];
});
}

// Here you can set app-specific global alerts
export const alertsConfig: MainAlert[] = alerts;
2 changes: 1 addition & 1 deletion frontend/src/modules/auth/sign-up-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { Input } from '~/modules/ui/input';
import type { TokenData } from '.';

const PasswordStrength = lazy(() => import('~/modules/auth/password-strength'));
const LegalText = lazy(() => import('~/modules/marketing/legals-text'));
const LegalText = lazy(() => import('~/modules/marketing/legal-texts'));

const formSchema = authBodySchema;

Expand Down
2 changes: 2 additions & 0 deletions frontend/src/modules/common/public-layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ import { Outlet } from '@tanstack/react-router';
import { Dialoger } from '~/modules/common/dialoger';
import { DropDowner } from '~/modules/common/dropdowner';
import { Sheeter } from '~/modules/common/sheeter';
import AlertRenderer from './main-alert/alert-render';

// Also in public routes, some components need to be initialized.
function PublicLayout() {
return (
<>
<AlertRenderer />
<Dialoger />
<Sheeter />
<DropDowner />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Link } from '@tanstack/react-router';
import { config } from 'config';
import type { LegalTypes } from './legals';
import type { LegalTypes } from './legal';

const LegalText = ({ textFor }: { textFor: LegalTypes }) => {
const LegalTexts = ({ textFor }: { textFor: LegalTypes }) => {
const appName = config.name;
const companyFull = config.company.name;
const companyShort = config.company.shortName;
Expand Down Expand Up @@ -566,4 +566,4 @@ const LegalText = ({ textFor }: { textFor: LegalTypes }) => {
);
};

export default LegalText;
export default LegalTexts;
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ import { SimpleHeader } from '~/modules/common/simple-header';
import StickyBox from '~/modules/common/sticky-box';
import PublicPage from '~/modules/marketing/page';

const LegalText = lazy(() => import('~/modules/marketing/legals-text'));
const LegalTexts = lazy(() => import('~/modules/marketing/legal-texts'));

export type LegalTypes = 'privacy' | 'terms';

const Legal = ({ type }: { type: LegalTypes }) => {
return (
<section className="bg-background">
<div className="mx-auto max-w-[48rem] font-light px-4 md:px-8 min-h-screen">
<LegalText textFor={type} />
<LegalTexts textFor={type} />
</div>
</section>
);
Expand All @@ -26,7 +26,7 @@ const tabs = [
{ id: 'privacy', label: 'common:privacy_policy' },
] as const;

export const LegalsMenu = () => {
export const LegalMenu = () => {
const { t } = useTranslation();
return (
<PublicPage title={t('common:legal')}>
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/routes/marketing.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { createRoute } from '@tanstack/react-router';
import About from '~/modules/marketing/about';
import Accessibility from '~/modules/marketing/accessibility';
import Contact from '~/modules/marketing/contact';
import { LegalsMenu } from '~/modules/marketing/legals';
import { LegalMenu } from '~/modules/marketing/legal';
import { PublicRoute, rootRoute } from './general';

export const AboutRoute = createRoute({
Expand All @@ -23,7 +23,7 @@ export const LegalRoute = createRoute({
path: '/legal',
staticData: { pageTitle: 'Legal', isAuth: false },
getParentRoute: () => rootRoute,
component: () => <LegalsMenu />,
component: () => <LegalMenu />,
});

export const AccessibilityRoute = createRoute({
Expand Down
1 change: 1 addition & 0 deletions frontend/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export default defineConfig(() => {
server: {
host: '0.0.0.0',
port: Number(frontendUrl.port),
strictPort: true,
},
build: {
rollupOptions: {
Expand Down
11 changes: 8 additions & 3 deletions info/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ This document describes the high-level architecture of Cella.
5. Open standards. Our long term vision is that each Cella - as in each cell - can speak fluently with other cells.

### Backend
- [Hono](https://hono.dev) + [NodeJS](https://nodejs.org)
- [Postgres](https://www.postgresql.org) / [PGLite](https://pglite.dev/) + [Drizzle ORM](https://orm.drizzle.team/)
- [NodeJS](https://nodejs.org)
- [Hono](https://hono.dev)
- [Postgres](https://www.postgresql.org)
- [Drizzle ORM](https://orm.drizzle.team/)
- [Zod](https://github.com/colinhacks/zod)
- [OpenAPI](https://www.openapis.org)
- [Lucia Auth](https://lucia-auth.com/)
Expand All @@ -29,10 +31,13 @@ This document describes the high-level architecture of Cella.
- [Lucide icons](https://lucide.dev)

### Build tools
- [Vite](https://vitejs.dev) + [Vite-PWA](https://github.com/antfu/vite-plugin-pwa)
- [pnpm](https://pnpm.io)
- [Vite](https://vitejs.dev)
- [Vite-PWA](https://github.com/antfu/vite-plugin-pwa)
- [Biome](https://biomejs.dev)
- [Lefthook](https://github.com/evilmartians/lefthook)
- [PGLite](https://pglite.dev/)


## File structure
```
Expand Down
4 changes: 2 additions & 2 deletions info/QUICKSTART.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ pnpm seed
## Customize
1. Customize your config in `/config/default.ts`
2. Update package.json with your own data
3. Look at you .env file to understand what is required and update accordingly
4. There are many config files, which end with '-config.ts'. Here you can set for example your entity structure or your navigation structure.
3. Look at your .env file to understand what is required, for example to send emails you will need an API key.
4. There are many config files with filenames like `-config.ts`. For example for entities or navigation structure.


## Cella CLI
Expand Down
Loading
Loading