Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .github/workflows/build_devnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,22 @@ name: Build and Push Devnet Image

on:
push:
branches: [develop]
tags: ['v*']
# also allow manual runs
workflow_dispatch:

jobs:
build:
if: github.event_name == 'workflow_dispatch' || startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
permissions:
contents: read

steps:
- name: Checkout source
uses: actions/checkout@v4
with:
ref: ${{ github.sha }}

- uses: docker/setup-qemu-action@v3
- uses: docker/setup-buildx-action@v3
Expand Down Expand Up @@ -42,3 +45,4 @@ jobs:
VERSION=${{ steps.vars.outputs.sha_short }}
tags: |
ratio1/deeploy_ui:devnet

137 changes: 137 additions & 0 deletions .github/workflows/sem_ver.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
name: Semantic Versioning

on:
push:
branches: [ develop ]

permissions:
contents: write

concurrency:
group: semver-${{ github.ref }}
cancel-in-progress: false

env:
VERSION_FILE: package.json

jobs:
release:
# Extra safety: don't run on the bot's own version bump commits (even though [skip ci] should skip already)
if: github.actor != 'github-actions[bot]'
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0 # fetch all history + tags
token: ${{ secrets.PAT_TOKEN }}

- name: Configure git
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"

- name: Fetch tags
run: git fetch --force --tags

# Bootstrap only when there are no semver tags yet
- name: Bootstrap initial tag (only if none exist)
id: bootstrap
shell: bash
run: |
set -euo pipefail

latest="$(git tag -l 'v[0-9]*.[0-9]*.[0-9]*' --sort=-v:refname | head -n1 || true)"
if [[ -n "$latest" ]]; then
echo "bootstrapped=false" >> "$GITHUB_OUTPUT"
exit 0
fi

if [[ ! -f "$VERSION_FILE" ]]; then
echo "VERSION_FILE not found: $VERSION_FILE" >&2
exit 1
fi

detected="$(grep -oE "v?[0-9]+\.[0-9]+\.[0-9]+" "$VERSION_FILE" | head -n1 || true)"
if [[ -z "$detected" ]]; then
echo "No semver found in $VERSION_FILE" >&2
exit 1
fi
[[ "$detected" == v* ]] || detected="v$detected"

echo "No semver tags found. Bootstrapping tag: $detected"
git tag -a "$detected" -m "Bootstrap $detected"
git push origin "$detected"

echo "bootstrapped=true" >> "$GITHUB_OUTPUT"

- name: Calculate next version
if: steps.bootstrap.outputs.bootstrapped != 'true'
id: semver
uses: paulhatch/semantic-version@v5.4.0
with:
tag_prefix: "v"
# Conventional Commits defaults (major if !: or BREAKING CHANGE:, minor if feat:)
major_pattern: "/!:|BREAKING CHANGE:/"
minor_pattern: "/feat:/"
search_commit_body: true
version_format: "${major}.${minor}.${patch}"

- name: Guard (do nothing if tag already exists)
if: steps.bootstrap.outputs.bootstrapped != 'true'
id: guard
shell: bash
run: |
set -euo pipefail
tag="${{ steps.semver.outputs.version_tag }}"
if git show-ref --tags --verify --quiet "refs/tags/$tag"; then
echo "Tag already exists: $tag"
echo "should_release=false" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "should_release=true" >> "$GITHUB_OUTPUT"

- name: Update version file
if: steps.guard.outputs.should_release == 'true'
env:
NEW_TAG: ${{ steps.semver.outputs.version_tag }}
run: |
set -euo pipefail
python - <<'PY'
import json, os
from pathlib import Path

path = Path(os.environ["VERSION_FILE"])
new_tag = os.environ["NEW_TAG"]
# Strip leading 'v' for package.json (uses bare semver)
version = new_tag.lstrip("v")

data = json.loads(path.read_text(encoding="utf-8"))
data["version"] = version
path.write_text(json.dumps(data, indent=2) + "\n", encoding="utf-8")
print(f"Updated {path} -> {version}")
PY

- name: Commit + tag + push
if: steps.guard.outputs.should_release == 'true'
run: |
set -euo pipefail
tag="${{ steps.semver.outputs.version_tag }}"

git add "$VERSION_FILE"
if ! git diff --cached --quiet; then
git commit -m "chore(release): ${tag}"
fi

git tag -a "$tag" -m "Release $tag"

# Push commit (if any) and annotated tags together
git push origin HEAD:develop --follow-tags

- name: Summary
if: steps.bootstrap.outputs.bootstrapped != 'true'
run: |
echo "Previous Version: ${{ steps.semver.outputs.previous_version }}"
echo "New Tag: ${{ steps.semver.outputs.version_tag }}"
echo "Version Type: ${{ steps.semver.outputs.version_type }}"
164 changes: 82 additions & 82 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,84 +1,84 @@
{
"name": "deeploy-dapp",
"private": true,
"type": "module",
"version": "0.1.2",
"scripts": {
"dev": "next dev --turbo --experimental-https",
"dev:logs": "NEXT_DEBUG=1 next dev --turbo --experimental-https",
"build": "next build",
"start": "next start",
"lint": "eslint .",
"add-service": "tsx scripts/add-service.ts",
"validate-services": "tsx scripts/validate-services.ts"
},
"dependencies": {
"@codemirror/autocomplete": "^6.19.0",
"@codemirror/lang-json": "^6.0.2",
"@codemirror/lint": "^6.9.0",
"@heroui/alert": "^2.2.23",
"@heroui/button": "^2.2.23",
"@heroui/checkbox": "^2.3.24",
"@heroui/date-picker": "^2.3.27",
"@heroui/dropdown": "^2.3.23",
"@heroui/form": "^2.1.23",
"@heroui/input": "^2.4.24",
"@heroui/modal": "^2.2.20",
"@heroui/pagination": "^2.2.21",
"@heroui/select": "^2.4.24",
"@heroui/skeleton": "^2.2.15",
"@heroui/slider": "^2.4.20",
"@heroui/spinner": "^2.2.20",
"@heroui/switch": "^2.2.21",
"@heroui/system": "^2.4.22",
"@heroui/tabs": "^2.2.20",
"@heroui/theme": "^2.4.22",
"@hookform/resolvers": "^5.1.1",
"@tanstack/react-query": "^5.80.6",
"@uiw/react-codemirror": "^4.25.2",
"axios": "^1.12.0",
"clsx": "^2.1.1",
"connectkit": "^1.8.2",
"date-fns": "^4.1.0",
"dexie": "^4.0.11",
"dexie-react-hooks": "^1.1.7",
"framer-motion": "^12.23.22",
"lodash": "^4.17.23",
"next": "^16.1.5",
"react": "18.3.1",
"react-dom": "18.3.1",
"react-hook-form": "^7.59.0",
"react-hot-toast": "^2.5.2",
"react-icons": "^5.5.0",
"siwe": "^2.3.2",
"viem": "^2.31.0",
"wagmi": "^2.15.6",
"world-countries": "^5.1.0",
"zod": "^3.25.67"
},
"devDependencies": {
"@eslint/js": "^9.25.0",
"@tailwindcss/postcss": "^4.1.11",
"@types/inquirer": "^9.0.9",
"@types/lodash": "^4.17.17",
"@types/node": "^24.0.0",
"@types/react": "^19.1.2",
"@types/react-dom": "^19.1.2",
"autoprefixer": "^10.4.21",
"eslint": "^9.25.0",
"eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-react-refresh": "^0.4.19",
"globals": "^16.0.0",
"inquirer": "^12.10.0",
"postcss": "^8.5.4",
"prettier": "^3.5.3",
"prettier-plugin-tailwindcss": "^0.6.14",
"tailwindcss": "^4.1.11",
"tsx": "^4.20.6",
"typescript": "~5.8.3",
"typescript-eslint": "^8.30.1"
},
"overrides": {
"h3": "1.15.5"
}
"name": "deeploy-dapp",
"private": true,
"type": "module",
"version": "1.1.5",
"scripts": {
"dev": "next dev --turbo --experimental-https",
"dev:logs": "NEXT_DEBUG=1 next dev --turbo --experimental-https",
"build": "next build",
"start": "next start",
"lint": "eslint .",
"add-service": "tsx scripts/add-service.ts",
"validate-services": "tsx scripts/validate-services.ts"
},
"dependencies": {
"@codemirror/autocomplete": "^6.19.0",
"@codemirror/lang-json": "^6.0.2",
"@codemirror/lint": "^6.9.0",
"@heroui/alert": "^2.2.23",
"@heroui/button": "^2.2.23",
"@heroui/checkbox": "^2.3.24",
"@heroui/date-picker": "^2.3.27",
"@heroui/dropdown": "^2.3.23",
"@heroui/form": "^2.1.23",
"@heroui/input": "^2.4.24",
"@heroui/modal": "^2.2.20",
"@heroui/pagination": "^2.2.21",
"@heroui/select": "^2.4.24",
"@heroui/skeleton": "^2.2.15",
"@heroui/slider": "^2.4.20",
"@heroui/spinner": "^2.2.20",
"@heroui/switch": "^2.2.21",
"@heroui/system": "^2.4.22",
"@heroui/tabs": "^2.2.20",
"@heroui/theme": "^2.4.22",
"@hookform/resolvers": "^5.1.1",
"@tanstack/react-query": "^5.80.6",
"@uiw/react-codemirror": "^4.25.2",
"axios": "^1.12.0",
"clsx": "^2.1.1",
"connectkit": "^1.8.2",
"date-fns": "^4.1.0",
"dexie": "^4.0.11",
"dexie-react-hooks": "^1.1.7",
"framer-motion": "^12.23.22",
"lodash": "^4.17.23",
"next": "^16.1.5",
"react": "18.3.1",
"react-dom": "18.3.1",
"react-hook-form": "^7.59.0",
"react-hot-toast": "^2.5.2",
"react-icons": "^5.5.0",
"siwe": "^2.3.2",
"viem": "^2.31.0",
"wagmi": "^2.15.6",
"world-countries": "^5.1.0",
"zod": "^3.25.67"
},
"devDependencies": {
"@eslint/js": "^9.25.0",
"@tailwindcss/postcss": "^4.1.11",
"@types/inquirer": "^9.0.9",
"@types/lodash": "^4.17.17",
"@types/node": "^24.0.0",
"@types/react": "^19.1.2",
"@types/react-dom": "^19.1.2",
"autoprefixer": "^10.4.21",
"eslint": "^9.25.0",
"eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-react-refresh": "^0.4.19",
"globals": "^16.0.0",
"inquirer": "^12.10.0",
"postcss": "^8.5.4",
"prettier": "^3.5.3",
"prettier-plugin-tailwindcss": "^0.6.14",
"tailwindcss": "^4.1.11",
"tsx": "^4.20.6",
"typescript": "~5.8.3",
"typescript-eslint": "^8.30.1"
},
"overrides": {
"h3": "1.15.5"
}
}
3 changes: 2 additions & 1 deletion src/components/create-job/JobFormWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,8 @@ function JobFormWrapper({ projectName, draftJobsCount }) {
{
basePluginType: BasePluginType.Native,
pluginSignature: PLUGIN_SIGNATURE_TYPES[0],
...getBaseSchemaTunnelingDefaults(),
enableTunneling: BOOLEAN_TYPES[1],
port: '',
customParams: [],
},
],
Expand Down
22 changes: 19 additions & 3 deletions src/components/create-job/plugins/NativeInputsSection.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,38 @@
import ConfigSectionTitle from '@components/job/config/ConfigSectionTitle';
import { PLUGIN_SIGNATURE_TYPES } from '@data/pluginSignatureTypes';
import { BOOLEAN_TYPES } from '@data/booleanTypes';
import { CUSTOM_PLUGIN_SIGNATURE, PLUGIN_SIGNATURE_TYPES } from '@data/pluginSignatureTypes';
import CustomParametersSection from '@shared/jobs/native/CustomParametersSection';
import NativeAppIdentitySection from '@shared/jobs/native/NativeAppIdentitySection';
import PortMappingSection from '@shared/PortMappingSection';
import { useEffect } from 'react';
import { useFormContext } from 'react-hook-form';
import AppParametersSection from '../sections/AppParametersSection';

export default function NativeInputsSection({ name }: { name: string }) {
const { watch } = useFormContext();
const { watch, setValue, clearErrors } = useFormContext();

const pluginSignature: (typeof PLUGIN_SIGNATURE_TYPES)[number] = watch(`${name}.pluginSignature`);

const isCustomSignature = pluginSignature === CUSTOM_PLUGIN_SIGNATURE;

useEffect(() => {
if (!isCustomSignature) {
setValue(`${name}.enableTunneling`, BOOLEAN_TYPES[1]);
setValue(`${name}.tunnelingToken`, undefined);
Comment on lines +20 to +21
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

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

When switching from a custom to a non-custom plugin signature, this effect disables tunneling but only clears errors for tunnelingToken. If the user previously enabled tunneling and triggered a validation error on port (or other tunneling-related fields), that error can remain even though the field is no longer required, because setValue here does not request validation. Consider also clearing/triggering validation for ${name}.port (and any other affected fields) or passing { shouldValidate: true } to the setValue calls so stale errors don’t block submission.

Suggested change
setValue(`${name}.enableTunneling`, BOOLEAN_TYPES[1]);
setValue(`${name}.tunnelingToken`, undefined);
setValue(`${name}.enableTunneling`, BOOLEAN_TYPES[1], { shouldValidate: true });
setValue(`${name}.tunnelingToken`, undefined, { shouldValidate: true });

Copilot uses AI. Check for mistakes.
clearErrors(`${name}.tunnelingToken`);
}
}, [isCustomSignature, name, setValue, clearErrors]);

return (
<div className="col gap-4">
<NativeAppIdentitySection pluginSignature={pluginSignature} baseName={name} />

<ConfigSectionTitle title="App Parameters" />
<AppParametersSection baseName={name} />
<AppParametersSection
baseName={name}
disableTunneling={!isCustomSignature}
tunnelingDisabledNote="Tunneling is disabled by default for the selected plugin signature."
/>

<ConfigSectionTitle title="Port Mapping" />
<PortMappingSection baseName={name} />
Expand Down
Loading