Skip to content
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
32 changes: 32 additions & 0 deletions .github/workflows/cli.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: CLI tests
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
timeout-minutes: 60
runs-on: ubuntu-latest
steps:
- name: Check out frontend
uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- name: Install dependencies
run: npm ci
- name: Generate resources and fields
run: npm run generate:resource -- --name=Department
- run: npm run generate:resource -- --name=People
- run: npm run generate:field -- --name=Department --property=name --kind=primitive --type=string --isOptional=false --isShowInTable=true
- run: npm run generate:field -- --name=People --property=profilePicture --kind=reference --referenceType=toOne --type=File --isOptional=true --isShowInTable=true
- run: npm run generate:field -- --name=People --property=firstName --kind=primitive --type=string --isOptional=false --isShowInTable=true
- run: npm run generate:field -- --name=People --property=lastName --kind=primitive --type=string --isOptional=false --isShowInTable=true
- run: npm run generate:field -- --name=People --property=department --kind=reference --referenceType=toOne --type=Department --isOptional=true --isShowInTable=true --propertyForSelect=name
- run: npm run generate:field -- --name=People --property=isActive --kind=primitive --type=boolean --isOptional=false --isShowInTable=true
- run: npm run generate:field -- --name=People --property=birthDate --kind=primitive --type=Date --isOptional=true --isShowInTable=true
- run: npm run generate:field -- --name=People --property=hireDate --kind=primitive --type=Date --isOptional=false --isShowInTable=true
- run: npm run generate:field -- --name=People --property=salary --kind=primitive --type=number --isOptional=false --isShowInTable=true
- name: Build
run: npm run build
83 changes: 42 additions & 41 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
@@ -1,51 +1,52 @@
name: E2E tests
on:
push:
branches: [ main ]
branches: [main]
pull_request:
branches: [ main ]
branches: [main]
jobs:
test:
timeout-minutes: 60
runs-on: ubuntu-latest
steps:
- name: Check out backend
uses: actions/checkout@v4
with:
repository: brocoders/nestjs-boilerplate
# Use token for private repository
# token: ${{ secrets.CI_PAT }}
path: backend
- run: cd backend && cp env-example-document .env
- run: cd backend && sed -i 's/APP_PORT=3000/APP_PORT=3001/g' .env
- run: cd backend && sed -i 's/BACKEND_DOMAIN=http:\/\/localhost:3000/BACKEND_DOMAIN=http:\/\/localhost:3001/g' .env
- name: Run backend
# print output of the command to file and store it as artifact
run: cd backend && docker compose -f docker-compose.document.yaml up > ${{ runner.temp }}/backend.log 2>&1 &
- run: cd backend && sed -i 's/\r//g' wait-for-it.sh
- run: cd backend && ./wait-for-it.sh localhost:3001 -- echo "Backend is up"
- name: Check out backend
uses: actions/checkout@v4
with:
repository: brocoders/nestjs-boilerplate
# Use token for private repository
# token: ${{ secrets.CI_PAT }}
path: backend
- run: cd backend && cp env-example-document .env
- run: cd backend && sed -i 's/APP_PORT=3000/APP_PORT=3001/g' .env
- run: cd backend && sed -i 's/BACKEND_DOMAIN=http:\/\/localhost:3000/BACKEND_DOMAIN=http:\/\/localhost:3001/g' .env
- name: Run backend
# print output of the command to file and store it as artifact
run: cd backend && docker compose -f docker-compose.document.yaml up > ${{ runner.temp }}/backend.log 2>&1 &
- run: cd backend && sed -i 's/\r//g' wait-for-it.sh
- run: cd backend && ./wait-for-it.sh localhost:3001 -- echo "Backend is up"

- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- name: Install dependencies
run: npm ci
- name: Run lint
run: npm run lint
- name: Install Playwright Browsers
run: npx playwright install --with-deps
- name: Run Playwright tests
run: npx playwright test
- uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: playwright-report
path: playwright-report/
retention-days: 30
- uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: backend-log
path: ${{ runner.temp }}/backend.log
retention-days: 30
- name: Check out frontend
uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- name: Install dependencies
run: npm ci
- name: Run lint
run: npm run lint
- name: Install Playwright Browsers
run: npx playwright install --with-deps
- name: Run Playwright tests
run: npx playwright test
- uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: playwright-report
path: playwright-report/
retention-days: 30
- uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: backend-log
path: ${{ runner.temp }}/backend.log
retention-days: 30
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ before: \<create\-component\-reference\-field \/\>
function <%= h.inflection.camelize(property, false) %>Field() {
const { t } = useTranslation("admin-panel-<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>-create");
const { data, hasNextPage, isFetchingNextPage, fetchNextPage } =
useGet<%= h.inflection.transform(type, ['pluralize']) %>Query();
useGet<%= h.inflection.transform(type, ['pluralize']) %>ListQuery();

const options = useMemo(
() => (data?.pages.flatMap((page) => page?.data ?? []).filter(Boolean) ?? []),
Expand Down
12 changes: 6 additions & 6 deletions .hygen/generate/field/create/field-property-type.ejs.t
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ after: type CreateFormData

<% if (kind === 'primitive') { -%>
<% if (type === 'string') { -%>
<%= property %><% if (isOptional) { -%>?<% } -%>: string;
<%= property %>: string;
<% } else if (type === 'number') { -%>
<%= property %><% if (isOptional) { -%>?<% } -%>: string;
<%= property %>: string;
<% } else if (type === 'boolean') { -%>
<%= property %><% if (isOptional) { -%>?<% } -%>: boolean;
<%= property %>: boolean;
<% } else if (type === 'Date') { -%>
<%= property %><% if (isOptional) { -%>?<% } -%>: Date | null;
<%= property %>: Date | null;
<% } -%>
<% } else if (kind === 'reference') { -%>
<% if (referenceType === 'toMany') { -%>
Expand All @@ -23,9 +23,9 @@ after: type CreateFormData
<% } -%>
<% } else { -%>
<% if (type === 'File') { -%>
<%= property %><% if (isOptional) { -%>?<% } -%>: FileEntity | null;
<%= property %>: FileEntity | null;
<% } else { -%>
<%= property %><% if (isOptional) { -%>?<% } -%>: <%= type %> | null;
<%= property %>: <%= type %> | null;
<% } -%>
<% } -%>
<% } -%>
16 changes: 13 additions & 3 deletions .hygen/generate/field/create/field-property-validation.ejs.t
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,31 @@ before: \<create\-form\-validation\-schema \/\>
.string()
<% if (!isOptional) { -%>
.required(t("inputs.<%= property %>.validation.required"))
<% } else { -%>
.defined()
<% } -%>
,
<% } else if (type === 'number') { -%>
<%= property %>: yup
.string()
<% if (!isOptional) { -%>
.required(t("inputs.<%= property %>.validation.required"))
<% } else { -%>
.defined()
<% } -%>
,
<% } else if (type === 'boolean') { -%>
<%= property %>: yup.boolean(),
<%= property %>: yup.boolean().defined(),
<% } else if (type === 'Date') { -%>
<%= property %>: yup
.date()
<% if (!isOptional) { -%>
.required(t("inputs.<%= property %>.validation.required"))
<% } -%>
.nullable(),
.nullable()
<% if (isOptional) { -%>
.defined()
<% } -%>,
<% } -%>
<% } else if (kind === 'reference') { -%>
<% if (referenceType === 'toMany') { -%>
Expand Down Expand Up @@ -57,6 +64,9 @@ before: \<create\-form\-validation\-schema \/\>
<% if (!isOptional) { -%>
.required(t("inputs.<%= property %>.validation.required"))
<% } -%>
.nullable(),
.nullable()
<% if (isOptional) { -%>
.defined()
<% } -%>,
<% } -%>
<% } -%>
4 changes: 2 additions & 2 deletions .hygen/generate/field/create/import-type-query.ejs.t
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
inject: true
to: src/app/[language]/admin-panel/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/create/page-content.tsx
at_line: 2
skip_if: import { useGet<%= h.inflection.transform(type, ['pluralize']) %>Query }
skip_if: import { useGet<%= h.inflection.transform(type, ['pluralize']) %>ListQuery }
---

<% if (kind === 'reference') { -%>
<% if (type !== 'File') { -%>
import { useGet<%= h.inflection.transform(type, ['pluralize']) %>Query } from "@/app/[language]/admin-panel/<%= h.inflection.transform(type, ['pluralize', 'underscore', 'dasherize']) %>/queries/queries";
import { useGet<%= h.inflection.transform(type, ['pluralize']) %>ListQuery } from "@/app/[language]/admin-panel/<%= h.inflection.transform(type, ['pluralize', 'underscore', 'dasherize']) %>/queries/queries";
<% } -%>
<% } -%>
2 changes: 1 addition & 1 deletion .hygen/generate/field/edit/field-component-reference.ejs.t
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ before: \<edit\-component\-reference\-field \/\>
function <%= h.inflection.camelize(property, false) %>Field() {
const { t } = useTranslation("admin-panel-<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>-edit");
const { data, hasNextPage, isFetchingNextPage, fetchNextPage } =
useGet<%= h.inflection.transform(type, ['pluralize']) %>Query();
useGet<%= h.inflection.transform(type, ['pluralize']) %>ListQuery();

const options = useMemo(
() => (data?.pages.flatMap((page) => page?.data ?? []).filter(Boolean) ?? []),
Expand Down
12 changes: 6 additions & 6 deletions .hygen/generate/field/edit/field-property-type.ejs.t
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ after: type EditFormData

<% if (kind === 'primitive') { -%>
<% if (type === 'string') { -%>
<%= property %><% if (isOptional) { -%>?<% } -%>: string;
<%= property %>: string;
<% } else if (type === 'number') { -%>
<%= property %><% if (isOptional) { -%>?<% } -%>: string;
<%= property %>: string;
<% } else if (type === 'boolean') { -%>
<%= property %><% if (isOptional) { -%>?<% } -%>: boolean;
<%= property %>: boolean;
<% } else if (type === 'Date') { -%>
<%= property %><% if (isOptional) { -%>?<% } -%>: Date | null;
<%= property %>: Date | null;
<% } -%>
<% } else if (kind === 'reference') { -%>
<% if (referenceType === 'toMany') { -%>
Expand All @@ -23,9 +23,9 @@ after: type EditFormData
<% } -%>
<% } else { -%>
<% if (type === 'File') { -%>
<%= property %><% if (isOptional) { -%>?<% } -%>: FileEntity | null;
<%= property %>: FileEntity | null;
<% } else { -%>
<%= property %><% if (isOptional) { -%>?<% } -%>: <%= type %> | null;
<%= property %>: <%= type %> | null;
<% } -%>
<% } -%>
<% } -%>
16 changes: 13 additions & 3 deletions .hygen/generate/field/edit/field-property-validation.ejs.t
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,31 @@ before: \<edit\-form\-validation\-schema \/\>
.string()
<% if (!isOptional) { -%>
.required(t("inputs.<%= property %>.validation.required"))
<% } else { -%>
.defined()
<% } -%>
,
<% } else if (type === 'number') { -%>
<%= property %>: yup
.string()
<% if (!isOptional) { -%>
.required(t("inputs.<%= property %>.validation.required"))
<% } else { -%>
.defined()
<% } -%>
,
<% } else if (type === 'boolean') { -%>
<%= property %>: yup.boolean(),
<%= property %>: yup.boolean().defined(),
<% } else if (type === 'Date') { -%>
<%= property %>: yup
.date()
<% if (!isOptional) { -%>
.required(t("inputs.<%= property %>.validation.required"))
<% } -%>
.nullable(),
.nullable()
<% if (isOptional) { -%>
.defined()
<% } -%>,
<% } -%>
<% } else if (kind === 'reference') { -%>
<% if (referenceType === 'toMany') { -%>
Expand Down Expand Up @@ -57,6 +64,9 @@ before: \<edit\-form\-validation\-schema \/\>
<% if (!isOptional) { -%>
.required(t("inputs.<%= property %>.validation.required"))
<% } -%>
.nullable(),
.nullable()
<% if (isOptional) { -%>
.defined()
<% } -%>,
<% } -%>
<% } -%>
4 changes: 2 additions & 2 deletions .hygen/generate/field/edit/import-type-query.ejs.t
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
inject: true
to: src/app/[language]/admin-panel/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/edit/[id]/page-content.tsx
at_line: 2
skip_if: import { useGet<%= h.inflection.transform(type, ['pluralize']) %>Query }
skip_if: import { useGet<%= h.inflection.transform(type, ['pluralize']) %>ListQuery }
---

<% if (kind === 'reference') { -%>
<% if (type !== 'File') { -%>
import { useGet<%= h.inflection.transform(type, ['pluralize']) %>Query } from "@/app/[language]/admin-panel/<%= h.inflection.transform(type, ['pluralize', 'underscore', 'dasherize']) %>/queries/queries";
import { useGet<%= h.inflection.transform(type, ['pluralize']) %>ListQuery } from "@/app/[language]/admin-panel/<%= h.inflection.transform(type, ['pluralize', 'underscore', 'dasherize']) %>/queries/queries";
<% } -%>
<% } -%>
10 changes: 5 additions & 5 deletions .hygen/generate/resource/api-service.ejs.t
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,26 @@ import { InfinityPaginationType } from "../types/infinity-pagination";
import { RequestConfigType } from "./types/request-config";
import { <%= name %> as Entity } from "../types/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>";

export type Get<%= h.inflection.transform(name, ['pluralize']) %>Request = {
export type Get<%= h.inflection.transform(name, ['pluralize']) %>ListRequest = {
page: number;
limit: number;
};

export type Get<%= h.inflection.transform(name, ['pluralize']) %>Response = InfinityPaginationType<Entity>;
export type Get<%= h.inflection.transform(name, ['pluralize']) %>ListResponse = InfinityPaginationType<Entity>;

export function useGet<%= h.inflection.transform(name, ['pluralize']) %>Service() {
export function useGet<%= h.inflection.transform(name, ['pluralize']) %>ListService() {
const fetch = useFetch();

return useCallback(
(data: Get<%= h.inflection.transform(name, ['pluralize']) %>Request, requestConfig?: RequestConfigType) => {
(data: Get<%= h.inflection.transform(name, ['pluralize']) %>ListRequest, requestConfig?: RequestConfigType) => {
const requestUrl = new URL(`${API_URL}/v1/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>`);
requestUrl.searchParams.append("page", data.page.toString());
requestUrl.searchParams.append("limit", data.limit.toString());

return fetch(requestUrl, {
method: "GET",
...requestConfig,
}).then(wrapperFetchJsonResponse<Get<%= h.inflection.transform(name, ['pluralize']) %>Response>);
}).then(wrapperFetchJsonResponse<Get<%= h.inflection.transform(name, ['pluralize']) %>ListResponse>);
},
[fetch]
);
Expand Down
8 changes: 4 additions & 4 deletions .hygen/generate/resource/page-content.ejs.t
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import Container from "@mui/material/Container";
import Grid from "@mui/material/Grid";
import Typography from "@mui/material/Typography";
import { useCallback, useMemo, useRef, useState } from "react";
import { useGet<%= h.inflection.transform(name, ['pluralize']) %>Query, <%= h.inflection.camelize(h.inflection.pluralize(name), true) %>QueryKeys } from "./queries/queries";
import { useGet<%= h.inflection.transform(name, ['pluralize']) %>ListQuery, <%= h.inflection.camelize(h.inflection.pluralize(name), true) %>QueryKeys } from "./queries/queries";
import { TableVirtuoso } from "react-virtuoso";
import TableCell from "@mui/material/TableCell";
import TableRow from "@mui/material/TableRow";
Expand Down Expand Up @@ -172,11 +172,11 @@ function Actions({ entityItem }: { entityItem: <%= name %> }) {
);
}

function <%= h.inflection.transform(name, ['pluralize']) %>() {
function <%= h.inflection.transform(name, ['pluralize']) %>PageContent() {
const { t } = useTranslation("admin-panel-<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>");

const { data, hasNextPage, isFetchingNextPage, fetchNextPage } =
useGet<%= h.inflection.transform(name, ['pluralize']) %>Query();
useGet<%= h.inflection.transform(name, ['pluralize']) %>ListQuery();

const handleScroll = useCallback(() => {
if (!hasNextPage || isFetchingNextPage) return;
Expand Down Expand Up @@ -255,4 +255,4 @@ function <%= h.inflection.transform(name, ['pluralize']) %>() {
);
}

export default withPageRequiredAuth(<%= h.inflection.transform(name, ['pluralize']) %>, { roles: [RoleEnum.ADMIN] });
export default withPageRequiredAuth(<%= h.inflection.transform(name, ['pluralize']) %>PageContent, { roles: [RoleEnum.ADMIN] });
Loading