This repository was archived by the owner on Jun 26, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathfeatures.json
More file actions
171 lines (171 loc) · 11.9 KB
/
Copy pathfeatures.json
File metadata and controls
171 lines (171 loc) · 11.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
[
{
"category": "technical",
"description": "Plugin scaffolding: project builds, dev server starts, Functions nav item renders in sidebar",
"steps": [
"Scaffold project from OCP dynamic plugin template",
"Configure console-extensions.json with nav section + href",
"Dev server starts without errors",
"Functions nav item visible in sidebar"
],
"passes": true
},
{
"category": "technical",
"description": "Dev environment: init.sh starts and stops plugin and console, docs restructured into WORKFLOW.md",
"steps": [
"init.sh starts webpack dev server and OCP console container",
"init.sh waits for ports to be ready before exiting",
"init.sh --stop cleanly stops both processes",
"AGENTS.md slimmed to project overview, workflow extracted to docs/WORKFLOW.md"
],
"passes": true
},
{
"category": "functional",
"description": "Function List Page renders empty state when no functions exist",
"steps": [
"Navigate to /functions route",
"Empty state component renders with Create function button",
"Create function button links to /functions/create"
],
"passes": true
},
{
"category": "functional",
"description": "Function List Page renders a table with function entries",
"steps": [
"SourceControlService lists function repos via Octokit (topic:serverless-function) and fetches func.yaml per repo for runtime",
"ClusterService watches Deployments with label function.knative.dev/name via useK8sWatchResource, maps to DeployedFunction[]",
"useFunctionListPage hook merges repos + deployments into FunctionListItem[] (repos are source of truth, undeployed get NotDeployed status)",
"Table renders with columns: name, runtime, status, url, replicas, actions using PatternFly clickable rows",
"Status column uses SDK components: SuccessStatus (Running), ProgressStatus (Deploying/CreatingRepo/Pushing/PushedToGitHub), ErrorStatus (Error), InfoStatus (ScaledToZero/NotDeployed), StatusIconAndText+YellowExclamationTriangleIcon (Unknown)",
"URL column shows hostname-only clickable link opening in new tab",
"Clicking function row or edit action navigates to /functions/edit/:name",
"Delete action uses SDK useDeleteModal with custom message and Undeploy button text",
"Empty state renders when no functions exist, spinner while loading"
],
"passes": true
},
{
"category": "technical",
"description": "Go backend: custom Go server replaces nginx for static file serving",
"steps": [
"Go server embeds and serves webpack-built static files",
"Multi-stage Dockerfile: Node build, Go build, ubi9-micro runtime",
"TLS support with automatic fallback to HTTP-only",
"Nginx ConfigMap removed from Helm chart"
],
"passes": true
},
{
"category": "functional",
"description": "Function Create Page renders form with all fields",
"steps": [
"Navigate to /functions/create",
"Form renders with name, runtime, registry, namespace, repo name fields",
"Runtime field offers node, python, go options",
"Create and Cancel buttons are visible"
],
"passes": true
},
{
"category": "technical",
"description": "PR #5 review cleanup: consolidate duplicate GitHub services, fix naming conventions, extract hooks per architecture guidelines",
"steps": [
"Merge src/services/github/ into src/services/source-control/, combine OctokitGitHubService push logic into GithubService, remove src/services/github/ directory entirely",
"Rename GitHubService interface to SourceControlService and add push method to the existing SourceControlService interface (rename pushFiles to push per design doc)",
"Rename useGitHubService hook to useSourceControlService",
"Rename BackendFunctionService.ts to FunctionBackendService.ts",
"Remove duplicate @octokit/rest from devDependencies in package.json (keep only the entry under dependencies)",
"Extract useFunctionCreatePage hook from FunctionCreatePage — move service calls into useEffect (both FunctionService and SourceControlService call external APIs), keep the component rendering-only",
"Extract useCreateFunctionForm hook from CreateFunctionForm — consolidate individual useState calls into a single fields state object with a setField(key, value) helper, derive isValid from fields, remove handleSubmit (call onSubmit(fields) directly)",
"Update design doc (2026-03-16-faas-poc-design.md) to reflect all renames and new method signatures"
],
"passes": true
},
{
"category": "functional",
"description": "Route rename and nav restructure: change /functions to /faas, flatten dev nav, add admin nav under Workloads",
"steps": [
"Rename all routes from /functions/* to /faas/* (list, create, edit)",
"Developer perspective: replace section+href with a single top-level console.navigation/href 'FaaS' pointing to /faas",
"Admin perspective: add console.navigation/separator and console.navigation/href 'FaaS' under section 'workloads' at the bottom (using insertAfter)",
"Update all internal links and navigation calls (e.g., Create button href, form cancel, post-create redirect)",
"Update tests to use /faas routes"
],
"passes": true
},
{
"category": "technical",
"description": "CI/CD: GitHub Actions pipelines for PR checks and master publish to GHCR, plus lint fixes and README deployment instructions",
"steps": [
"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",
"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",
"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)",
"Both pipelines authenticate to GHCR using GITHUB_TOKEN secret with packages:write permission (token added to repo's Actions secrets)",
"Add yarn lint script to package.json if missing, run it, and fix all lint errors in the codebase",
"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>"
],
"passes": true
},
{
"category": "functional",
"description": "GitHub PAT Avatar: session-wide PAT entry via modal + avatar component showing authenticated GitHub user",
"steps": [
"PatModal opens automatically on first visit to Function List Page when no PAT is stored in session",
"PatModal is dismissable — user can close it without entering a PAT",
"PatModal validates the PAT against GitHub API and on success stores it in session and closes",
"UserAvatar component renders inside ListPageHeader at the top-right corner on every page (list, create, edit)",
"UserAvatar has two states: not initialized shows 'Connect to GitHub' with a key/lock icon (clickable, opens PatModal); initialized shows GitHub username with avatar icon",
"UserAvatar is clickable only on the Function List Page, clicking reopens PatModal to change the PAT and associated GitHub user",
"On Create and Edit pages, UserAvatar displays the GitHub user but is not clickable (PAT cannot be changed from those pages)",
"When PatModal is dismissed without a PAT, the Function List Page (both empty state and table view) shows a hint text directing the user to click 'Connect to GitHub' in the top-right corner to set a PAT",
"PAT change logic is encapsulated in a useUserAvatar custom hook following layered architecture (Hook imports Service, Component imports Hook)",
"If the GH PAT is not set in the session then the Create button is inactive/disabled.",
"The GH PAT must not be compiled/hardcode into code at compile time."
],
"passes": false
},
{
"category": "functional",
"description": "Function List Page shows deployed functions from all user-accessible namespaces without requiring a PAT",
"steps": [
"ClusterService refactored: remove ALL_NAMESPACES and useActiveNamespace logic, always watch across all user-accessible namespaces (functions in GitHub repos can target different namespaces via func.yaml, so single-namespace view is not useful; filtering deferred to a later feature)",
"ClusterService lists all namespaces/projects accessible to the logged-in user and watches Deployments with label function.knative.dev/name across all of them",
"Function List Page renders deployed functions even when no PAT has been entered (PatModal dismissed or not yet shown)",
"When PAT is later provided, repo data from SourceControlService is merged with already-visible deployed functions",
"Deployed functions without a matching repo still appear in the table with available cluster data (name, namespace, status, replicas, url)"
],
"passes": false
},
{
"category": "functional",
"description": "Set GitHub Secret (KUBECONFIG) on created function repos so GH Actions can deploy to the cluster",
"steps": [
"Add createSecret method to SourceControlService interface",
"Encrypt secret value with repo public key using tweetnacl or libsodium.js",
"Wire into create flow: after repo creation and file push, set KUBECONFIG secret on the repo",
"GH Actions workflow can authenticate to the cluster and run func deploy"
],
"passes": false
},
{
"category": "functional",
"description": "Function Edit Page with TreeView file browser and CodeEditor for editing and deploying function code",
"steps": [
"SourceControlService extended with fetch(repo) and updateRepo(repo) methods. fetch retrieves full repo tree via git.getTree recursive + blob fetches. updateRepo commits on existing branches with local commit SHA cache for GitHub's eventual consistency",
"Navigate to /faas/edit/:name loads files from GitHub via listFunctionRepos + fetch (each page loads its own data from URL params)",
"Page layout: toolbar at top (Back link left, success/danger Alert center, Save & Deploy button right), FileTreeView fixed-width left panel (16rem, horizontally scrollable), SDK CodeEditor fills remaining width (70vh height)",
"FileTreeView builds nested tree from flat FileEntry[] paths with loading spinner state, empty placeholder state, directories expand/collapse only, files are selectable and update CodeEditor content",
"SDK CodeEditor with empty state (code icon + 'Start editing' message) when no file selected, language label visible in header",
"CodeEditor language auto-detected from file extension via getLanguageFromPath utility",
"Handler file auto-selected on load based on runtime from func.yaml (no fallback selection if handler not found)",
"Modified files indicated in tree with dot indicator after filename, dirty state derived by comparing working content against original per file on every onChange",
"Save & Deploy button pushes all files to GitHub via updateRepo, resets dirty state on success, shows spinner and disables button during push, shows success alert with auto-dismiss after 2 seconds",
"Back to Functions link navigates to /faas directly if clean, shows unsaved changes confirmation modal if dirty",
"Empty tree with 'No files' placeholder and disabled Save & Deploy when repo not found, back link always visible"
],
"passes": true
}
]