From 64643c11aa994867fc4002afab8986ea87311719 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sun, 9 Mar 2025 13:00:22 -0600 Subject: [PATCH] feat(ui): add Docker Compose file editor autocomplete - Implement Docker Compose file autocompletion in CodeMirror - Add comprehensive suggestions for top-level and service-level keys - Include a JSON schema for Docker Compose file validation - Enhance code editor with intelligent YAML editing support --- .../compose/general/compose-file-editor.tsx | 1 + .../dokploy/components/shared/code-editor.tsx | 116 ++ .../components/shared/compose-spec.json | 1078 +++++++++++++++++ apps/dokploy/package.json | 53 +- pnpm-lock.yaml | 31 +- 5 files changed, 1244 insertions(+), 35 deletions(-) create mode 100644 apps/dokploy/components/shared/compose-spec.json diff --git a/apps/dokploy/components/dashboard/compose/general/compose-file-editor.tsx b/apps/dokploy/components/dashboard/compose/general/compose-file-editor.tsx index 72589582..bbcbfd83 100644 --- a/apps/dokploy/components/dashboard/compose/general/compose-file-editor.tsx +++ b/apps/dokploy/components/dashboard/compose/general/compose-file-editor.tsx @@ -97,6 +97,7 @@ export const ComposeFileEditor = ({ composeId }: Props) => {
({ + ...opt, + apply: (view: EditorView, completion: Completion) => { + const insert = `${completion.label}:`; + view.dispatch({ + changes: { + from: view.state.selection.main.from, + to: view.state.selection.main.to, + insert, + }, + selection: { anchor: view.state.selection.main.from + insert.length }, + }); + }, +})); + +const dockerComposeServiceOptions = [ + { + label: "image", + type: "keyword", + info: "Specify the image to start the container from", + }, + { label: "build", type: "keyword", info: "Build configuration" }, + { label: "command", type: "keyword", info: "Override the default command" }, + { label: "container_name", type: "keyword", info: "Custom container name" }, + { + label: "depends_on", + type: "keyword", + info: "Express dependency between services", + }, + { label: "environment", type: "keyword", info: "Add environment variables" }, + { + label: "env_file", + type: "keyword", + info: "Add environment variables from a file", + }, + { + label: "expose", + type: "keyword", + info: "Expose ports without publishing them", + }, + { label: "ports", type: "keyword", info: "Expose ports" }, + { + label: "volumes", + type: "keyword", + info: "Mount host paths or named volumes", + }, + { label: "restart", type: "keyword", info: "Restart policy" }, + { label: "networks", type: "keyword", info: "Networks to join" }, +].map((opt) => ({ + ...opt, + apply: (view: EditorView, completion: Completion) => { + const insert = `${completion.label}:`; + view.dispatch({ + changes: { + from: view.state.selection.main.from, + to: view.state.selection.main.to, + insert, + }, + selection: { anchor: view.state.selection.main.from + insert.length }, + }); + }, +})); + +function dockerComposeComplete( + context: CompletionContext, +): CompletionResult | null { + const word = context.matchBefore(/\w*/); + if (!word) return null; + + if (!word.text && !context.explicit) return null; + + // Check if we're at the root level + const line = context.state.doc.lineAt(context.pos); + const indentation = /^\s*/.exec(line.text)?.[0].length || 0; + + console.log(indentation); + if (indentation === 0) { + return { + from: word.from, + options: dockerComposeServices, + validFor: /^\w*$/, + }; + } + + // If we're inside a service definition + if (indentation === 4) { + return { + from: word.from, + options: dockerComposeServiceOptions, + validFor: /^\w*$/, + }; + } + + return null; +} + interface Props extends ReactCodeMirrorProps { wrapperClassName?: string; disabled?: boolean; @@ -45,6 +156,11 @@ export const CodeEditor = ({ ? StreamLanguage.define(shell) : StreamLanguage.define(properties), props.lineWrapping ? EditorView.lineWrapping : [], + language === "yaml" + ? autocompletion({ + override: [dockerComposeComplete], + }) + : [], ]} {...props} editable={!props.disabled} diff --git a/apps/dokploy/components/shared/compose-spec.json b/apps/dokploy/components/shared/compose-spec.json new file mode 100644 index 00000000..92036daa --- /dev/null +++ b/apps/dokploy/components/shared/compose-spec.json @@ -0,0 +1,1078 @@ +{ + "$schema": "https://json-schema.org/draft/2019-09/schema#", + "id": "compose_spec.json", + "type": "object", + "title": "Compose Specification", + "description": "The Compose file is a YAML file defining a multi-containers based application.", + + "properties": { + "version": { + "type": "string", + "description": "declared for backward compatibility, ignored." + }, + + "name": { + "type": "string", + "description": "define the Compose project name, until user defines one explicitly." + }, + + "include": { + "type": "array", + "items": { + "$ref": "#/definitions/include" + }, + "description": "compose sub-projects to be included." + }, + + "services": { + "id": "#/properties/services", + "type": "object", + "patternProperties": { + "^[a-zA-Z0-9._-]+$": { + "$ref": "#/definitions/service" + } + }, + "additionalProperties": false + }, + + "networks": { + "id": "#/properties/networks", + "type": "object", + "patternProperties": { + "^[a-zA-Z0-9._-]+$": { + "$ref": "#/definitions/network" + } + } + }, + + "volumes": { + "id": "#/properties/volumes", + "type": "object", + "patternProperties": { + "^[a-zA-Z0-9._-]+$": { + "$ref": "#/definitions/volume" + } + }, + "additionalProperties": false + }, + + "secrets": { + "id": "#/properties/secrets", + "type": "object", + "patternProperties": { + "^[a-zA-Z0-9._-]+$": { + "$ref": "#/definitions/secret" + } + }, + "additionalProperties": false + }, + + "configs": { + "id": "#/properties/configs", + "type": "object", + "patternProperties": { + "^[a-zA-Z0-9._-]+$": { + "$ref": "#/definitions/config" + } + }, + "additionalProperties": false + } + }, + + "patternProperties": { "^x-": {} }, + "additionalProperties": false, + + "definitions": { + "service": { + "id": "#/definitions/service", + "type": "object", + + "properties": { + "develop": { "$ref": "#/definitions/development" }, + "deploy": { "$ref": "#/definitions/deployment" }, + "annotations": { "$ref": "#/definitions/list_or_dict" }, + "attach": { "type": ["boolean", "string"] }, + "build": { + "oneOf": [ + { "type": "string" }, + { + "type": "object", + "properties": { + "context": { "type": "string" }, + "dockerfile": { "type": "string" }, + "dockerfile_inline": { "type": "string" }, + "entitlements": { + "type": "array", + "items": { "type": "string" } + }, + "args": { "$ref": "#/definitions/list_or_dict" }, + "ssh": { "$ref": "#/definitions/list_or_dict" }, + "labels": { "$ref": "#/definitions/list_or_dict" }, + "cache_from": { + "type": "array", + "items": { "type": "string" } + }, + "cache_to": { "type": "array", "items": { "type": "string" } }, + "no_cache": { "type": ["boolean", "string"] }, + "additional_contexts": { "$ref": "#/definitions/list_or_dict" }, + "network": { "type": "string" }, + "pull": { "type": ["boolean", "string"] }, + "target": { "type": "string" }, + "shm_size": { "type": ["integer", "string"] }, + "extra_hosts": { "$ref": "#/definitions/extra_hosts" }, + "isolation": { "type": "string" }, + "privileged": { "type": ["boolean", "string"] }, + "secrets": { "$ref": "#/definitions/service_config_or_secret" }, + "tags": { "type": "array", "items": { "type": "string" } }, + "ulimits": { "$ref": "#/definitions/ulimits" }, + "platforms": { "type": "array", "items": { "type": "string" } } + }, + "additionalProperties": false, + "patternProperties": { "^x-": {} } + } + ] + }, + "blkio_config": { + "type": "object", + "properties": { + "device_read_bps": { + "type": "array", + "items": { "$ref": "#/definitions/blkio_limit" } + }, + "device_read_iops": { + "type": "array", + "items": { "$ref": "#/definitions/blkio_limit" } + }, + "device_write_bps": { + "type": "array", + "items": { "$ref": "#/definitions/blkio_limit" } + }, + "device_write_iops": { + "type": "array", + "items": { "$ref": "#/definitions/blkio_limit" } + }, + "weight": { "type": ["integer", "string"] }, + "weight_device": { + "type": "array", + "items": { "$ref": "#/definitions/blkio_weight" } + } + }, + "additionalProperties": false + }, + "cap_add": { + "type": "array", + "items": { "type": "string" }, + "uniqueItems": true + }, + "cap_drop": { + "type": "array", + "items": { "type": "string" }, + "uniqueItems": true + }, + "cgroup": { "type": "string", "enum": ["host", "private"] }, + "cgroup_parent": { "type": "string" }, + "command": { "$ref": "#/definitions/command" }, + "configs": { "$ref": "#/definitions/service_config_or_secret" }, + "container_name": { "type": "string" }, + "cpu_count": { + "oneOf": [{ "type": "string" }, { "type": "integer", "minimum": 0 }] + }, + "cpu_percent": { + "oneOf": [ + { "type": "string" }, + { "type": "integer", "minimum": 0, "maximum": 100 } + ] + }, + "cpu_shares": { "type": ["number", "string"] }, + "cpu_quota": { "type": ["number", "string"] }, + "cpu_period": { "type": ["number", "string"] }, + "cpu_rt_period": { "type": ["number", "string"] }, + "cpu_rt_runtime": { "type": ["number", "string"] }, + "cpus": { "type": ["number", "string"] }, + "cpuset": { "type": "string" }, + "credential_spec": { + "type": "object", + "properties": { + "config": { "type": "string" }, + "file": { "type": "string" }, + "registry": { "type": "string" } + }, + "additionalProperties": false, + "patternProperties": { "^x-": {} } + }, + "depends_on": { + "oneOf": [ + { "$ref": "#/definitions/list_of_strings" }, + { + "type": "object", + "additionalProperties": false, + "patternProperties": { + "^[a-zA-Z0-9._-]+$": { + "type": "object", + "additionalProperties": false, + "patternProperties": { "^x-": {} }, + "properties": { + "restart": { "type": ["boolean", "string"] }, + "required": { + "type": "boolean", + "default": true + }, + "condition": { + "type": "string", + "enum": [ + "service_started", + "service_healthy", + "service_completed_successfully" + ] + } + }, + "required": ["condition"] + } + } + } + ] + }, + "device_cgroup_rules": { "$ref": "#/definitions/list_of_strings" }, + "devices": { + "type": "array", + "items": { + "oneOf": [ + { "type": "string" }, + { + "type": "object", + "required": ["source"], + "properties": { + "source": { "type": "string" }, + "target": { "type": "string" }, + "permissions": { "type": "string" } + }, + "additionalProperties": false, + "patternProperties": { "^x-": {} } + } + ] + } + }, + "dns": { "$ref": "#/definitions/string_or_list" }, + "dns_opt": { + "type": "array", + "items": { "type": "string" }, + "uniqueItems": true + }, + "dns_search": { "$ref": "#/definitions/string_or_list" }, + "domainname": { "type": "string" }, + "entrypoint": { "$ref": "#/definitions/command" }, + "env_file": { "$ref": "#/definitions/env_file" }, + "label_file": { "$ref": "#/definitions/label_file" }, + "environment": { "$ref": "#/definitions/list_or_dict" }, + + "expose": { + "type": "array", + "items": { + "type": ["string", "number"], + "format": "expose" + }, + "uniqueItems": true + }, + "extends": { + "oneOf": [ + { "type": "string" }, + { + "type": "object", + + "properties": { + "service": { "type": "string" }, + "file": { "type": "string" } + }, + "required": ["service"], + "additionalProperties": false + } + ] + }, + "external_links": { + "type": "array", + "items": { "type": "string" }, + "uniqueItems": true + }, + "extra_hosts": { "$ref": "#/definitions/extra_hosts" }, + "gpus": { "$ref": "#/definitions/gpus" }, + "group_add": { + "type": "array", + "items": { + "type": ["string", "number"] + }, + "uniqueItems": true + }, + "healthcheck": { "$ref": "#/definitions/healthcheck" }, + "hostname": { "type": "string" }, + "image": { "type": "string" }, + "init": { "type": ["boolean", "string"] }, + "ipc": { "type": "string" }, + "isolation": { "type": "string" }, + "labels": { "$ref": "#/definitions/list_or_dict" }, + "links": { + "type": "array", + "items": { "type": "string" }, + "uniqueItems": true + }, + "logging": { + "type": "object", + + "properties": { + "driver": { "type": "string" }, + "options": { + "type": "object", + "patternProperties": { + "^.+$": { "type": ["string", "number", "null"] } + } + } + }, + "additionalProperties": false, + "patternProperties": { "^x-": {} } + }, + "mac_address": { "type": "string" }, + "mem_limit": { "type": ["number", "string"] }, + "mem_reservation": { "type": ["string", "integer"] }, + "mem_swappiness": { "type": ["integer", "string"] }, + "memswap_limit": { "type": ["number", "string"] }, + "network_mode": { "type": "string" }, + "networks": { + "oneOf": [ + { "$ref": "#/definitions/list_of_strings" }, + { + "type": "object", + "patternProperties": { + "^[a-zA-Z0-9._-]+$": { + "oneOf": [ + { + "type": "object", + "properties": { + "aliases": { "$ref": "#/definitions/list_of_strings" }, + "ipv4_address": { "type": "string" }, + "ipv6_address": { "type": "string" }, + "link_local_ips": { + "$ref": "#/definitions/list_of_strings" + }, + "mac_address": { "type": "string" }, + "driver_opts": { + "type": "object", + "patternProperties": { + "^.+$": { "type": ["string", "number"] } + } + }, + "priority": { "type": "number" } + }, + "additionalProperties": false, + "patternProperties": { "^x-": {} } + }, + { "type": "null" } + ] + } + }, + "additionalProperties": false + } + ] + }, + "oom_kill_disable": { "type": ["boolean", "string"] }, + "oom_score_adj": { + "oneOf": [ + { "type": "string" }, + { "type": "integer", "minimum": -1000, "maximum": 1000 } + ] + }, + "pid": { "type": ["string", "null"] }, + "pids_limit": { "type": ["number", "string"] }, + "platform": { "type": "string" }, + "ports": { + "type": "array", + "items": { + "oneOf": [ + { "type": "number" }, + { "type": "string" }, + { + "type": "object", + "properties": { + "name": { "type": "string" }, + "mode": { "type": "string" }, + "host_ip": { "type": "string" }, + "target": { "type": ["integer", "string"] }, + "published": { "type": ["string", "integer"] }, + "protocol": { "type": "string" }, + "app_protocol": { "type": "string" } + }, + "additionalProperties": false, + "patternProperties": { "^x-": {} } + } + ] + }, + "uniqueItems": true + }, + "post_start": { + "type": "array", + "items": { "$ref": "#/definitions/service_hook" } + }, + "pre_stop": { + "type": "array", + "items": { "$ref": "#/definitions/service_hook" } + }, + "privileged": { "type": ["boolean", "string"] }, + "profiles": { "$ref": "#/definitions/list_of_strings" }, + "pull_policy": { + "type": "string", + "enum": ["always", "never", "if_not_present", "build", "missing"] + }, + "read_only": { "type": ["boolean", "string"] }, + "restart": { "type": "string" }, + "runtime": { + "type": "string" + }, + "scale": { + "type": ["integer", "string"] + }, + "security_opt": { + "type": "array", + "items": { "type": "string" }, + "uniqueItems": true + }, + "shm_size": { "type": ["number", "string"] }, + "secrets": { "$ref": "#/definitions/service_config_or_secret" }, + "sysctls": { "$ref": "#/definitions/list_or_dict" }, + "stdin_open": { "type": ["boolean", "string"] }, + "stop_grace_period": { "type": "string" }, + "stop_signal": { "type": "string" }, + "storage_opt": { "type": "object" }, + "tmpfs": { "$ref": "#/definitions/string_or_list" }, + "tty": { "type": ["boolean", "string"] }, + "ulimits": { "$ref": "#/definitions/ulimits" }, + "user": { "type": "string" }, + "uts": { "type": "string" }, + "userns_mode": { "type": "string" }, + "volumes": { + "type": "array", + "items": { + "oneOf": [ + { "type": "string" }, + { + "type": "object", + "required": ["type"], + "properties": { + "type": { "type": "string" }, + "source": { "type": "string" }, + "target": { "type": "string" }, + "read_only": { "type": ["boolean", "string"] }, + "consistency": { "type": "string" }, + "bind": { + "type": "object", + "properties": { + "propagation": { "type": "string" }, + "create_host_path": { "type": ["boolean", "string"] }, + "recursive": { + "type": "string", + "enum": ["enabled", "disabled", "writable", "readonly"] + }, + "selinux": { "type": "string", "enum": ["z", "Z"] } + }, + "additionalProperties": false, + "patternProperties": { "^x-": {} } + }, + "volume": { + "type": "object", + "properties": { + "nocopy": { "type": ["boolean", "string"] }, + "subpath": { "type": "string" } + }, + "additionalProperties": false, + "patternProperties": { "^x-": {} } + }, + "tmpfs": { + "type": "object", + "properties": { + "size": { + "oneOf": [ + { "type": "integer", "minimum": 0 }, + { "type": "string" } + ] + }, + "mode": { "type": ["number", "string"] } + }, + "additionalProperties": false, + "patternProperties": { "^x-": {} } + } + }, + "additionalProperties": false, + "patternProperties": { "^x-": {} } + } + ] + }, + "uniqueItems": true + }, + "volumes_from": { + "type": "array", + "items": { "type": "string" }, + "uniqueItems": true + }, + "working_dir": { "type": "string" } + }, + "patternProperties": { "^x-": {} }, + "additionalProperties": false + }, + + "healthcheck": { + "id": "#/definitions/healthcheck", + "type": "object", + "properties": { + "disable": { "type": ["boolean", "string"] }, + "interval": { "type": "string" }, + "retries": { "type": ["number", "string"] }, + "test": { + "oneOf": [ + { "type": "string" }, + { "type": "array", "items": { "type": "string" } } + ] + }, + "timeout": { "type": "string" }, + "start_period": { "type": "string" }, + "start_interval": { "type": "string" } + }, + "additionalProperties": false, + "patternProperties": { "^x-": {} } + }, + "development": { + "id": "#/definitions/development", + "type": ["object", "null"], + "properties": { + "watch": { + "type": "array", + "items": { + "type": "object", + "required": ["path", "action"], + "properties": { + "ignore": { "type": "array", "items": { "type": "string" } }, + "path": { "type": "string" }, + "action": { + "type": "string", + "enum": [ + "rebuild", + "sync", + "restart", + "sync+restart", + "sync+exec" + ] + }, + "target": { "type": "string" }, + "exec": { "$ref": "#/definitions/service_hook" } + }, + "additionalProperties": false, + "patternProperties": { "^x-": {} } + } + } + }, + "additionalProperties": false, + "patternProperties": { "^x-": {} } + }, + "deployment": { + "id": "#/definitions/deployment", + "type": ["object", "null"], + "properties": { + "mode": { "type": "string" }, + "endpoint_mode": { "type": "string" }, + "replicas": { "type": ["integer", "string"] }, + "labels": { "$ref": "#/definitions/list_or_dict" }, + "rollback_config": { + "type": "object", + "properties": { + "parallelism": { "type": ["integer", "string"] }, + "delay": { "type": "string" }, + "failure_action": { "type": "string" }, + "monitor": { "type": "string" }, + "max_failure_ratio": { "type": ["number", "string"] }, + "order": { "type": "string", "enum": ["start-first", "stop-first"] } + }, + "additionalProperties": false, + "patternProperties": { "^x-": {} } + }, + "update_config": { + "type": "object", + "properties": { + "parallelism": { "type": ["integer", "string"] }, + "delay": { "type": "string" }, + "failure_action": { "type": "string" }, + "monitor": { "type": "string" }, + "max_failure_ratio": { "type": ["number", "string"] }, + "order": { "type": "string", "enum": ["start-first", "stop-first"] } + }, + "additionalProperties": false, + "patternProperties": { "^x-": {} } + }, + "resources": { + "type": "object", + "properties": { + "limits": { + "type": "object", + "properties": { + "cpus": { "type": ["number", "string"] }, + "memory": { "type": "string" }, + "pids": { "type": ["integer", "string"] } + }, + "additionalProperties": false, + "patternProperties": { "^x-": {} } + }, + "reservations": { + "type": "object", + "properties": { + "cpus": { "type": ["number", "string"] }, + "memory": { "type": "string" }, + "generic_resources": { + "$ref": "#/definitions/generic_resources" + }, + "devices": { "$ref": "#/definitions/devices" } + }, + "additionalProperties": false, + "patternProperties": { "^x-": {} } + } + }, + "additionalProperties": false, + "patternProperties": { "^x-": {} } + }, + "restart_policy": { + "type": "object", + "properties": { + "condition": { "type": "string" }, + "delay": { "type": "string" }, + "max_attempts": { "type": ["integer", "string"] }, + "window": { "type": "string" } + }, + "additionalProperties": false, + "patternProperties": { "^x-": {} } + }, + "placement": { + "type": "object", + "properties": { + "constraints": { "type": "array", "items": { "type": "string" } }, + "preferences": { + "type": "array", + "items": { + "type": "object", + "properties": { + "spread": { "type": "string" } + }, + "additionalProperties": false, + "patternProperties": { "^x-": {} } + } + }, + "max_replicas_per_node": { "type": ["integer", "string"] } + }, + "additionalProperties": false, + "patternProperties": { "^x-": {} } + } + }, + "additionalProperties": false, + "patternProperties": { "^x-": {} } + }, + + "generic_resources": { + "id": "#/definitions/generic_resources", + "type": "array", + "items": { + "type": "object", + "properties": { + "discrete_resource_spec": { + "type": "object", + "properties": { + "kind": { "type": "string" }, + "value": { "type": ["number", "string"] } + }, + "additionalProperties": false, + "patternProperties": { "^x-": {} } + } + }, + "additionalProperties": false, + "patternProperties": { "^x-": {} } + } + }, + + "devices": { + "id": "#/definitions/devices", + "type": "array", + "items": { + "type": "object", + "properties": { + "capabilities": { "$ref": "#/definitions/list_of_strings" }, + "count": { "type": ["string", "integer"] }, + "device_ids": { "$ref": "#/definitions/list_of_strings" }, + "driver": { "type": "string" }, + "options": { "$ref": "#/definitions/list_or_dict" } + }, + "additionalProperties": false, + "patternProperties": { "^x-": {} }, + "required": ["capabilities"] + } + }, + + "gpus": { + "id": "#/definitions/gpus", + "oneOf": [ + { "type": "string", "enum": ["all"] }, + { + "type": "array", + "items": { + "type": "object", + "properties": { + "capabilities": { "$ref": "#/definitions/list_of_strings" }, + "count": { "type": ["string", "integer"] }, + "device_ids": { "$ref": "#/definitions/list_of_strings" }, + "driver": { "type": "string" }, + "options": { "$ref": "#/definitions/list_or_dict" } + } + }, + "additionalProperties": false, + "patternProperties": { "^x-": {} } + } + ] + }, + + "include": { + "id": "#/definitions/include", + "oneOf": [ + { "type": "string" }, + { + "type": "object", + "properties": { + "path": { "$ref": "#/definitions/string_or_list" }, + "env_file": { "$ref": "#/definitions/string_or_list" }, + "project_directory": { "type": "string" } + }, + "additionalProperties": false + } + ] + }, + + "network": { + "id": "#/definitions/network", + "type": ["object", "null"], + "properties": { + "name": { "type": "string" }, + "driver": { "type": "string" }, + "driver_opts": { + "type": "object", + "patternProperties": { + "^.+$": { "type": ["string", "number"] } + } + }, + "ipam": { + "type": "object", + "properties": { + "driver": { "type": "string" }, + "config": { + "type": "array", + "items": { + "type": "object", + "properties": { + "subnet": { "type": "string" }, + "ip_range": { "type": "string" }, + "gateway": { "type": "string" }, + "aux_addresses": { + "type": "object", + "additionalProperties": false, + "patternProperties": { "^.+$": { "type": "string" } } + } + }, + "additionalProperties": false, + "patternProperties": { "^x-": {} } + } + }, + "options": { + "type": "object", + "additionalProperties": false, + "patternProperties": { "^.+$": { "type": "string" } } + } + }, + "additionalProperties": false, + "patternProperties": { "^x-": {} } + }, + "external": { + "type": ["boolean", "string", "object"], + "properties": { + "name": { + "deprecated": true, + "type": "string" + } + }, + "additionalProperties": false, + "patternProperties": { "^x-": {} } + }, + "internal": { "type": ["boolean", "string"] }, + "enable_ipv4": { "type": ["boolean", "string"] }, + "enable_ipv6": { "type": ["boolean", "string"] }, + "attachable": { "type": ["boolean", "string"] }, + "labels": { "$ref": "#/definitions/list_or_dict" } + }, + "additionalProperties": false, + "patternProperties": { "^x-": {} } + }, + + "volume": { + "id": "#/definitions/volume", + "type": ["object", "null"], + "properties": { + "name": { "type": "string" }, + "driver": { "type": "string" }, + "driver_opts": { + "type": "object", + "patternProperties": { + "^.+$": { "type": ["string", "number"] } + } + }, + "external": { + "type": ["boolean", "string", "object"], + "properties": { + "name": { + "deprecated": true, + "type": "string" + } + }, + "additionalProperties": false, + "patternProperties": { "^x-": {} } + }, + "labels": { "$ref": "#/definitions/list_or_dict" } + }, + "additionalProperties": false, + "patternProperties": { "^x-": {} } + }, + + "secret": { + "id": "#/definitions/secret", + "type": "object", + "properties": { + "name": { "type": "string" }, + "environment": { "type": "string" }, + "file": { "type": "string" }, + "external": { + "type": ["boolean", "string", "object"], + "properties": { + "name": { "type": "string" } + } + }, + "labels": { "$ref": "#/definitions/list_or_dict" }, + "driver": { "type": "string" }, + "driver_opts": { + "type": "object", + "patternProperties": { + "^.+$": { "type": ["string", "number"] } + } + }, + "template_driver": { "type": "string" } + }, + "additionalProperties": false, + "patternProperties": { "^x-": {} } + }, + + "config": { + "id": "#/definitions/config", + "type": "object", + "properties": { + "name": { "type": "string" }, + "content": { "type": "string" }, + "environment": { "type": "string" }, + "file": { "type": "string" }, + "external": { + "type": ["boolean", "string", "object"], + "properties": { + "name": { + "deprecated": true, + "type": "string" + } + } + }, + "labels": { "$ref": "#/definitions/list_or_dict" }, + "template_driver": { "type": "string" } + }, + "additionalProperties": false, + "patternProperties": { "^x-": {} } + }, + + "command": { + "oneOf": [ + { "type": "null" }, + { "type": "string" }, + { "type": "array", "items": { "type": "string" } } + ] + }, + + "service_hook": { + "id": "#/definitions/service_hook", + "type": "object", + "properties": { + "command": { "$ref": "#/definitions/command" }, + "user": { "type": "string" }, + "privileged": { "type": ["boolean", "string"] }, + "working_dir": { "type": "string" }, + "environment": { "$ref": "#/definitions/list_or_dict" } + }, + "additionalProperties": false, + "patternProperties": { "^x-": {} } + }, + + "env_file": { + "oneOf": [ + { "type": "string" }, + { + "type": "array", + "items": { + "oneOf": [ + { "type": "string" }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "string" + }, + "format": { + "type": "string" + }, + "required": { + "type": ["boolean", "string"], + "default": true + } + }, + "required": ["path"] + } + ] + } + } + ] + }, + + "label_file": { + "oneOf": [ + { "type": "string" }, + { + "type": "array", + "items": { "type": "string" } + } + ] + }, + + "string_or_list": { + "oneOf": [ + { "type": "string" }, + { "$ref": "#/definitions/list_of_strings" } + ] + }, + + "list_of_strings": { + "type": "array", + "items": { "type": "string" }, + "uniqueItems": true + }, + + "list_or_dict": { + "oneOf": [ + { + "type": "object", + "patternProperties": { + ".+": { + "type": ["string", "number", "boolean", "null"] + } + }, + "additionalProperties": false + }, + { "type": "array", "items": { "type": "string" }, "uniqueItems": true } + ] + }, + + "extra_hosts": { + "oneOf": [ + { + "type": "object", + "patternProperties": { + ".+": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": false + } + ] + } + }, + "additionalProperties": false + }, + { "type": "array", "items": { "type": "string" }, "uniqueItems": true } + ] + }, + + "blkio_limit": { + "type": "object", + "properties": { + "path": { "type": "string" }, + "rate": { "type": ["integer", "string"] } + }, + "additionalProperties": false + }, + "blkio_weight": { + "type": "object", + "properties": { + "path": { "type": "string" }, + "weight": { "type": ["integer", "string"] } + }, + "additionalProperties": false + }, + "service_config_or_secret": { + "type": "array", + "items": { + "oneOf": [ + { "type": "string" }, + { + "type": "object", + "properties": { + "source": { "type": "string" }, + "target": { "type": "string" }, + "uid": { "type": "string" }, + "gid": { "type": "string" }, + "mode": { "type": ["number", "string"] } + }, + "additionalProperties": false, + "patternProperties": { "^x-": {} } + } + ] + } + }, + "ulimits": { + "type": "object", + "patternProperties": { + "^[a-z]+$": { + "oneOf": [ + { "type": ["integer", "string"] }, + { + "type": "object", + "properties": { + "hard": { "type": ["integer", "string"] }, + "soft": { "type": ["integer", "string"] } + }, + "required": ["soft", "hard"], + "additionalProperties": false, + "patternProperties": { "^x-": {} } + } + ] + } + } + }, + "constraints": { + "service": { + "id": "#/definitions/constraints/service", + "anyOf": [{ "required": ["build"] }, { "required": ["image"] }], + "properties": { + "build": { + "required": ["context"] + } + } + } + } + } +} diff --git a/apps/dokploy/package.json b/apps/dokploy/package.json index 5eab6fa8..7cc9ebf3 100644 --- a/apps/dokploy/package.json +++ b/apps/dokploy/package.json @@ -36,8 +36,6 @@ "test": "vitest --config __test__/vitest.config.ts" }, "dependencies": { - "micromatch": "4.0.8", - "ai": "^4.0.23", "@ai-sdk/anthropic": "^1.0.6", "@ai-sdk/azure": "^1.0.15", "@ai-sdk/cohere": "^1.0.6", @@ -45,20 +43,7 @@ "@ai-sdk/mistral": "^1.0.6", "@ai-sdk/openai": "^1.0.12", "@ai-sdk/openai-compatible": "^0.0.13", - "ollama-ai-provider": "^1.1.0", - "better-auth": "1.2.0", - "bl": "6.0.11", - "rotating-file-stream": "3.2.3", - "qrcode": "^1.5.3", - "otpauth": "^9.2.3", - "hi-base32": "^0.5.1", - "boxen": "^7.1.1", - "@octokit/auth-app": "^6.0.4", - "nodemailer": "6.9.14", - "@react-email/components": "^0.0.21", - "node-os-utils": "1.3.7", - "@lucia-auth/adapter-drizzle": "1.0.7", - "dockerode": "4.0.2", + "@codemirror/autocomplete": "^6.18.6", "@codemirror/lang-json": "^6.0.1", "@codemirror/lang-yaml": "^6.1.1", "@codemirror/language": "^6.10.1", @@ -66,7 +51,10 @@ "@codemirror/view": "6.29.0", "@dokploy/server": "workspace:*", "@dokploy/trpc-openapi": "0.0.4", + "@faker-js/faker": "^8.4.1", "@hookform/resolvers": "^3.9.0", + "@lucia-auth/adapter-drizzle": "1.0.7", + "@octokit/auth-app": "^6.0.4", "@octokit/webhooks": "^13.2.7", "@radix-ui/react-accordion": "1.1.2", "@radix-ui/react-alert-dialog": "^1.0.5", @@ -87,8 +75,10 @@ "@radix-ui/react-tabs": "^1.0.4", "@radix-ui/react-toggle": "^1.0.3", "@radix-ui/react-tooltip": "^1.0.7", + "@react-email/components": "^0.0.21", "@stepperize/react": "4.0.1", "@stripe/stripe-js": "4.8.0", + "@tailwindcss/typography": "0.5.16", "@tanstack/react-query": "^4.36.1", "@tanstack/react-table": "^8.16.0", "@trpc/client": "^10.43.6", @@ -98,10 +88,14 @@ "@uiw/codemirror-theme-github": "^4.22.1", "@uiw/react-codemirror": "^4.22.1", "@xterm/addon-attach": "0.10.0", - "@xterm/xterm": "^5.4.0", "@xterm/addon-clipboard": "0.1.0", + "@xterm/xterm": "^5.4.0", "adm-zip": "^0.5.14", + "ai": "^4.0.23", "bcrypt": "5.1.1", + "better-auth": "1.2.0", + "bl": "6.0.11", + "boxen": "^7.1.1", "bullmq": "5.4.2", "class-variance-authority": "^0.7.0", "clsx": "^2.1.0", @@ -109,10 +103,12 @@ "copy-to-clipboard": "^3.3.3", "copy-webpack-plugin": "^12.0.2", "date-fns": "3.6.0", + "dockerode": "4.0.2", "dotenv": "16.4.5", "drizzle-orm": "^0.39.1", "drizzle-zod": "0.5.1", "fancy-ansi": "^0.1.3", + "hi-base32": "^0.5.1", "i18next": "^23.16.4", "input-otp": "^1.2.4", "js-cookie": "^3.0.5", @@ -120,15 +116,21 @@ "lodash": "4.17.21", "lucia": "^3.0.1", "lucide-react": "^0.469.0", + "micromatch": "4.0.8", "nanoid": "3", "next": "^15.0.1", "next-i18next": "^15.3.1", "next-themes": "^0.2.1", + "node-os-utils": "1.3.7", "node-pty": "1.0.0", "node-schedule": "2.1.1", + "nodemailer": "6.9.14", "octokit": "3.1.2", + "ollama-ai-provider": "^1.1.0", + "otpauth": "^9.2.3", "postgres": "3.4.4", "public-ip": "6.0.2", + "qrcode": "^1.5.3", "react": "18.2.0", "react-confetti-explosion": "2.1.2", "react-day-picker": "8.10.1", @@ -137,6 +139,7 @@ "react-i18next": "^15.1.0", "react-markdown": "^9.0.1", "recharts": "^2.12.7", + "rotating-file-stream": "3.2.3", "slugify": "^1.6.6", "sonner": "^1.5.0", "ssh2": "1.15.0", @@ -150,22 +153,20 @@ "ws": "8.16.0", "xterm-addon-fit": "^0.8.0", "zod": "^3.23.4", - "zod-form-data": "^2.0.2", - "@faker-js/faker": "^8.4.1", - "@tailwindcss/typography": "0.5.16" + "zod-form-data": "^2.0.2" }, "devDependencies": { - "@types/micromatch": "4.0.9", - "@types/qrcode": "^1.5.5", - "@types/nodemailer": "^6.4.15", - "@types/node-os-utils": "1.3.4", "@types/adm-zip": "^0.5.5", "@types/bcrypt": "5.0.2", "@types/js-cookie": "^3.0.6", "@types/js-yaml": "4.0.9", "@types/lodash": "4.17.4", + "@types/micromatch": "4.0.9", "@types/node": "^18.17.0", + "@types/node-os-utils": "1.3.4", "@types/node-schedule": "2.1.6", + "@types/nodemailer": "^6.4.15", + "@types/qrcode": "^1.5.5", "@types/react": "^18.2.37", "@types/react-dom": "^18.2.15", "@types/ssh2": "1.15.1", @@ -196,6 +197,8 @@ ] }, "commitlint": { - "extends": ["@commitlint/config-conventional"] + "extends": [ + "@commitlint/config-conventional" + ] } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8d921aeb..ca809b5c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -118,12 +118,15 @@ importers: '@ai-sdk/openai-compatible': specifier: ^0.0.13 version: 0.0.13(zod@3.23.8) + '@codemirror/autocomplete': + specifier: ^6.18.6 + version: 6.18.6 '@codemirror/lang-json': specifier: ^6.0.1 version: 6.0.1 '@codemirror/lang-yaml': specifier: ^6.1.1 - version: 6.1.1(@codemirror/view@6.29.0) + version: 6.1.1 '@codemirror/language': specifier: ^6.10.1 version: 6.10.2 @@ -246,7 +249,7 @@ importers: version: 4.23.0(@codemirror/language@6.10.2)(@codemirror/state@6.4.1)(@codemirror/view@6.29.0) '@uiw/react-codemirror': specifier: ^4.22.1 - version: 4.23.0(@babel/runtime@7.25.0)(@codemirror/autocomplete@6.17.0(@codemirror/language@6.10.2)(@codemirror/state@6.4.1)(@codemirror/view@6.29.0)(@lezer/common@1.2.1))(@codemirror/language@6.10.2)(@codemirror/lint@6.8.1)(@codemirror/search@6.5.6)(@codemirror/state@6.4.1)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.29.0)(codemirror@6.0.1(@lezer/common@1.2.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + version: 4.23.0(@babel/runtime@7.25.0)(@codemirror/autocomplete@6.18.6)(@codemirror/language@6.10.2)(@codemirror/lint@6.8.1)(@codemirror/search@6.5.6)(@codemirror/state@6.4.1)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.29.0)(codemirror@6.0.1(@lezer/common@1.2.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@xterm/addon-attach': specifier: 0.10.0 version: 0.10.0(@xterm/xterm@5.5.0) @@ -997,6 +1000,9 @@ packages: '@codemirror/view': ^6.0.0 '@lezer/common': ^1.0.0 + '@codemirror/autocomplete@6.18.6': + resolution: {integrity: sha512-PHHBXFomUs5DF+9tCOM/UoW6XQ4R44lLNNhRaW9PKPTU0D7lIjRg3ElxaJnTwsl/oHiR93WSXDBrekhoUGCPtg==} + '@codemirror/commands@6.6.0': resolution: {integrity: sha512-qnY+b7j1UNcTS31Eenuc/5YJB6gQOzkUoNmJQc0rznwqSRpeaWWpjkWy2C/MPTcePpsKJEM26hXrOXl1+nceXg==} @@ -8018,6 +8024,13 @@ snapshots: '@codemirror/view': 6.29.0 '@lezer/common': 1.2.1 + '@codemirror/autocomplete@6.18.6': + dependencies: + '@codemirror/language': 6.10.2 + '@codemirror/state': 6.4.1 + '@codemirror/view': 6.29.0 + '@lezer/common': 1.2.1 + '@codemirror/commands@6.6.0': dependencies: '@codemirror/language': 6.10.2 @@ -8030,16 +8043,14 @@ snapshots: '@codemirror/language': 6.10.2 '@lezer/json': 1.0.2 - '@codemirror/lang-yaml@6.1.1(@codemirror/view@6.29.0)': + '@codemirror/lang-yaml@6.1.1': dependencies: - '@codemirror/autocomplete': 6.17.0(@codemirror/language@6.10.2)(@codemirror/state@6.4.1)(@codemirror/view@6.29.0)(@lezer/common@1.2.1) + '@codemirror/autocomplete': 6.18.6 '@codemirror/language': 6.10.2 '@codemirror/state': 6.4.1 '@lezer/common': 1.2.1 '@lezer/highlight': 1.2.0 '@lezer/yaml': 1.0.3 - transitivePeerDependencies: - - '@codemirror/view' '@codemirror/language@6.10.2': dependencies: @@ -10808,9 +10819,9 @@ snapshots: dependencies: '@types/node': 20.14.10 - '@uiw/codemirror-extensions-basic-setup@4.23.0(@codemirror/autocomplete@6.17.0(@codemirror/language@6.10.2)(@codemirror/state@6.4.1)(@codemirror/view@6.29.0)(@lezer/common@1.2.1))(@codemirror/commands@6.6.0)(@codemirror/language@6.10.2)(@codemirror/lint@6.8.1)(@codemirror/search@6.5.6)(@codemirror/state@6.4.1)(@codemirror/view@6.29.0)': + '@uiw/codemirror-extensions-basic-setup@4.23.0(@codemirror/autocomplete@6.18.6)(@codemirror/commands@6.6.0)(@codemirror/language@6.10.2)(@codemirror/lint@6.8.1)(@codemirror/search@6.5.6)(@codemirror/state@6.4.1)(@codemirror/view@6.29.0)': dependencies: - '@codemirror/autocomplete': 6.17.0(@codemirror/language@6.10.2)(@codemirror/state@6.4.1)(@codemirror/view@6.29.0)(@lezer/common@1.2.1) + '@codemirror/autocomplete': 6.18.6 '@codemirror/commands': 6.6.0 '@codemirror/language': 6.10.2 '@codemirror/lint': 6.8.1 @@ -10832,14 +10843,14 @@ snapshots: '@codemirror/state': 6.4.1 '@codemirror/view': 6.29.0 - '@uiw/react-codemirror@4.23.0(@babel/runtime@7.25.0)(@codemirror/autocomplete@6.17.0(@codemirror/language@6.10.2)(@codemirror/state@6.4.1)(@codemirror/view@6.29.0)(@lezer/common@1.2.1))(@codemirror/language@6.10.2)(@codemirror/lint@6.8.1)(@codemirror/search@6.5.6)(@codemirror/state@6.4.1)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.29.0)(codemirror@6.0.1(@lezer/common@1.2.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@uiw/react-codemirror@4.23.0(@babel/runtime@7.25.0)(@codemirror/autocomplete@6.18.6)(@codemirror/language@6.10.2)(@codemirror/lint@6.8.1)(@codemirror/search@6.5.6)(@codemirror/state@6.4.1)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.29.0)(codemirror@6.0.1(@lezer/common@1.2.1))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.25.0 '@codemirror/commands': 6.6.0 '@codemirror/state': 6.4.1 '@codemirror/theme-one-dark': 6.1.2 '@codemirror/view': 6.29.0 - '@uiw/codemirror-extensions-basic-setup': 4.23.0(@codemirror/autocomplete@6.17.0(@codemirror/language@6.10.2)(@codemirror/state@6.4.1)(@codemirror/view@6.29.0)(@lezer/common@1.2.1))(@codemirror/commands@6.6.0)(@codemirror/language@6.10.2)(@codemirror/lint@6.8.1)(@codemirror/search@6.5.6)(@codemirror/state@6.4.1)(@codemirror/view@6.29.0) + '@uiw/codemirror-extensions-basic-setup': 4.23.0(@codemirror/autocomplete@6.18.6)(@codemirror/commands@6.6.0)(@codemirror/language@6.10.2)(@codemirror/lint@6.8.1)(@codemirror/search@6.5.6)(@codemirror/state@6.4.1)(@codemirror/view@6.29.0) codemirror: 6.0.1(@lezer/common@1.2.1) react: 18.2.0 react-dom: 18.2.0(react@18.2.0)