Skip to content

Add variable UI#1251

Merged
ikhoon merged 5 commits into
line:mainfrom
ikhoon:variable-ui
Feb 2, 2026
Merged

Add variable UI#1251
ikhoon merged 5 commits into
line:mainfrom
ikhoon:variable-ui

Conversation

@ikhoon

@ikhoon ikhoon commented Jan 29, 2026

Copy link
Copy Markdown
Contributor

Motivation:

As a final step in template file support, add a UI for manipulating variables so users can manage variables and preview rendered files in the Central Dogma webapp.

Modifications:

  • Add CRUD pages for variables in the project and repository settings page.
  • Add Preview with Variables tab in the file viewer to preview the rendered file with applied variables.
  • Rename applyTemplate to renderTemplate, which seems to convey the intention more clearly for both the method and parameter name.
  • Lower the permission level of variable management to MEMBER and WRITE from ProjectRole.OWNER and RepositoryRole.ADMIN.
    • If users can modify files, they can also modify .variables.xxx file, so granting the same permission seems to make sense.
  • Change the file pattern in the file editor to allow dot files.
  • Redirect localhost:3000 to 127.0.0.1:3000 to avoid cross-origin issues in development environments.

Result:

You can now manage variables using the variable UI in Central Dogma web app.

@ikhoon ikhoon added this to the 0.80.0 milestone Jan 29, 2026
@coderabbitai

coderabbitai Bot commented Jan 29, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Adds variable metadata and UI plus renames template flag: Variable gains nullable description and creation (UserAndTimestamp); services record creation and adjust permissions; applyTemplate renamed to renderTemplate across server/client; tests updated; frontend adds variable CRUD UI, RTK Query endpoints, and preview-with-variables support.

Changes

Cohort / File(s) Summary
Server: Variable model & service
server/src/main/java/.../variable/Variable.java, server/src/main/java/.../variable/VariableServiceV1.java
Added nullable description and mutable creation to Variable; updated constructors, equals/hashCode, toString; VariableServiceV1 now sets creation during variable construction and adjusted permission levels on some endpoints.
Server: Templating & watch
server/src/main/java/.../TemplateParams.java, server/src/main/java/.../TemplateParamsConverter.java, server/src/main/java/.../ContentServiceV1.java, server/src/main/java/.../WatchService.java
Renamed applyTemplate → renderTemplate across TemplateParams and converters; ContentServiceV1 forwards variableFile and templateRevision into templater.render; watch uses renderTemplate flag.
Server tests
server/src/test/java/.../VariableTemplateCrudTest.java, server/src/test/java/.../variable/VariableServiceV1Test.java
Updated tests to use new Variable constructor (creation/description), replaced applyTemplate→renderTemplate callsites, and adjusted expected objects/assertions.
Client Java libraries
client/java*/src/.../*.java, client/java-armeria/.../ArmeriaCentralDogma.java, client/java-armeria-legacy/.../LegacyCentralDogma.java
Renamed applyTemplate → renderTemplate across public APIs, request objects, watchers, and FileWatcher; updated method signatures and call sites while preserving behavior.
Webapp: API slice & types
webapp/src/dogma/features/api/apiSlice.ts, webapp/src/dogma/features/project/settings/variables/VariableDto.ts
Added VariableDto type (id,type,name?,value,description?,creation?) and RTK Query endpoints/hooks for variables; extended getFileContent to accept optional renderTemplate.
Webapp: Variable UI & pages
webapp/src/dogma/features/project/settings/variables/*, webapp/src/pages/.../settings/variables/**
Added VariableForm, VariableList, VariableView, DeleteVariable components and project/repo pages for list/new/view/edit; wired to new API hooks, notifications, and navigation.
Webapp: Settings tabs
webapp/src/dogma/features/project/settings/ProjectSettingsView.tsx, webapp/src/dogma/features/repo/settings/RepositorySettingsView.tsx
Added 'variables' tab to project and repo settings and extended TabName unions with appropriate accessRole values.
Webapp: Editor preview & FileEditor
webapp/src/dogma/common/components/editor/FileEditor.tsx
Preview tab can show "Preview with Variables"; FileEditor fetches file content with renderTemplate and computes modifiedContent for diff/preview.
Webapp: Misc UI & config
webapp/src/dogma/common/components/DeleteConfirmationModal.tsx, webapp/next.config.js, small copyright files
Highlight id in delete modal with Chakra Mark; added host-based redirect in Next.js config; minor copyright header updates.

Sequence Diagram(s)

mermaid
sequenceDiagram
autonumber
participant UI as Frontend UI
participant API as Web API (apiSlice)
participant Server as Central Dogma Server
participant DB as Persistence

UI->>API: addNewVariable(project, repo, VariableDto{id,type,value,description})
API->>Server: POST /api/v1/projects/{p}/repos/{r}/variables (payload)
Server->>Server: VariableServiceV1.setNameAndCreation(author) — attach creation metadata
Server->>DB: persist Variable (id,type,value,description,creation)
DB-->>Server: ack
Server-->>API: 201 Created (VariableDto)
API-->>UI: resolve / update cache / notify

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • trustin
  • jrhee17
  • minwoox

Poem

🐰
I dug a little field of name and time,
A tiny description, a timestamp chime.
From backend burrow to the UI glade,
Variables hop out, in tidy parade.
Hop-hop — new fields bloom, and tests applaud 🌿

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 17.81% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add variable UI' directly and accurately describes the main focus of the pull request: introducing a user interface for variable management.
Description check ✅ Passed The description is well-structured, relates directly to the changeset, and clearly explains the motivation, modifications, and results of adding variable UI functionality.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 14

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
webapp/src/dogma/features/repo/settings/RepositorySettingsView.tsx (1)

38-55: Verify anonymous access for repo variables.

allowAnonymous: true on the variables tab may leak repo-level variable values. If variables can contain secrets/config, disable anonymous access.

🔒 Suggested adjustment
-  { name: 'variables', path: 'variables', accessRole: 'WRITE', allowAnonymous: true },
+  { name: 'variables', path: 'variables', accessRole: 'WRITE', allowAnonymous: false },
🤖 Fix all issues with AI agents
In
`@server/src/main/java/com/linecorp/centraldogma/server/internal/api/variable/Variable.java`:
- Around line 120-122: In Variable.equals(...) replace the direct call
creation.equals(variable.creation) with a null-safe comparison using
Objects.equals(creation, variable.creation) so the nullable field annotated
`@Nullable` is compared safely; update the equals method in class Variable to use
Objects.equals for the creation field (keeping existing comparisons for non-null
fields like value as-is).

In
`@server/src/main/java/com/linecorp/centraldogma/server/internal/api/variable/VariableServiceV1.java`:
- Around line 231-241: The helper setNameAndCreation currently overwrites the
variable.creation on both create and update; split responsibilities by adding a
new helper setName(Variable variable, String projectName, `@Nullable` String
repoName) that only builds and sets the name, and keep
setNameAndCreation(Variable..., Author) for creation flows; update all update*
handlers to call setName instead of setNameAndCreation, and ensure create*
handlers continue to call setNameAndCreation (or alternatively, guard inside
setNameAndCreation to only set creation if variable.getCreation() == null or
rename creation to lastModified if overwriting was intended).

In `@webapp/src/dogma/features/project/settings/ProjectSettingsView.tsx`:
- Around line 37-45: The variables tab currently allows anonymous access which
may leak sensitive values; locate the 'variables' tab configuration in
ProjectSettingsView.tsx (related to the TabName union and the tab options around
the allowAnonymous flag) and change its access control so it no longer sets
allowAnonymous: true unless you intentionally want public access — instead set
allowAnonymous: false or replace with an authenticated-role check (e.g., require
specific roles or isAuthenticated) for the variables tab to ensure only
authorized users can view variable values.

In `@webapp/src/dogma/features/project/settings/variables/VariableForm.tsx`:
- Around line 176-188: The JSON Textarea in the VariableForm component is
missing a defaultValue so edit mode doesn't pre-populate the field; update the
Textarea (id="value-json") to pass defaultValue using the existing
defaultValue.value (or JSON.stringify(defaultValue.value) if the stored value is
an object) and keep the existing react-hook-form register validation
(register('value', ...)) so the textarea shows the current variable value when
editing.
- Around line 214-217: The Create button in the VariableForm component doesn't
reflect the submission state; update it to mirror the Update button by passing
the same loading prop used there (e.g., isLoading={isSubmitting} or
loading={isSubmitting}) and keep loadingText="Creating", and also disable the
button while submitting (disabled={isSubmitting}) to prevent double-submission —
locate the Button inside the isNew branch in VariableForm and apply the same
loading/disabled logic used by the Update button.
- Around line 198-206: In VariableForm update the description Textarea so its id
and name reflect the description field (currently id="value" and name="value"):
change them to id="description" and name="description" to match
register('description') and defaultValue.description; this fixes accessibility
and avoids confusion between the value and description inputs.
- Around line 142-152: The loop callback parameter shadows the component state
variable named variableType causing the defaultChecked comparison to be wrong;
in the VARIABLE_TYPES.map callback rename the parameter (e.g., option or
typeOption) to avoid shadowing, and update the Radio's defaultChecked to compare
the loop item's type to the component state (variableType) or the intended
selected value (e.g., defaultChecked={variableType === option.type} or checked
based on the form value) while keeping the register('type') usage and
defaultValue reference correct.

In `@webapp/src/dogma/features/project/settings/variables/VariableList.tsx`:
- Around line 69-76: Accessor callbacks for the VariableDto columns assume
creation is always present and will throw when creation is undefined; update the
columnHelper.accessor calls (the ones that read creation.user and
creation.timestamp) to safely handle missing creation by using optional chaining
(e.g., row.creation?.user and row.creation?.timestamp) and return sensible
fallbacks in the cell renderers (e.g., empty string or "—" for Text and a
null-safe DateWithTooltip prop) so the UI does not error when creation is
undefined.

In `@webapp/src/dogma/features/project/settings/variables/VariableView.tsx`:
- Around line 160-175: The code reads variable.creation.user and
variable.creation.timestamp directly but VariableDto marks creation as optional;
update the VariableView rendering to guard against undefined creation: check
variable.creation before accessing .user and before passing .timestamp to
DateWithTooltip (e.g., render a fallback like "-" or "Unknown" for user and only
render DateWithTooltip when creation?.timestamp exists). Apply these checks
where variable.creation is referenced in VariableView (around the Modified By
and Modified At rows) so null/undefined creation won't cause a runtime error.
- Around line 83-94: The PrismJS version used in VariableView.tsx (where
Prism.highlight is called inside the render/format helper that returns a <Code
... dangerouslySetInnerHTML={{ __html: Prism.highlight(...) }} />) is
vulnerable; update the PrismJS dependency in package.json to "prismjs":
">=1.30.0" (or bump to latest), run your package manager to refresh lockfile
(npm install / yarn install / pnpm install), and rebuild; ensure the updated
lockfile/lock entries are included in the PR so CI picks up the patched Prism
(no code changes to VariableView.tsx required other than dependency bump).

In
`@webapp/src/pages/app/projects/`[projectName]/repos/[repoName]/settings/variables/[id]/index.tsx:
- Around line 25-31: RepoVariableViewPage fires useGetVariableQuery with invalid
params because router.query can be undefined on first render; update the
component to wait for router.isReady before calling the query by passing a
boolean skip (or `skip: !router.isReady`) or conditional call to
useGetVariableQuery so it only runs when router.isReady is true and
projectName/repoName/id are non-empty; reference the component name
(RepoVariableViewPage), the router.isReady flag, and the hook
useGetVariableQuery to locate where to add the guard.

In
`@webapp/src/pages/app/projects/`[projectName]/repos/[repoName]/settings/variables/new/index.tsx:
- Around line 43-55: The onSubmit handler contains an unreachable error check
after calling addNewVariable(...).unwrap(); remove the redundant block that
inspects (response as { error: ... }).error and the throw, since unwrap()
already throws on error; instead treat response as the successful payload and
proceed to dispatch newNotification, call onSuccess(), and Router.push; update
references in this function (onSubmit, addNewVariable, unwrap, dispatch,
newNotification, Router.push) so the code flow assumes unwrap either returns the
success response or throws.

In
`@webapp/src/pages/app/projects/`[projectName]/settings/variables/[id]/edit/index.tsx:
- Around line 39-45: The onSubmit handler currently mutates the incoming
VariableDto and contains an unreachable post-unwrap error check; instead, stop
mutating the parameter and build a new payload object (e.g., const payload = {
...variable, name: `projects/${projectName}/variables/${variable.id}` }) and
pass that to updateVariable({ projectName, id, variable: payload }). Remove the
if-check that inspects response.error after calling .unwrap() since unwrap
throws on errors and will be handled by the catch block.

In
`@webapp/src/pages/app/projects/`[projectName]/settings/variables/[id]/index.tsx:
- Around line 25-30: The page calls useGetVariableQuery with router.query values
before Next's router is ready causing invalid requests; update VariableViewPage
to wait for router.isReady and only call useGetVariableQuery when ready by
deriving projectName and id after router.isReady and passing the RTK Query hook
a skip option (or conditional) so useGetVariableQuery({ projectName, id }, {
skip: !router.isReady }) is used until router.isReady is true.
🧹 Nitpick comments (8)
webapp/src/pages/app/projects/[projectName]/settings/variables/index.tsx (1)

28-29: Consider skipping the query when projectName is empty.

When the router isn't ready, projectName will be an empty string, causing an unnecessary API call. Consider using RTK Query's skip option to prevent this.

♻️ Suggested improvement
-  const projectName = router.query.projectName ? (router.query.projectName as string) : '';
-  const { data: variablesData } = useGetVariablesQuery({ projectName });
+  const projectName = router.query.projectName as string;
+  const { data: variablesData } = useGetVariablesQuery({ projectName }, { skip: !projectName });
webapp/src/pages/app/projects/[projectName]/settings/variables/[id]/edit/index.tsx (1)

31-33: Consider guarding against undefined router params.

Direct casting without checking could cause issues when the router isn't ready (e.g., during initial render). The query will also fire with undefined values.

♻️ Suggested improvement
   const router = useRouter();
-  const projectName = router.query.projectName as string;
-  const id = router.query.id as string;
+  const projectName = (router.query.projectName as string) || '';
+  const id = (router.query.id as string) || '';

-  const { data, isLoading: isVariableLoading, error } = useGetVariableQuery({ projectName, id });
+  const { data, isLoading: isVariableLoading, error } = useGetVariableQuery(
+    { projectName, id },
+    { skip: !projectName || !id }
+  );
webapp/src/pages/app/projects/[projectName]/repos/[repoName]/settings/variables/index.tsx (1)

28-30: Consider skipping the query when params are empty.

Same as the project-level page—when the router isn't ready, queries will fire with empty strings.

♻️ Suggested improvement
-  const projectName = router.query.projectName ? (router.query.projectName as string) : '';
-  const repoName = router.query.repoName ? (router.query.repoName as string) : '';
-  const { data: variablesData } = useGetVariablesQuery({ projectName, repoName });
+  const projectName = router.query.projectName as string;
+  const repoName = router.query.repoName as string;
+  const { data: variablesData } = useGetVariablesQuery(
+    { projectName, repoName },
+    { skip: !projectName || !repoName }
+  );
webapp/src/dogma/features/project/settings/variables/VariableList.tsx (1)

26-41: Remove unused generic type parameter.

The generic Data extends object is unused—the component only works with VariableDto. The eslint-disable comment confirms this is dead code.

♻️ Suggested simplification
-// eslint-disable-next-line `@typescript-eslint/no-unused-vars`
-export type VariableListProps<Data extends object> = {
+export type VariableListProps = {
   projectName: string;
   repoName?: string;
   variables: VariableDto[];
   deleteVariable: (projectName: string, id: string, repoName?: string) => Promise<void>;
   isLoading: boolean;
 };

-const VariableList = <Data extends object>({
+const VariableList = ({
   projectName,
   repoName,
   variables,
   deleteVariable,
   isLoading,
-}: VariableListProps<Data>) => {
+}: VariableListProps) => {
webapp/src/pages/app/projects/[projectName]/settings/variables/new/index.tsx (2)

45-47: Redundant error check after unwrap().

RTK Query's unwrap() already throws the error if the mutation fails, so the response will only contain the actual data on success. This error check will never be true.

🔧 Suggested fix
     try {
       const response = await addNewVariable({ projectName, newVariable }).unwrap();
-      if ((response as { error: FetchBaseQueryError | SerializedError }).error) {
-        throw (response as { error: FetchBaseQueryError | SerializedError }).error;
-      }
       dispatch(newNotification('New variable is created', `Successfully created`, 'success'));

17-17: Inconsistent router usage.

The code imports both Router (default) and useRouter, then uses router from the hook on Line 36 but Router.push on Line 50. Consider using router.push consistently since the router instance is already available.

🔧 Suggested fix
-import Router, { useRouter } from 'next/router';
+import { useRouter } from 'next/router';

Then on Line 50:

-      Router.push(`/app/projects/${projectName}/settings/variables`);
+      router.push(`/app/projects/${projectName}/settings/variables`);

Also applies to: 50-50

webapp/src/pages/app/projects/[projectName]/repos/[repoName]/settings/variables/[id]/edit/index.tsx (2)

43-45: Redundant error check after unwrap().

Same as noted in the project-level new variable page - RTK Query's unwrap() throws on error, so this check is unreachable.

🔧 Suggested fix
     try {
       const response = await updateVariable({ projectName, repoName, id, variable }).unwrap();
-      if ((response as { error: FetchBaseQueryError | SerializedError }).error) {
-        throw (response as { error: FetchBaseQueryError | SerializedError }).error;
-      }
       dispatch(newNotification(`Variable '${variable.id}' is updated`, `Successfully updated`, 'success'));

17-17: Inconsistent router usage.

Same pattern as the project-level page - imports both Router and useRouter, but could use router.push consistently.

Also applies to: 48-48

Comment thread webapp/src/dogma/features/project/settings/ProjectSettingsView.tsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Fix all issues with AI agents
In
`@server/src/main/java/com/linecorp/centraldogma/server/internal/api/converter/TemplateParamsConverter.java`:
- Around line 43-48: The code in TemplateParamsConverter currently reads only
ctx.queryParam("renderTemplate") which breaks clients still sending
applyTemplate; update the parsing in the TemplateParamsConverter so it accepts
both names: first check ctx.queryParam("renderTemplate") and if null fallback to
ctx.queryParam("applyTemplate"), parse the chosen value with
Boolean.parseBoolean (default false when null), keep variableFile and
templateRevision logic the same (templateRevStr -> new Revision(...)), and call
TemplateParams.of(renderTemplate, variableFile, templateRevision); ensure the
preference order uses renderTemplate when both are present.

In `@webapp/src/dogma/common/components/editor/FileEditor.tsx`:
- Around line 126-139: modifiedContent can be left undefined when the preview
query is skipped or the editor hasn't mounted; ensure you always assign a safe
fallback (e.g., empty string) so the preview remains stable. Update the
assignment logic for modifiedContent in FileEditor.tsx to use nullish coalescing
or explicit fallbacks: use dataWithVariables?.rawContent ?? '' when readOnly and
no error, use `ErrorMessageParser.parse(error)` guarded and default to `''` if
parsing fails, and use `editorRef?.current?.getValue() ?? ''` when not readOnly.
Apply the same pattern to the other occurrence referenced (around lines 250-265)
so both code paths always produce a defined string.
- Line 147: Remove the debug console.log that prints file contents in
FileEditor.tsx (the line logging fileContent, originalContent, revision).
Replace it by either removing the statement entirely or, if runtime tracing is
needed, log only non-sensitive metadata (e.g., file identifier or revision) and
never raw fileContent/originalContent; update any tests or callers that relied
on that console output accordingly.
- Around line 141-145: The current render block mutates state directly by
comparing cachedRevision to revision and calling setFileContent and
setCachedRevision; move this synchronization out of render into a useEffect hook
that depends on revision (and optionally displayContent) so the effect runs when
revision changes, and inside the effect call setFileContent(displayContent) and
setCachedRevision(String(revision)); reference the existing variables
cachedRevision, setCachedRevision, setFileContent, revision and displayContent
and implement the logic inside useEffect in the FileEditor component instead of
in the render body.

In `@webapp/src/dogma/features/file/NewFile.tsx`:
- Line 38: The FILE_PATH_PATTERN currently only anchors the end of the string,
allowing prefixes like "../secret" to match; update the regex used in
NewFile.tsx (symbol FILE_PATH_PATTERN) to enforce full-string validation by
adding a start anchor so the pattern matches the entire input (i.e., change
/[-_.0-9a-zA-Z]*[-_0-9a-zA-Z]+$/ to include a leading ^ to become fully
anchored).

Comment thread webapp/src/dogma/common/components/editor/FileEditor.tsx
Comment thread webapp/src/dogma/common/components/editor/FileEditor.tsx Outdated
Comment thread webapp/src/dogma/common/components/editor/FileEditor.tsx Outdated
Comment thread webapp/src/dogma/features/file/NewFile.tsx Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
client/java/src/main/java/com/linecorp/centraldogma/client/AbstractFileRequest.java (1)

50-77: ⚠️ Potential issue | 🟠 Major

Ensure this breaking API change is documented in release notes and migration guide.

The methods applyTemplate(boolean) and applyTemplate(String) have been replaced with renderTemplate(...). All existing usages in the codebase have been updated, but external consumers will need to update their code when upgrading. Document this breaking change in the release notes and provide a migration guide to help users transition to the new method names.

🧹 Nitpick comments (4)
webapp/src/dogma/features/api/apiSlice.ts (1)

563-602: Consider request-specific DTOs for variable create/update.
VariableDto includes fields that are often server-managed (e.g., creation, possibly id). If those are read-only, a dedicated CreateVariableRequestDto / UpdateVariableRequestDto (omitting read-only fields) reduces validation risk and payload size.

server/src/test/java/com/linecorp/centraldogma/server/internal/api/variable/VariableServiceV1Test.java (2)

39-50: Align MOCK_CREATION with the authenticated user

Using a hardcoded "tester" can drift from the USERNAME used by the auth setup if you later assert creation metadata. Consider deriving it from USERNAME for consistency.

♻️ Suggested tweak
-private static final UserAndTimestamp MOCK_CREATION = new UserAndTimestamp("tester");
+private static final UserAndTimestamp MOCK_CREATION = new UserAndTimestamp(USERNAME);

96-98: Add at least one assertion for creation metadata

All comparisons currently ignore creation, so regressions in server-side creation (user/timestamp) won’t be caught. Consider asserting it in one create/read/update path.

Also applies to: 115-117, 127-129, 138-141, 149-152, 182-185

server/src/test/java/com/linecorp/centraldogma/server/VariableTemplateCrudTest.java (1)

56-56: Omit client-supplied creation metadata in test requests

The service unconditionally overwrites creation with server-managed values (VariableServiceV1.java line 239), making client-supplied creation in tests unnecessary. Remove the UserAndTimestamp import and pass null for the creation parameter in Variable constructors to clarify test intent and avoid duplicating server-side logic.

♻️ Proposed adjustment
-import com.linecorp.centraldogma.server.metadata.UserAndTimestamp;
-        final UserAndTimestamp creation = new UserAndTimestamp("tester");
-        final Variable variable = new Variable(id, type, null, value, creation, null);
+        final Variable variable = new Variable(id, type, null, value, null, null);

@ikhoon ikhoon marked this pull request as ready for review January 30, 2026 08:49
@ikhoon

ikhoon commented Jan 30, 2026

Copy link
Copy Markdown
Contributor Author

Screenshots:
image
image
image
image
image

@jrhee17 jrhee17 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 👍


<FormControl isRequired isInvalid={errors.value != null}>
<FormLabel>
<LabelledIcon icon={variableType === 'STRING' ? CiText : TbJson} text="Value" />

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note) For the record, I'm still unsure why a separate String type is necessary when the UI could map variable name to each json key.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a slight difference in perspective on this. We may need to look at real use cases later, but personally, I don't think JSON encoding in Web UI without IDE assistance is convenient.

To provide a better user experience, I thought offering a STRING, so users can simply enter values in an input box without worrrying about encoding, would be helpful. If we only provide JSON type, users would have to add quotes even for simple value, which could make the UI inconvenient.

@ikhoon ikhoon merged commit 5693150 into line:main Feb 2, 2026
10 of 12 checks passed
@ikhoon ikhoon deleted the variable-ui branch February 2, 2026 09:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants