feat: CMD-187 autocreate search page - #1129
Conversation
So that it can be loaded from CDN. Use cases are: - if search template is broken - for custom search page - for non-Core website
Compared to "cms-search", "google-search" is: - more accurate - more obvious to those not familiar with Core-CMS
So dev sees 'google-search' from CSS before seeing it in HTML `id` attr.
Caused server error.
This had create dbreadcrumsb before.
Final markup undecided, so keep it simple, and easy to understand.
Updated pull request template to improve clarity and structure.
## Overview Update to [Core-Styles v2.55](https://github.com/TACC/Core-Styles/releases/tag/v2.55.0) for: - accessibility fixes to `.section`s - new `.section` style **`accent`** - support [Bootstrap v4 `media` object](https://getbootstrap.com/docs/4.6/components/media-object/) - new script to create page to test sections ## Related - required by TACC/Core-CMS-Custom#531 ## Changes - **updated** Core-Styles - **added** section--accent` ## Testing 1. `make build` 2. `make start` 3. Create a page with: - two sections, one after the other - each section has `<h2>` and text - try different section combinations 4. Verify UI matches sections of: - TACC/Core-Styles#625 - TACC/Core-Styles#624 ## UI <img width="899" height="470" alt="Screenshot 2026-04-08 at 20 48 11" src="https://github.com/user-attachments/assets/bc90026d-c1c0-4491-b362-913aa7eb48eb" />
## Overview / Changes Update Dockerfile to use Node 20 (to match Core-Styles dependency expectation). ## Related - TACC/Core-Styles#595 ## Testing 1. `make stop` 2. `make build` 3. `make start` 4. No errors. 5. http://localhost:8000/ 6. Site loads. ## UI ```log Core-CMS % make build docker-compose -f ./docker-compose.yml build [+] Building 128.4s (26/26) FINISHED => [internal] load local bake definitions 0.0s => => reading from stdin 517B 0.0s => [internal] load build definition from Dockerfile 0.1s => => transferring dockerfile: 1.72kB 0.0s => WARN: FromAsCasing: 'as' and 'FROM' keywords' casing do not match 0.1s => WARN: FromAsCasing: 'as' and 'FROM' keywords' casing do not match 0.1s => WARN: FromAsCasing: 'as' and 'FROM' keywords' casing do not match 0.1s => WARN: FromAsCasing: 'as' and 'FROM' keywords' casing do not match 0.1s => [internal] load metadata for docker.io/library/node:20 3.9s => [internal] load metadata for docker.io/library/python:3.11-bullse 2.8s => [auth] library/python:pull token for registry-1.docker.io 0.0s => [auth] library/node:pull token for registry-1.docker.io 0.0s => [internal] load .dockerignore 0.0s => => transferring context: 176B 0.0s => [python-base 1/8] FROM docker.io/library/python:3.11-bullseye@sha 0.0s => => resolve docker.io/library/python:3.11-bullseye@sha256:df0bd610 0.0s => [node_build 1/6] FROM docker.io/library/node:20@sha256:8789e1e07 50.4s => => resolve docker.io/library/node:20@sha256:8789e1e0752d81088a085 0.0s => => sha256:05af486a428bc264e22e9b46c9b0d3e75a3b868c1b4 447B / 447B 0.6s => => sha256:3043560987f3ed858a74597354d7d913ab0ae88 1.25MB / 1.25MB 0.5s => => sha256:4ab7d5d5363a3853730f20f1192dd6640eba1 48.59MB / 48.59MB 3.6s => => sha256:2ad0741a80b84ae8126670b69ac8e761fc 203.07MB / 203.07MB 12.8s => => sha256:d970c14c7a02db7b2db8e2a7f7302b3362854d2 3.33kB / 3.33kB 0.3s => => sha256:95b913dee6e116304b9bb2391ef8aedbb1f5e 64.48MB / 64.48MB 9.6s => => sha256:0af98f0879b367460715b477e9118922ba24f 23.60MB / 23.60MB 9.6s => => sha256:d03e31a3f7ef0d2866d799846c3a18286fab 48.37MB / 48.37MB 10.2s => => extracting sha256:d03e31a3f7ef0d2866d799846c3a18286fab6fcddbd8 3.7s => => extracting sha256:0af98f0879b367460715b477e9118922ba24f17d9a4a 1.5s => => extracting sha256:95b913dee6e116304b9bb2391ef8aedbb1f5ee16d16 10.4s => => extracting sha256:2ad0741a80b84ae8126670b69ac8e761fcd50aa252d 11.8s => => extracting sha256:d970c14c7a02db7b2db8e2a7f7302b3362854d2d5307 0.0s => => extracting sha256:4ab7d5d5363a3853730f20f1192dd6640eba1a6576ab 7.0s => => extracting sha256:3043560987f3ed858a74597354d7d913ab0ae886bbe9 0.1s => => extracting sha256:05af486a428bc264e22e9b46c9b0d3e75a3b868c1b48 0.1s => [internal] load build context 2.3s => => transferring context: 15.02MB 2.2s => [node_build 2/6] COPY package.json package-lock.json /code/ 1.9s => [node_build 3/6] WORKDIR /code 0.1s => [node_build 4/6] RUN npm ci 14.3s => [node_build 5/6] COPY . /code/ 3.1s => [node_build 6/6] RUN npm run build --build-id="$BUILD_ID" 16.8s => CACHED [python-base 2/8] RUN apt-get update && apt-get install -y 0.0s => CACHED [python-base 3/8] RUN pip3 install --upgrade pip setuptool 0.0s => CACHED [python-base 4/8] RUN curl -sSL https://install.python-poe 0.0s => CACHED [python-base 5/8] RUN mkdir /code 0.0s => CACHED [python-base 6/8] COPY pyproject.toml poetry.lock /code/ 0.0s => CACHED [python-base 7/8] WORKDIR /code 0.0s => CACHED [python-base 8/8] RUN poetry install --only main --no-root 0.0s => CACHED [production 1/2] RUN mkdir -p /var/log/cms 0.1s => [production 2/2] COPY --from=node_build /code/ /code 2.1s => exporting to image 18.2s => => exporting layers 13.3s => => exporting manifest sha256:3c78d75eb72ed4e682cc3e5474d578cc5bb4 0.1s => => exporting config sha256:50d8ed278a89aca09a0acb279557e19803c2ce 0.0s => => exporting attestation manifest sha256:9a1884c8b82634fb21ccaf3f 0.1s => => exporting manifest list sha256:f5200ba0b4a47719c2fac6e6da6c117 0.0s => => naming to docker.io/taccwma/core-cms:latest 0.0s => => unpacking to docker.io/taccwma/core-cms:latest 4.5s => resolving provenance for metadata file 0.1s [+] build 1/1 ✔ Image taccwma/core-cms:latest Built 130.8s ```
## Overview Another Core-Styles bump for accessibility fixes. I actually think I am near the end of all this, for now.
## Overview **Before:** * no footer links by default * added footer link style did not match design **After:** * footer links by default * footer link style matches design * footer links are accessible ## Related - requires [TACC/Core-Styles@v2.56.0](https://github.com/TACC/Core-Styles/releases/tag/v2.56.0) ## Changes - **added** default footer links - **updated** Core-Styles ## Testing 1. `make setup` 2. Open http://localhost:8000/. 3. See footer has links. 4. See footer links match text color but have faint underline. 5. See footer link hover and press change footer link style. ## UI | Before Links<br>Before Styles | After Links<br>Before Styles | After Links<br>After Styles | | - | - | - | | <img width="405" height="465" alt="before footer links, before footer styles" src="https://github.com/user-attachments/assets/429eccc5-2106-42bf-81a3-a1b849ffb2df" /> | <img width="405" height="465" alt="after footer links, before footer styles" src="https://github.com/user-attachments/assets/16fe8fa6-3046-49c3-8186-f7539f1766a0" /> | <img width="405" height="465" alt="after footer links, after footer styles" src="https://github.com/user-attachments/assets/9a23bf01-dd20-4d96-a6d7-f8cb24264ae2" /> https://github.com/user-attachments/assets/18fc6809-4854-4e04-a57d-60f38a2e23e1 https://github.com/user-attachments/assets/ce4a87df-5f66-4638-93b8-3a27506c8d4e https://github.com/user-attachments/assets/71fe0d5c-c4ca-4908-b1a2-74be5aba0e21
Stop reporting this outdated security risk.
Updated the default URL path for the Section/Container style QA page from '/section-style-qa/' to '/test-section-style/'.
## Overview Updated README to reflect command name change for creating test pages.
Added sections for Architecture and Pull Requests to AGENTS.md.
I know its for agents, but i view it when I need to edit. And others view it when they want to know.
Found helpful since using local agents.
## Overview Use a Core-Styles commit-ish with the footer text-color fix. ## Related - requires TACC/Core-Styles#633 ## Changes - **updated** `@tacc/core-styles` to a branch-based install - **updated** lockfile entries to the matching Core-Styles commit ## Testing 1. Verify dependency and lockfile both reference `fix/footer-text-color-one-step-darker`. 2. Build CSS locally and confirm footer text/links render one step darker. ## UI <img width="960" height="874" alt="cms-footer-after" src="https://github.com/user-attachments/assets/48b850ce-7f0e-43f2-be2c-ded2452113fc" /> --- Made with [Cursor](https://cursor.com)
Review Summary by QodoAuto-create Google Search page with Django CMS integration
WalkthroughsDescription• Automatically create and manage Google Search page with minimal configuration • Add new search_page Django app with CMS integration and apphook support • Introduce SEARCH_PAGE_AUTO_SETUP and GOOGLE_SEARCH_ENGINE_ID settings • Implement search template with Google Custom Search Engine styling and fallback warning • Update search bar to use dynamically resolved search page URL via template tag Diagramflowchart LR
A["Settings<br/>SEARCH_PAGE_AUTO_SETUP<br/>GOOGLE_SEARCH_ENGINE_ID"] -->|triggers| B["SearchPageConfig.ready()"]
B -->|calls| C["create_page()"]
C -->|creates CMS Page<br/>with apphook| D["SearchPageApphook"]
D -->|routes to| E["SearchPageView"]
E -->|renders| F["search_page.html<br/>with Google CSE"]
G["nav_search.raw.html"] -->|uses| H["search_page_url tag"]
H -->|resolves to| D
File Changes1. apps/search_page/apps.py
|
Code Review by Qodo
Context used✅ Tickets:
CMD-187 1. Unused Page import
|
| @@ -0,0 +1,10 @@ | |||
| from django import template | |||
| from cms.models import Page | |||
There was a problem hiding this comment.
1. Unused page import 📘 Rule violation ⚙ Maintainability
taccsite_cms/templatetags/search_tags.py imports Page but never uses it, which triggers a Flake8 F401 unused import violation. This can fail linting for the taccsite_cms/ module.
Agent Prompt
## Issue description
`taccsite_cms/templatetags/search_tags.py` imports `Page` but does not use it, which violates Flake8 (`F401`).
## Issue Context
Compliance requires no new Flake8 violations when running `flake8 taccsite_cms/ --max-line-length=120`.
## Fix Focus Areas
- taccsite_cms/templatetags/search_tags.py[1-4]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| def ready(self): | ||
| if settings.SEARCH_PAGE_AUTO_SETUP: | ||
| from .utils import create_page | ||
| create_page() |
There was a problem hiding this comment.
2. Db write in appconfig.ready 🐞 Bug ☼ Reliability
SearchPageConfig.ready() calls create_page(), which performs ORM reads/writes during Django app initialization; this can crash server startup or management commands when CMS tables aren’t migrated/available yet. The codebase already uses post_migrate for DB bootstrapping, so this is an inconsistent and unsafe initialization mechanism.
Agent Prompt
## Issue description
`SearchPageConfig.ready()` triggers DB work (`create_page()`) during app initialization. This runs on every process start and can fail before migrations (or when DB is unavailable), preventing startup.
## Issue Context
The repository already bootstraps DB state using `post_migrate` (see `taccsite_cms/apps.py`). The search page creation should follow the same pattern and be resilient to missing tables.
## Fix Focus Areas
- apps/search_page/apps.py[1-10]
- apps/search_page/utils.py[41-64]
- taccsite_cms/apps.py[13-24]
## Implementation notes
- Replace `ready()` DB call with `post_migrate.connect(...)` (like `taccsite_cms.apps.TaccsiteCmsConfig`).
- Guard access to `settings.SEARCH_PAGE_AUTO_SETUP` via `getattr(settings, 'SEARCH_PAGE_AUTO_SETUP', False)`.
- Ensure the handler is idempotent and wraps DB errors (e.g., `OperationalError`, `ProgrammingError`) with logging instead of crashing startup.
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
## Overview Rebuilds the search feature on current `main` instead of stale `release/v4.36.X`. > [!WARNING] > First run on a fresh database will crash `manage.py migrate` itself, because `apps/search_page/apps.py`'s `ready()` hook queries `cms_page` before it exists. Workaround: set `SEARCH_PAGE_AUTO_SETUP = False`, migrate, then set it back to `True` and restart. [Details.](#885 (review)) > [!IMPORTANT] > Should instead: > - [Use a custom migration.](#885 (review)) > - (and/or) Create a [Core-CMS plugin](https://github.com/search?q=org%3ATACC+%22Core-CMS-Plugin%22&type=repositories) (from [TACC/Django-App](https://github.com/TACC/Django-App)). ## Related - replaces #1129 ## Changes - **rebuilt** branch from `main` + cherry-picked search-only commits - **dropped** unrelated inherited commits (favicons, breadcrumbs, image-zoom, etc.) ## Testing / UI See #1129.
Tip
Superseded by #1215 (into #1216).
Overview
Support a Google Search page with less effort.
What Effort?
Every Time:
code→ ID.SEARCHsettings.Previously:
/searchpage.Now, Instead:
Important
Incomplete because there is a suggestion (which I agree with) to use a custom migration.
Originally built off code from
release/v4.36.Xwhen it had beenmainbranch.Caution
Do not merge.
To Do:
mainbranch.Warning
Successful run requires two deploys. Help wanted.
Related
Instances:
Private, so no results.
Private, but has results from public LCCF.
Private still, so no results.
Changes
search_pageappSEARCH_AUTO_SETUPsettingGOOGLE_SEARCH_ENGINE_IDsettingTesting
GOOGLE_SEARCH_ENGINE_IDsetting e.g.GOOGLE_SEARCH_ENGINE_ID = 'b099996c09ebd4ece'SEARCH_AUTO_SETUP = Truesetting.GOOGLE_SEARCH_ENGINE_IDsetting.UI
GOOGLE_SEARCH_ENGINE_IDGOOGLE_SEARCH_ENGINE_ID