Skip to content

Commit 4a107a3

Browse files
authored
feat: allow to use django SMTP configuration to send emails (baserow#5001)
* Allow to use django SMTP configuration to send emails
1 parent 5cdde98 commit 4a107a3

29 files changed

Lines changed: 2208 additions & 52 deletions

File tree

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
---
2+
name: add-django-config-env-var
3+
description: Add a new environment variable for a Django setting in Baserow and propagate it to the few repo files that usually need it. Use this when a request says a config env var must be added in several places or references `INTEGRATION_LOCAL_BASEROW_PAGE_SIZE_LIMIT` as the pattern to follow.
4+
---
5+
6+
# Add Django Config Env Var
7+
8+
Use `INTEGRATION_LOCAL_BASEROW_PAGE_SIZE_LIMIT` as the template. The env var name should be prefixed with `BASEROW_` but the internal var isn't.
9+
10+
Keep the change simple and explicit. Do not add abstractions for this.
11+
12+
## Files To Check
13+
14+
When adding a new setting, usually check these files:
15+
16+
- `backend/src/baserow/config/settings/base.py`
17+
- `docker-compose.yml`
18+
- `docker-compose.no-caddy.yml`
19+
- `web-frontend/env-remap.mjs`
20+
- Backend or frontend code that uses the setting
21+
- A focused test if behavior changes
22+
23+
## Workflow
24+
25+
1. Add the Django setting in `backend/src/baserow/config/settings/base.py` near the closest related setting.
26+
27+
Example:
28+
29+
```python
30+
MY_SETTING = int(os.getenv("BASEROW_MY_SETTING", 123))
31+
```
32+
33+
2. If the variable should be configurable in Docker, add it everywhere the similar example appears in:
34+
35+
- `docker-compose.yml`
36+
- `docker-compose.no-caddy.yml`
37+
38+
3. If the frontend needs it at runtime, add it to `web-frontend/env-remap.mjs`.
39+
40+
4. Update consumers to use the setting:
41+
42+
- Backend: `settings.MY_SETTING`
43+
- Tests: `override_settings(MY_SETTING=...)`
44+
45+
5. Add or update a targeted test if the setting changes behavior.
46+
47+
6. Add the related documentation
48+
49+
## Quick Checklist
50+
51+
1. Add it in `base.py`
52+
2. Mirror the matching Docker entries
53+
3. Add the Nuxt remap if frontend code needs it
54+
4. Use `settings.<NAME>` in code
55+
5. Add a focused test if needed
56+
6. Add the documentation
57+
58+
## Guardrails
59+
60+
- Do not add a raw `os.getenv(...)` in application code when the value belongs in Django settings.
61+
- Do not update only one Docker location if the example appears in several places.
62+
- Do not expose a backend-only setting to Nuxt unless the frontend actually needs it.
63+
- Prefer copying the closest existing setting instead of inventing a new pattern.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
interface:
2+
display_name: "Add Django Config Env Var"
3+
short_description: "Add and propagate a Django env variable"
4+
default_prompt: "Use $add-django-config-env-var to add a new environment variable that changes Django configuration across Baserow."
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
---
2+
name: create-update-service
3+
description: Allow to create or update Baserow Integrations and Services
4+
---
5+
6+
# Create Or Update Baserow Services And Integrations
7+
8+
Use this skill when a task involves creating or updating a Baserow integration type or service type in the `contrib/integrations` stack.
9+
10+
This repo already has the core patterns. Prefer copying an existing implementation close to the target behavior instead of inventing a new structure.
11+
12+
Integrations and services are shared by the Application builder and the Automation tool. Each of them should be compatible with both tools.
13+
14+
## First Step
15+
16+
Before editing, identify which of these applies:
17+
18+
1. New integration type only
19+
2. New service type attached to an existing integration
20+
3. Update to an existing integration or service
21+
4. Full feature spanning backend, frontend, translations, and tests
22+
23+
Then inspect the closest existing example with `rg` before changing files.
24+
25+
Useful starting points:
26+
27+
- Backend registrations: `backend/src/baserow/contrib/integrations/apps.py`
28+
- Frontend registrations: `web-frontend/modules/integrations/plugin.js`
29+
- Core backend service examples: `backend/src/baserow/contrib/integrations/core/service_types.py`
30+
- Core frontend service examples: `web-frontend/modules/integrations/core/serviceTypes.js`
31+
- Backend integration example: `backend/src/baserow/contrib/integrations/core/integration_types.py`
32+
- Frontend integration example: `web-frontend/modules/integrations/core/integrationTypes.js`
33+
34+
## Backend Checklist
35+
36+
For a new or updated service type, check these areas:
37+
38+
1. Model fields exist and support the intended configuration.
39+
2. The `ServiceType` subclass exposes the right `type`, `model_class`, `dispatch_types`, `allowed_fields`, and serializer configuration.
40+
3. Related nested objects are handled in `after_create`, update helpers, or custom methods when needed.
41+
4. Context/schema methods are implemented if the service emits data for downstream nodes.
42+
5. The service is registered in `backend/src/baserow/contrib/integrations/apps.py`.
43+
6. A migration is added if models changed.
44+
45+
For a new or updated integration type, check these areas:
46+
47+
1. The `IntegrationType` subclass defines `type`, `model_class`, serializer field names, allowed fields, and sensitive fields when relevant.
48+
2. Any integration-specific context data or permissions behavior is preserved.
49+
3. The integration is registered in `backend/src/baserow/contrib/integrations/apps.py`.
50+
4. A migration is added if models changed.
51+
52+
Common backend files to inspect:
53+
54+
- `backend/src/baserow/contrib/integrations/*/models.py`
55+
- `backend/src/baserow/contrib/integrations/*/service_types.py`
56+
- `backend/src/baserow/contrib/integrations/*/integration_types.py`
57+
- `backend/src/baserow/contrib/integrations/api/**`
58+
- `backend/src/baserow/contrib/integrations/migrations/**`
59+
60+
## Frontend Checklist
61+
62+
If the feature is user-configurable, update the frontend in parallel with the backend:
63+
64+
1. Add or update the service or integration type class.
65+
2. Register it in `web-frontend/modules/integrations/plugin.js`.
66+
3. Add or update the form component used to configure it.
67+
4. Add translations in `web-frontend/modules/integrations/locales/en.json`.
68+
5. Add any supporting mixins, helpers, or assets only if the existing pattern requires them.
69+
70+
Common frontend files to inspect:
71+
72+
- `web-frontend/modules/integrations/*/serviceTypes.js`
73+
- `web-frontend/modules/integrations/*/integrationTypes.js`
74+
- `web-frontend/modules/integrations/*/components/services/**`
75+
- `web-frontend/modules/integrations/*/components/integrations/**`
76+
- `web-frontend/modules/integrations/locales/en.json`
77+
78+
## How To Implement
79+
80+
### Creating a new service type
81+
82+
1. Start from the closest existing service type with similar dispatch behavior:
83+
`ACTION`, `DATA`, or trigger behavior.
84+
2. Add or update the backend model if the service needs persisted fields.
85+
3. Implement or extend the backend `ServiceType` subclass.
86+
4. Register the service in `backend/src/baserow/contrib/integrations/apps.py`.
87+
5. Implement the frontend service type class and form component.
88+
6. Register the service in `web-frontend/modules/integrations/plugin.js`.
89+
7. Add translations and tests.
90+
91+
### Creating a new integration type
92+
93+
1. Start from the closest existing integration type with similar auth or configuration needs.
94+
2. Add or update the backend model if required.
95+
3. Implement or extend the backend `IntegrationType` subclass.
96+
4. Register the integration in `backend/src/baserow/contrib/integrations/apps.py`.
97+
5. Implement the frontend integration type class and form component.
98+
6. Register the integration in `web-frontend/modules/integrations/plugin.js`.
99+
7. Add translations and tests.
100+
101+
### Updating an existing type
102+
103+
1. Find all backend and frontend registrations for the type string.
104+
2. Check whether API serializers, nested relations, or schema generation need updates.
105+
3. Keep existing `type` identifiers stable unless the user explicitly wants a breaking change.
106+
4. Check whether old records need a migration or a data backfill.
107+
5. Update tests for both create and update flows when behavior changes.
108+
109+
## Testing Expectations
110+
111+
Run the narrowest relevant tests first or create one if none exists.
112+
113+
Backend examples:
114+
115+
- Integration and Service tests in `backend/tests/baserow/api/integrations/**`
116+
117+
Frontend examples:
118+
119+
- Unit tests near `web-frontend/test/unit/integrations/**`
120+
121+
Minimum validation before finishing:
122+
123+
1. The type is registered on both backend and frontend when applicable.
124+
2. The create and update flows serialize the intended fields.
125+
3. Required translations exist.
126+
4. Migrations are present for model changes.
127+
5. The most relevant targeted tests pass, or the failure is reported explicitly.
128+
129+
## Search Patterns
130+
131+
Use these searches to move quickly:
132+
133+
- `rg -n "class .*ServiceType" backend/src/baserow/contrib/integrations`
134+
- `rg -n "class .*IntegrationType" backend/src/baserow/contrib/integrations`
135+
- `rg -n "register\\(" backend/src/baserow/contrib/integrations/apps.py web-frontend/modules/integrations/plugin.js`
136+
- `rg -n "getType\\(\\)" web-frontend/modules/integrations`
137+
- `rg -n "\"serviceType\\.|integrationType\\.\"" web-frontend/modules/integrations/locales/en.json`
138+
139+
## Guardrails
140+
141+
- Do not add a backend type without checking the matching frontend registration path.
142+
- Do not rename a persisted `type` string casually.
143+
- Do not forget migrations when model fields change.
144+
- Do not add broad abstractions unless at least two existing implementations already need them.
145+
- Prefer matching the nearest existing module layout over introducing a new folder structure.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
interface:
2+
display_name: 'Integrations and Services'
3+
short_description: 'Create or update Baserow Integrations and Services'
4+
default_prompt: 'Use $create-update-service to create or update Baserow Integrations and Services.'
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
---
2+
name: write-frontend-unit-test
3+
description: Write or update Baserow frontend unit tests for core, premium, or enterprise code using the repo's existing Vitest, Nuxt, Vue Test Utils, TestApp, and snapshot patterns.
4+
---
5+
6+
# Write Baserow Frontend Unit Tests
7+
8+
Use this skill when a task is to add, fix, or extend a frontend unit test in `web-frontend`, `premium/web-frontend`, or `enterprise/web-frontend`.
9+
10+
Do not invent a generic Vue testing style. This repo already has established patterns. Start by finding the closest existing spec and copy its setup shape.
11+
12+
## First Step
13+
14+
Before editing, identify the test target:
15+
16+
1. Pure utility or parser function
17+
2. Vuex store logic
18+
3. Vue component mounted with the shared app context
19+
4. Nuxt/Vue 3 component mounted directly with `mountSuspended`
20+
5. Premium or enterprise variant of one of the above
21+
22+
Then inspect the nearest existing spec in the same module area.
23+
24+
Useful searches:
25+
26+
- `rg --files web-frontend/test premium/web-frontend/test enterprise/web-frontend/test | rg '\.spec\.'`
27+
- `rg -n "new TestApp\\(|new PremiumTestApp\\(|mountSuspended\\(" web-frontend/test premium/web-frontend/test enterprise/web-frontend/test`
28+
- `rg -n "toMatchSnapshot\\(|vi\\.fn\\(|vi\\.spyOn\\(" web-frontend/test premium/web-frontend/test enterprise/web-frontend/test`
29+
30+
## Tooling Used In This Repo
31+
32+
Current frontend unit tests use:
33+
34+
- `vitest` for `describe`, `test`, `expect`, `vi`
35+
- `@vue/test-utils`
36+
- `@nuxt/test-utils/runtime` with `mountSuspended`
37+
- Repo helpers such as `TestApp`, `PremiumTestApp`, `MockServer`, and fixtures under `web-frontend/test`
38+
- Snapshot assertions for rendered HTML when the component output matters
39+
40+
Important local files:
41+
42+
- `web-frontend/vitest.setup.ts`
43+
- `web-frontend/test/helpers/testApp.js`
44+
- `premium/web-frontend/test/helpers/premiumTestApp.js`
45+
46+
`vitest.setup.ts` already mocks i18n, UUID generation, and `WebSocket`. Reuse that environment instead of re-mocking those globally in each spec.
47+
48+
## Choose The Right Pattern
49+
50+
### Pure utility tests
51+
52+
For functions in `modules/*/utils/**`, keep the test simple:
53+
54+
1. Import the function directly.
55+
2. Use plain inputs and deterministic assertions.
56+
3. Prefer `toStrictEqual`, `toBe`, or explicit formatted objects over snapshots.
57+
58+
Good examples:
59+
60+
- `web-frontend/test/unit/core/utils/date.spec.js`
61+
- `web-frontend/test/unit/core/utils/string.spec.js`
62+
63+
### Store tests
64+
65+
For Vuex store behavior, prefer `TestApp` unless the existing spec clearly uses a temporary local store:
66+
67+
1. Create `testApp = new TestApp()` in `beforeEach`.
68+
2. Read `store = testApp.store`.
69+
3. Seed state through store actions or the mock server.
70+
4. Always `await testApp.afterEach()` in `afterEach`.
71+
72+
Good examples:
73+
74+
- `web-frontend/test/unit/core/store/auth.spec.js`
75+
- `web-frontend/test/unit/builder/store/dataSource.spec.js`
76+
77+
If the code lives in premium and needs premium-only auth/license behavior, use `PremiumTestApp`.
78+
79+
### Shared app component tests
80+
81+
For many components, especially older patterns or components coupled to store, router, registry, or client behavior:
82+
83+
1. Create `testApp = new TestApp()` or `new PremiumTestApp()`.
84+
2. Mount with `testApp.mount(Component, { props, propsData, slots, listeners, global })`.
85+
3. Prefer the existing helper in the file, for example `mountComponent(...)`.
86+
4. Clean up with `await testApp.afterEach()`.
87+
88+
`TestApp.mount` supports both `props` and legacy `propsData`, and converts `listeners` into Vue 3 event props. Match the nearby spec instead of rewriting all setup.
89+
90+
Good examples:
91+
92+
- `web-frontend/test/unit/core/components/dropdown.spec.js`
93+
- `premium/web-frontend/test/unit/premium/view/calendar/calendarView.spec.js`
94+
95+
### Direct `mountSuspended` component tests
96+
97+
For newer Nuxt/Vue 3 component tests that do not need the full helper wrapper:
98+
99+
1. Use `const testApp = useNuxtApp()` in `beforeEach` if the component expects injected app/store context.
100+
2. Mount with `mountSuspended(Component, { props, slots, global: { provide, stubs, mocks } })`.
101+
3. Provide injected dependencies explicitly.
102+
103+
Good examples:
104+
105+
- `web-frontend/test/unit/builder/components/elements/components/HeadingElement.spec.js`
106+
107+
## Assertions
108+
109+
Prefer the narrowest assertion that proves behavior:
110+
111+
- Use `toStrictEqual` or `toEqual` for transformed data and store state.
112+
- Use `toBe` for scalar values.
113+
- Use `vi.fn()` and `vi.spyOn()` for event handlers and method calls.
114+
- Use snapshots for rendered markup where the repo already uses them.
115+
116+
Do not default to snapshots for pure logic.
117+
118+
When asserting reactive store objects, this repo sometimes normalizes them with:
119+
120+
```js
121+
JSON.parse(JSON.stringify(value))
122+
```
123+
124+
Use that only when the nearby test does it for Vue reactivity serialization issues.
125+
126+
Don't assert internals, always assert visible result in the DOM. For instance don't
127+
use
128+
129+
```js
130+
expect(wrapper.vm.values.use_instance_smtp_settings).toBe(false) # BAD
131+
```
132+
133+
Don't directly use vm properties.
134+
135+
## Mocking And Fixtures
136+
137+
Prefer repo helpers over bespoke mocks:
138+
139+
1. Use `testApp.mockServer` when the behavior depends on store-backed API calls.
140+
2. Use fixtures under `web-frontend/test/fixtures` and premium or enterprise fixture folders when suitable.
141+
3. Use `testApp.dontFailOnErrorResponses()` only when the test intentionally exercises failing responses.
142+
143+
Do not build a large custom mock environment if `TestApp` already provides the needed app, client, registry, router, and store wiring.
144+
145+
## File Placement
146+
147+
Follow the existing test tree:
148+
149+
- Core: `web-frontend/test/unit/...`
150+
- Premium: `premium/web-frontend/test/unit/...`
151+
- Enterprise: `enterprise/web-frontend/test/unit/...`
152+
153+
Keep the spec near the feature area rather than creating a new generic test folder.
154+
155+
## Validation
156+
157+
Run the narrowest relevant test command first.
158+
159+
Examples:
160+
161+
- `just f yarn test:core --run test/unit/core/components/dropdown.spec.js`
162+
- `just f yarn test:core --run test/unit/core/store/auth.spec.js`
163+
- `just f yarn test:premium --run ../premium/web-frontend/test/unit/premium/view/calendar/calendarView.spec.js`
164+
- `just f yarn test:enterprise --run ../enterprise/web-frontend/test/unit/enterprise/plugins.spec.js`
165+
166+
If a snapshot changes intentionally, review the diff instead of blindly accepting it.
167+
168+
## Guardrails
169+
170+
- Do not introduce Jest APIs. Use Vitest APIs already present in the repo.
171+
- Do not add a standalone mount helper when `TestApp` or `PremiumTestApp` already fits.
172+
- Do not over-mock store, router, or client dependencies if the real test helpers can provide them.
173+
- Do not mix unrelated styles in one file. Match the nearest local spec.
174+
- Do not leave out `afterEach` cleanup when using `TestApp` or `PremiumTestApp`.
175+
- Do not create broad integration-style tests when a focused unit test is enough.

0 commit comments

Comments
 (0)