Skip to content

Commit 05efb2b

Browse files
feat: add CI/CD pipeline, Dependabot and build fixes (#5)
* main (#1) * ci: add CI workflow with type check, build, verify and dry-run publish Runs on every push and PR across all branches. Checks: - TypeScript (server + admin) - Build - Strapi plugin verify - Version not already published on npm - Dry run publish publish.yml now requires CI to pass before publishing to npm. * fix: replace yarn run -T with npx tsc and fix implicit any type errors - Fix test:ts:front and test:ts:back scripts to use npx tsc (was yarn-only syntax) - Add explicit types for implicit any parameters caught by the type check: MouseEvent on DropZone drag handle click boolean on Modal.Root onOpenChange in EmbedModal and FormPreview string | number on SingleSelect onChange in FieldSettingsPanel and SubmissionsPage * ci: add Dependabot for npm and GitHub Actions weekly updates * fix: remove stale compiled JS files from src and ignore them in .gitignore Rollup was resolving register.js (and other compiled .js files) instead of the .ts sources, causing 'default is not exported' build failures in CI. Deleted all .js artifacts from server/src and admin/src and added them to .gitignore so they are never committed again. * fix: add --noEmit to tsc type-check scripts to prevent JS file generation Without --noEmit, tsc outputs .js files next to the .ts sources. Rollup then resolves the CJS .js files instead of the .ts sources and fails with 'default is not exported' on the CommonJS interop boundary. * ci: prevent double CI run on PR branches Push trigger now only fires on main, development and production. Feature branches are covered by the pull_request trigger alone, so CI no longer runs twice when pushing to an open PR. * 📝 Add docstrings to `main` (#2) * ci: add CI workflow with type check, build, verify and dry-run publish Runs on every push and PR across all branches. Checks: - TypeScript (server + admin) - Build - Strapi plugin verify - Version not already published on npm - Dry run publish publish.yml now requires CI to pass before publishing to npm. * fix: replace yarn run -T with npx tsc and fix implicit any type errors - Fix test:ts:front and test:ts:back scripts to use npx tsc (was yarn-only syntax) - Add explicit types for implicit any parameters caught by the type check: MouseEvent on DropZone drag handle click boolean on Modal.Root onOpenChange in EmbedModal and FormPreview string | number on SingleSelect onChange in FieldSettingsPanel and SubmissionsPage * ci: add Dependabot for npm and GitHub Actions weekly updates * fix: remove stale compiled JS files from src and ignore them in .gitignore Rollup was resolving register.js (and other compiled .js files) instead of the .ts sources, causing 'default is not exported' build failures in CI. Deleted all .js artifacts from server/src and admin/src and added them to .gitignore so they are never committed again. * fix: add --noEmit to tsc type-check scripts to prevent JS file generation Without --noEmit, tsc outputs .js files next to the .ts sources. Rollup then resolves the CJS .js files instead of the .ts sources and fails with 'default is not exported' on the CommonJS interop boundary. * ci: prevent double CI run on PR branches Push trigger now only fires on main, development and production. Feature branches are covered by the pull_request trigger alone, so CI no longer runs twice when pushing to an open PR. * 📝 Add docstrings to `main` Docstrings generation was requested by @devCluna. * #1 (comment) The following files were modified: * `admin/src/components/DropZone.tsx` * `admin/src/components/EmbedModal.tsx` * `admin/src/components/FieldSettingsPanel.tsx` * `admin/src/components/FormPreview.tsx` * `admin/src/pages/SubmissionsPage.tsx` --------- Co-authored-by: dev.cluna <dev.cluna@gmail.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
1 parent d28d546 commit 05efb2b

10 files changed

Lines changed: 156 additions & 7 deletions

File tree

.github/dependabot.yml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
version: 2
2+
3+
updates:
4+
- package-ecosystem: "npm"
5+
directory: "/"
6+
schedule:
7+
interval: "weekly"
8+
day: "monday"
9+
time: "09:00"
10+
timezone: "America/Guayaquil"
11+
open-pull-requests-limit: 10
12+
target-branch: "development"
13+
groups:
14+
strapi:
15+
patterns:
16+
- "@strapi/*"
17+
dnd-kit:
18+
patterns:
19+
- "@dnd-kit/*"
20+
react:
21+
patterns:
22+
- "react"
23+
- "react-dom"
24+
- "@types/react"
25+
- "@types/react-dom"
26+
ignore:
27+
- dependency-name: "@strapi/strapi"
28+
update-types: ["version-update:semver-major"]
29+
- dependency-name: "@strapi/design-system"
30+
update-types: ["version-update:semver-major"]
31+
32+
- package-ecosystem: "github-actions"
33+
directory: "/"
34+
schedule:
35+
interval: "weekly"
36+
day: "monday"
37+
time: "09:00"
38+
timezone: "America/Guayaquil"
39+
open-pull-requests-limit: 5
40+
target-branch: "development"

.github/workflows/ci.yml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
- development
8+
- production
9+
pull_request:
10+
workflow_call:
11+
12+
jobs:
13+
ci:
14+
runs-on: ubuntu-latest
15+
16+
steps:
17+
- name: Checkout
18+
uses: actions/checkout@v4
19+
20+
- name: Setup Node.js
21+
uses: actions/setup-node@v4
22+
with:
23+
node-version: '20'
24+
registry-url: 'https://registry.npmjs.org'
25+
26+
- name: Install dependencies
27+
run: npm ci
28+
29+
- name: Type check (server)
30+
run: npm run test:ts:back
31+
32+
- name: Type check (admin)
33+
run: npm run test:ts:front
34+
35+
- name: Build
36+
run: npm run build
37+
38+
- name: Verify plugin
39+
run: npm run verify
40+
41+
- name: Check version not already published
42+
run: |
43+
VERSION=$(node -p "require('./package.json').version")
44+
if npm view strapi-plugin-form-builder-cms@$VERSION version 2>/dev/null; then
45+
echo "❌ Version $VERSION is already published on npm. Bump the version before merging."
46+
exit 1
47+
fi
48+
echo "✅ Version $VERSION is not yet published."
49+
50+
- name: Dry run publish
51+
run: npm publish --dry-run --access public

.github/workflows/publish.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ on:
99
jobs:
1010
publish:
1111
if: github.event.pull_request.merged == true
12+
needs: ci
1213
runs-on: ubuntu-latest
1314

1415
steps:
@@ -44,3 +45,6 @@ jobs:
4445
body: |
4546
Published from PR #${{ github.event.pull_request.number }}: ${{ github.event.pull_request.title }}
4647
generate_release_notes: true
48+
49+
ci:
50+
uses: ./.github/workflows/ci.yml

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,10 @@ public/uploads/*
102102
dist
103103
build
104104

105+
# Compiled JS files inside src (TypeScript sources only)
106+
server/src/**/*.js
107+
admin/src/**/*.js
108+
105109

106110
############################
107111
# Node.js

admin/src/components/DropZone.tsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,17 @@ import { CSS } from '@dnd-kit/utilities';
2020
import { Trash, Drag } from '@strapi/icons';
2121
import { FormField } from '../types';
2222

23+
/**
24+
* Renders a draggable, selectable row that represents a FormField with a delete action.
25+
*
26+
* The row highlights when `selected`. Clicking the row calls `onSelect`; interacting with the drag handle does not toggle selection; clicking the delete button calls `onDelete`.
27+
*
28+
* @param field - The form field to render (label and type are displayed).
29+
* @param selected - Whether this row is currently selected; controls visual highlight.
30+
* @param onSelect - Callback invoked when the row (outside the drag handle and delete button) is clicked.
31+
* @param onDelete - Callback invoked when the delete button is clicked.
32+
* @returns The rendered sortable field row element.
33+
*/
2334
function SortableFieldRow({
2435
field,
2536
selected,
@@ -62,7 +73,7 @@ function SortableFieldRow({
6273
{...attributes}
6374
{...listeners}
6475
style={{ cursor: 'grab', color: 'var(--strapi-neutral-400)', padding: '0 4px' }}
65-
onClick={(e) => e.stopPropagation()}
76+
onClick={(e: React.MouseEvent) => e.stopPropagation()}
6677
>
6778
<Drag />
6879
</Box>

admin/src/components/EmbedModal.tsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,17 @@ interface Props {
88
onClose: () => void;
99
}
1010

11+
/**
12+
* Renders a modal that displays an embeddable HTML snippet for a given form and provides a one-click copy action.
13+
*
14+
* The component returns `null` when `open` is `false`. When visible, it shows a preformatted snippet containing a container div
15+
* with `id="sfb-form-<formId>"` and a script tag that loads the embed script from the current origin with `data-form-id` set.
16+
*
17+
* @param formId - The form identifier inserted into the snippet's container id and `data-form-id` attribute
18+
* @param open - Controls whether the modal is visible
19+
* @param onClose - Callback invoked when the modal is closed
20+
* @returns The modal element when `open` is `true`, otherwise `null`
21+
*/
1122
export function EmbedModal({ formId, open, onClose }: Props) {
1223
const [copied, setCopied] = useState(false);
1324

@@ -24,7 +35,7 @@ export function EmbedModal({ formId, open, onClose }: Props) {
2435
};
2536

2637
return (
27-
<Modal.Root open={open} onOpenChange={(v) => !v && onClose()}>
38+
<Modal.Root open={open} onOpenChange={(v: boolean) => !v && onClose()}>
2839
<Modal.Content style={{ maxWidth: 600, width: '100%' }}>
2940
<Modal.Header>
3041
<Typography variant="beta">Embed this form</Typography>

admin/src/components/FieldSettingsPanel.tsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,17 @@ function LabeledInput({
4545
);
4646
}
4747

48+
/**
49+
* Render the settings panel UI for editing a single form field.
50+
*
51+
* Displays controls for label, name, placeholder, help text, required/width toggles,
52+
* type-specific inputs (heading, paragraph), option management (add/update/remove),
53+
* validation rule management (add/update/remove) with value/message editing, and CSS class.
54+
*
55+
* @param field - The current FormField to edit.
56+
* @param onChange - Callback invoked with the updated FormField whenever a change is made.
57+
* @returns A React element containing the field settings panel UI.
58+
*/
4859
export function FieldSettingsPanel({ field, onChange }: Props) {
4960
const update = (patch: Partial<FormField>) => onChange({ ...field, ...patch });
5061

@@ -260,7 +271,7 @@ export function FieldSettingsPanel({ field, onChange }: Props) {
260271
<Field.Root style={{ flex: 1 }}>
261272
<SingleSelect
262273
value={rule.type}
263-
onChange={(val) => updateValidation(i, { type: String(val), value: undefined, message: '' })}
274+
onChange={(val: string | number) => updateValidation(i, { type: String(val), value: undefined, message: '' })}
264275
size="S"
265276
>
266277
{available.map((opt) => (

admin/src/components/FormPreview.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,11 +283,21 @@ interface Props {
283283
onClose: () => void;
284284
}
285285

286+
/**
287+
* Render a modal preview of a form using the provided title, fields, and settings.
288+
*
289+
* @param title - The preview title displayed in the modal header
290+
* @param fields - The array of form field definitions to render inside the preview
291+
* @param settings - Form-level settings (used for things like the submit button text)
292+
* @param open - Whether the preview modal is visible
293+
* @param onClose - Callback invoked when the preview modal is closed
294+
* @returns The modal element containing the form preview, or `null` when `open` is false
295+
*/
286296
export function FormPreview({ title, fields, settings, open, onClose }: Props) {
287297
if (!open) return null;
288298

289299
return (
290-
<Modal.Root open={open} onOpenChange={(v) => !v && onClose()}>
300+
<Modal.Root open={open} onOpenChange={(v: boolean) => !v && onClose()}>
291301
<Modal.Content style={{ maxWidth: 760, width: '100%' }}>
292302
<Modal.Header>
293303
<Typography variant="beta">Preview — {title}</Typography>

admin/src/pages/SubmissionsPage.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ import { useFormsApi } from '../api';
2222
import { Form, FormField, FormSubmission } from '../types';
2323
import { PLUGIN_ID } from '../pluginId';
2424

25+
/**
26+
* Render the submissions management page for a specific form.
27+
*
28+
* Loads and displays form metadata, submission list, and statistics; provides controls to filter by status, view submission details, mark submissions as read, and delete submissions.
29+
*
30+
* @returns The React element for the Submissions page (table, filters, detail modal, and delete confirmation modal).
31+
*/
2532
export function SubmissionsPage() {
2633
const { formId } = useParams<{ formId: string }>();
2734
const navigate = useNavigate();
@@ -93,7 +100,7 @@ export function SubmissionsPage() {
93100
<SingleSelect
94101
aria-label="Filter by status"
95102
value={statusFilter}
96-
onChange={(val) => setStatusFilter(String(val))}
103+
onChange={(val: string | number) => setStatusFilter(String(val))}
97104
placeholder="All statuses"
98105
size="S"
99106
>

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@
2727
"watch": "strapi-plugin watch",
2828
"watch:link": "strapi-plugin watch:link",
2929
"verify": "strapi-plugin verify",
30-
"test:ts:front": "run -T tsc -p admin/tsconfig.json",
31-
"test:ts:back": "run -T tsc -p server/tsconfig.json"
30+
"test:ts:front": "npx tsc -p admin/tsconfig.json --noEmit",
31+
"test:ts:back": "npx tsc -p server/tsconfig.json --noEmit"
3232
},
3333
"dependencies": {
3434
"@dnd-kit/core": "^6.3.1",

0 commit comments

Comments
 (0)