Skip to content
This repository was archived by the owner on Jun 26, 2026. It is now read-only.

Commit c78830f

Browse files
twoGiantsclaude
andcommitted
feat: add Function Edit Page
File tree browser and code editor for viewing and editing function source code on GitHub. Files load from the Git Data API, the handler file is auto-selected based on func.yaml runtime. Save & Deploy pushes changes back via updateRepo, which caches the last commit SHA to handle GitHub's eventually consistent ref storage. Migrate test runner from Jest to Vitest with MSW 2.x for GitHub API mocking. Merge RepoInfo and SourceRepo into single RepoMetadata type. Extract shared utils (parseNamespaceAndRuntime, getLanguageFromPath, handlerMap). Add CSP connect-src for GitHub API in dev mode. Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Stanislav Jakuschevskij <sjakusch@redhat.com>
1 parent 066fce0 commit c78830f

38 files changed

Lines changed: 4135 additions & 2430 deletions

AGENTS.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ This is the project map. Read this first, every session.
77
FaaS PoC UI for OpenShift Console — React + TypeScript + Webpack + PatternFly 6 + OCP Dynamic Plugin SDK.
88
See `docs/design/` for full design specs.
99

10+
## Communication
11+
12+
- Ask before staring modifications of code.
13+
- Ask before starting a new task or making a design decision.
14+
- Once actively implementing, keep going without asking. Only stop to ask when blocked by sandbox, permissions, or ambiguous requirements.
15+
1016
## Writing Style
1117

1218
No em dashes (``). Use commas, periods, or parentheses instead.

docs/ARCHITECTURE.md

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,23 @@ Arrows mean "imports / depends on."
3939
- Services never import Components or Views
4040
- No circular dependencies
4141

42-
## Page / Component / Hook Rules
42+
## React
4343

44-
**Components are simple** — they receive data via props, render it, and call callbacks to return data to the parent (or use context). No logic at the top of a component.
44+
### Page / Component / Hook Rules
4545

46-
**Pages are smart** — they use central hooks (e.g. `useClusterService`, `useSourceControl`) to fetch, prepare, and transform all data needed for downstream components.
46+
**Components are simple by default** — they receive data via props, render it, and call callbacks. No logic at the top of a component.
4747

48-
**Extract logic into hooks** — if a page or component has any logic (state management, data transformation, side effects), extract it into a co-named hook: `FunctionTable.tsx``useFunctionTable.ts`, `FunctionsListPage.tsx``useFunctionsListPage.ts`. If there is no logic, no hook is needed.
48+
**A component may own its own data and state when it encapsulates a self-contained capability that is not specific to any one page** (e.g., forge connection, auth flows, notification subscriptions). The component becomes the single owner of that concern. Pages consume it without orchestrating its internals.
49+
50+
**Pages are smart for page-specific data** — they use central hooks (e.g. `useClusterService`, `useSourceControl`) to fetch, prepare, and transform all data needed for downstream components.
51+
52+
**Extract logic into hooks** — if a page or component has any logic (state management, data transformation, side effects), extract it into a custom hook. If the hook is reused by multiple components, put it in a separate file: `useFunctionTable.ts`. If the hook is only used by one component, keep it in the same file, do not export it. If there is no logic, no hook is needed.
53+
54+
**File ordering** — within a file, put the exported component at the top, then its hook below, then helper functions at the bottom. Readers see the main thing first and can drill down.
55+
56+
### Performance
57+
58+
- **No speculative memoization**: Do not wrap every function in `useCallback` or every value in `useMemo` as a habit. Use them when there is a concrete reason: a `React.memo` child that depends on a stable reference, or a known re-render path (e.g., a sibling component re-rendering on every keystroke). Plain functions and derived values are the default.
4959

5060
## Architectural Guidance
5161

docs/STYLEGUIDE.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,17 @@
1717
- **No `any` type**: Use proper TypeScript types.
1818
- **No `console.log`**: Use structured approach if logging needed.
1919
- **Naming**: `use*` for hooks, `*Service` for services, PascalCase for components/types.
20+
- **Co-locate helper functions**: Keep helper functions in the same file as the component or hook that uses them. Test them indirectly through the consumer's tests. Only extract to `utils/` when shared across multiple unrelated modules.
2021

2122
## Documentation
2223

2324
- **No em dashes (``)**. Use commas, periods, or parentheses instead.
2425

26+
## CSS
27+
28+
- **PatternFly first**: Use PatternFly component props for all layout and spacing. Only fall back to custom CSS when PatternFly does not cover the need.
29+
- **Relative units only**: When custom CSS is necessary, use `rem` and `em` for all sizing. Never use `px`.
30+
2531
## OCP Plugin Styling Constraints
2632

2733
The `.stylelintrc.yaml` enforces strict rules to prevent breaking the OpenShift Console:

docs/WORKFLOW.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Every session, before doing any work:
1717
After [Startup Sequence](#startup-sequence), work through the picked feature:
1818

1919
1. **Plan** — read `docs/ARCHITECTURE.md` + `docs/STYLEGUIDE.md` + `docs/TESTING.md`, then use `/brainstorming` to design the chosen feature from `docs/features.json`, then use `/writing-plans` to create implementation plan → `docs/plans/active/<NNN>-<type>-<short-name>.md`
20-
2. **Branch** — create feature branch per [Branching](#branching) convention
20+
2. **Branch** — create feature branch per [Branching](#branching) convention. Immediately push and open a **draft PR** (`gh pr create --draft`) to reserve the PR number for other contributors' branch numbering.
2121
3. **Implement** — using `/executing-plans` skill
2222
4. **Review** — code review using `/requesting-code-review` skill, fix found issues
2323
5. **Manual Test** — use browser automation and validate it works in the browser

docs/features.json

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,19 @@
9696
],
9797
"passes": true
9898
},
99+
{
100+
"category": "technical",
101+
"description": "CI/CD: GitHub Actions pipelines for PR checks and master publish to GHCR, plus lint fixes and README deployment instructions",
102+
"steps": [
103+
"PR pipeline (.github/workflows/pr.yml): triggers on pull_request to master, runs yarn install --immutable, yarn lint, yarn test — branch cannot merge without passing checks and an approval",
104+
"Publish pipeline (.github/workflows/publish.yml): triggers on push to master (merged PRs), runs yarn install --immutable, yarn lint, yarn test, then builds multi-arch container image via docker/build-push-action using existing Dockerfile and pushes to ghcr.io/twogiants/console-functions-plugin with :latest and :sha-<commit> tags",
105+
"Both pipelines use actions/setup-node@v4 with node-version 22, corepack enable, and cache: yarn for Yarn install caching (GitHub runners ship Node 20 by default with corepack disabled)",
106+
"Both pipelines authenticate to GHCR using GITHUB_TOKEN secret with packages:write permission (token added to repo's Actions secrets)",
107+
"Add yarn lint script to package.json if missing, run it, and fix all lint errors in the codebase",
108+
"Update README.md deployment section (lines 96-117) — replace generic Helm boilerplate, placeholder commands, and obsolete OCP 4.10 / i18n notes with concrete instructions: oc new-project console-functions-plugin, helm upgrade -i console-functions-plugin charts/openshift-console-plugin -n console-functions-plugin --create-namespace --set plugin.image=ghcr.io/twogiants/console-functions-plugin:latest@sha256:<digest>"
109+
],
110+
"passes": true
111+
},
99112
{
100113
"category": "functional",
101114
"description": "GitHub PAT Avatar: session-wide PAT entry via modal + avatar component showing authenticated GitHub user",
@@ -127,19 +140,6 @@
127140
],
128141
"passes": false
129142
},
130-
{
131-
"category": "technical",
132-
"description": "CI/CD: GitHub Actions pipelines for PR checks and master publish to GHCR, plus lint fixes and README deployment instructions",
133-
"steps": [
134-
"PR pipeline (.github/workflows/pr.yml): triggers on pull_request to master, runs yarn install --immutable, yarn lint, yarn test — branch cannot merge without passing checks and an approval",
135-
"Publish pipeline (.github/workflows/publish.yml): triggers on push to master (merged PRs), runs yarn install --immutable, yarn lint, yarn test, then builds multi-arch container image via docker/build-push-action using existing Dockerfile and pushes to ghcr.io/twogiants/console-functions-plugin with :latest and :sha-<commit> tags",
136-
"Both pipelines use actions/setup-node@v4 with node-version 22, corepack enable, and cache: yarn for Yarn install caching (GitHub runners ship Node 20 by default with corepack disabled)",
137-
"Both pipelines authenticate to GHCR using GITHUB_TOKEN secret with packages:write permission (token added to repo's Actions secrets)",
138-
"Add yarn lint script to package.json if missing, run it, and fix all lint errors in the codebase",
139-
"Update README.md deployment section (lines 96-117) — replace generic Helm boilerplate, placeholder commands, and obsolete OCP 4.10 / i18n notes with concrete instructions: oc new-project console-functions-plugin, helm upgrade -i console-functions-plugin charts/openshift-console-plugin -n console-functions-plugin --create-namespace --set plugin.image=ghcr.io/twogiants/console-functions-plugin:latest@sha256:<digest>"
140-
],
141-
"passes": true
142-
},
143143
{
144144
"category": "functional",
145145
"description": "Set GitHub Secret (KUBECONFIG) on created function repos so GH Actions can deploy to the cluster",
@@ -150,5 +150,23 @@
150150
"GH Actions workflow can authenticate to the cluster and run func deploy"
151151
],
152152
"passes": false
153+
},
154+
{
155+
"category": "functional",
156+
"description": "Function Edit Page with TreeView file browser and CodeEditor for editing and deploying function code",
157+
"steps": [
158+
"SourceControlService extended with fetch(repo) method that retrieves full repo tree and file contents via git.getTree recursive + blob fetches",
159+
"GithubService push() updated to support subsequent commits (fetch HEAD SHA as parent, updateRef) in addition to initial commits",
160+
"Navigate to /faas/edit/:name loads files from GitHub (uses nav state SourceRepo if available, falls back to listFunctionRepos lookup)",
161+
"Page layout: toolbar at top (Back link left, danger Alert center, Save & Deploy button right), FileTreeView left panel (~16rem, horizontally scrollable), CodeEditor fills remaining width",
162+
"FileTreeView builds nested tree from flat FileEntry[] paths, directories expand/collapse only, files are selectable and update CodeEditor content",
163+
"CodeEditor displays selected file with language auto-detected from file extension via getLanguageFromPath utility",
164+
"Handler file auto-selected on load based on runtime from func.yaml (no fallback selection if handler not found)",
165+
"Modified files indicated in tree with dot and distinct color, dirty state derived by comparing working content against original per file on every onChange",
166+
"Save & Deploy button pushes all files to GitHub, resets dirty state on success, shows spinner and disables button during push",
167+
"Back to Functions link navigates to /faas directly if clean, shows unsaved changes confirmation modal if dirty",
168+
"Empty tree and empty editor shown when repo not found (no error message), Save & Deploy button disabled, back link always visible"
169+
],
170+
"passes": false
153171
}
154172
]

0 commit comments

Comments
 (0)