@@ -103,6 +103,11 @@ const operatingSystems = [
103
103
' amazon-linux-2-x86_64' ,
104
104
]
105
105
106
+ // Update default values
107
+ const defaultServerOS = ' ubuntu-24-lts-x86_64'
108
+ const defaultBunVersion = ' v1.2.3'
109
+
110
+ // Update server types descriptions
106
111
const serverTypes: ServerType [] = [
107
112
{
108
113
value: ' app' ,
@@ -114,11 +119,11 @@ const serverTypes: ServerType[] = [
114
119
value: ' web' ,
115
120
label: ' Web Server' ,
116
121
badges: [' Bun' , ' Nginx' ],
117
- description: ' A secured web server with Nginx and PHP .'
122
+ description: ' A secured web server with Nginx.'
118
123
},
119
124
{
120
125
value: ' worker' ,
121
- label: ' Dedicated Worker Server' ,
126
+ label: ' Worker Server' ,
122
127
badges: [' Bun' ],
123
128
description: ' Connect to your local database / cache server to keep your queued jobs processing quickly.'
124
129
},
@@ -149,7 +154,15 @@ const serverTypes: ServerType[] = [
149
154
]
150
155
151
156
const bunVersions = [
152
- ' v1.0.30' ,
157
+ ' v1.2.3' ,
158
+ ' v1.2.2' ,
159
+ ' v1.2.1' ,
160
+ ' v1.2.0' ,
161
+ ' v1.1.20' ,
162
+ ' v1.1.15' ,
163
+ ' v1.1.10' ,
164
+ ' v1.1.5' ,
165
+ ' v1.1.0' ,
153
166
' v1.0.25' ,
154
167
' v1.0.20' ,
155
168
' v1.0.15' ,
@@ -268,6 +281,14 @@ const hasUnsavedChanges = ref(false)
268
281
const initialWorkerConfig = ref ({ ... workerConfig .value })
269
282
const initialCloudConfig = ref ({ ... cloudConfig .value })
270
283
284
+ // Add edit mode state
285
+ const editMode = ref <Record <string , boolean >>({})
286
+
287
+ // Add toggle edit mode function
288
+ const toggleEditMode = (key : string ) => {
289
+ editMode .value [key ] = ! editMode .value [key ]
290
+ }
291
+
271
292
// Function to update worker specs when size changes
272
293
const updateWorkerSpecs = () => {
273
294
workerConfig .value .specs = workerSizes [workerConfig .value .size ]
@@ -630,15 +651,19 @@ export class StacksInfrastructureStack extends cdk.Stack {
630
651
// Methods
631
652
const addServer = () => {
632
653
const id = Object .keys (cloudConfig .value .servers ).length + 1
633
- cloudConfig .value .servers [` app${id } ` ] = {
654
+ const key = ` app${id } `
655
+ cloudConfig .value .servers [key ] = {
634
656
name: ` app-server-${id } ` ,
635
657
domain: ' stacksjs.org' ,
636
658
region: ' us-east-1' ,
637
659
type: ' app' ,
638
660
size: ' t3.micro' ,
639
661
diskSize: 20 ,
640
- serverOS: ' ubuntu-20-lts-x86_64' ,
662
+ serverOS: defaultServerOS ,
663
+ bunVersion: defaultBunVersion ,
641
664
}
665
+ // Set edit mode for new server
666
+ editMode .value [key ] = true
642
667
}
643
668
644
669
const removeServer = (key : string ) => {
@@ -700,6 +725,11 @@ const saveWorkerConfig = async () => {
700
725
isSaving .value = false
701
726
}
702
727
}
728
+
729
+ // Add field name formatter
730
+ const formatFieldName = (field : string ) => {
731
+ return field .charAt (0 ).toUpperCase () + field .slice (1 )
732
+ }
703
733
</script >
704
734
705
735
<template >
@@ -956,9 +986,26 @@ const saveWorkerConfig = async () => {
956
986
<div
957
987
v-for =" (server, key) in cloudConfig.servers"
958
988
:key =" key"
959
- class =" relative border dark:border-gray-600 rounded-lg p-6 transition-all duration-200 hover:border-blue-200 dark:hover:border-blue-500"
989
+ class =" relative border dark:border-gray-600 rounded-lg p-6 transition-all duration-200"
990
+ :class =" { 'hover:border-blue-200 dark:hover:border-blue-500': editMode[key] }"
960
991
>
961
- <div class =" absolute top-4 right-4" >
992
+ <div class =" absolute top-4 right-4 flex items-center gap-2" >
993
+ <button
994
+ v-if =" !editMode[key]"
995
+ @click =" toggleEditMode(key)"
996
+ class =" inline-flex items-center gap-1 px-2.5 py-1.5 text-sm font-medium text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300 transition-colors duration-200"
997
+ >
998
+ <span class =" i-heroicons-pencil-square w-5 h-5" ></span >
999
+ Edit
1000
+ </button >
1001
+ <button
1002
+ v-else
1003
+ @click =" toggleEditMode(key)"
1004
+ class =" inline-flex items-center gap-1 px-2.5 py-1.5 text-sm font-medium text-green-600 hover:text-green-800 dark:text-green-400 dark:hover:text-green-300 transition-colors duration-200"
1005
+ >
1006
+ <span class =" i-heroicons-check w-5 h-5" ></span >
1007
+ Save
1008
+ </button >
962
1009
<button
963
1010
@click =" removeServer(key)"
964
1011
class =" inline-flex items-center gap-1 px-2.5 py-1.5 text-sm font-medium text-red-600 hover:text-red-800 dark:text-red-400 dark:hover:text-red-300 transition-colors duration-200"
@@ -968,12 +1015,49 @@ const saveWorkerConfig = async () => {
968
1015
</button >
969
1016
</div >
970
1017
1018
+ <!-- Server Header -->
971
1019
<div class =" mb-6" >
972
- <h5 class =" text-lg font-medium text-gray-900 dark:text-gray-100" >{{ server.name }}</h5 >
973
- <p class =" mt-1 text-sm text-gray-500 dark:text-gray-400" >{{ server.domain }}</p >
1020
+ <div class =" flex items-center gap-4 mb-2" >
1021
+ <h5 class =" text-lg font-medium text-gray-900 dark:text-gray-100" >{{ server.name }}</h5 >
1022
+ <div class =" flex flex-wrap gap-2" >
1023
+ <span
1024
+ v-for =" badge in serverTypes.find((t: ServerType) => t.value === server.type)?.badges"
1025
+ :key =" badge"
1026
+ class =" inline-flex items-center px-2 py-1 rounded-md text-xs font-medium bg-blue-100 text-blue-700 dark:bg-blue-900 dark:text-blue-300"
1027
+ >
1028
+ {{ badge }}
1029
+ </span >
1030
+ </div >
1031
+ </div >
1032
+ <div class =" flex items-center gap-2 text-sm text-gray-500 dark:text-gray-400" >
1033
+ <div class =" i-heroicons-link w-4 h-4" ></div >
1034
+ <p >{{ server.domain }}</p >
1035
+ </div >
1036
+ <p class =" mt-2 text-sm text-gray-500 dark:text-gray-400" >
1037
+ {{ serverTypes.find((t: ServerType) => t.value === server.type)?.description }}
1038
+ </p >
974
1039
</div >
975
1040
976
- <div class =" grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3" >
1041
+ <!-- Server Configuration -->
1042
+ <div v-if =" !editMode[key]" class =" mt-4" >
1043
+ <div class =" flex items-center gap-2" >
1044
+ <div class =" i-heroicons-server w-4 h-4 text-gray-400" ></div >
1045
+ <span class =" text-sm text-gray-900 dark:text-gray-100" >
1046
+ {{ (workerSizes[server.size as keyof typeof workerSizes].ram / 1024).toFixed(0) }}GB RAM ({{ server.size }})
1047
+ </span >
1048
+ <span class =" text-sm text-gray-500 dark:text-gray-400" >•</span >
1049
+ <span class =" text-sm text-gray-900 dark:text-gray-100" >
1050
+ {{ workerSizes[server.size as keyof typeof workerSizes].vcpu }} vCPUs
1051
+ </span >
1052
+ <span class =" text-sm text-gray-500 dark:text-gray-400" >•</span >
1053
+ <span class =" text-sm text-gray-900 dark:text-gray-100" >
1054
+ 64-bit {{ server.size.includes('g.') ? 'ARM' : 'x86' }}
1055
+ </span >
1056
+ </div >
1057
+ </div >
1058
+
1059
+ <!-- Edit Form -->
1060
+ <div v-else class =" grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3" >
977
1061
<div >
978
1062
<label class =" block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1" >Name</label >
979
1063
<input
@@ -982,7 +1066,6 @@ const saveWorkerConfig = async () => {
982
1066
class =" block w-full h-10 text-sm border-0 rounded-md bg-gray-50 dark:bg-blue-gray-600 py-2 px-3 text-gray-900 dark:text-gray-100 ring-1 ring-inset ring-gray-300 dark:ring-gray-600 focus:ring-2 focus:ring-blue-600 transition-colors duration-200"
983
1067
>
984
1068
</div >
985
-
986
1069
<div >
987
1070
<label class =" block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1" >Domain</label >
988
1071
<input
@@ -991,7 +1074,6 @@ const saveWorkerConfig = async () => {
991
1074
class =" block w-full h-10 text-sm border-0 rounded-md bg-gray-50 dark:bg-blue-gray-600 py-2 px-3 text-gray-900 dark:text-gray-100 ring-1 ring-inset ring-gray-300 dark:ring-gray-600 focus:ring-2 focus:ring-blue-600 transition-colors duration-200"
992
1075
>
993
1076
</div >
994
-
995
1077
<div >
996
1078
<label class =" block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1" >Region</label >
997
1079
<select
@@ -1003,42 +1085,20 @@ const saveWorkerConfig = async () => {
1003
1085
</option >
1004
1086
</select >
1005
1087
</div >
1006
-
1007
1088
<div >
1008
1089
<label class =" block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1" >Type</label >
1009
1090
<div class =" relative" >
1010
1091
<select
1011
1092
v-model =" server.type"
1012
- class =" block w-full h-10 text-sm border-0 rounded-md bg-gray-50 dark:bg-blue-gray-600 py-2 pl-3 pr-10 text-gray-900 dark:text-gray-100 ring-1 ring-inset ring-gray-300 dark:ring-gray-600 focus:ring-2 focus:ring-blue-600 transition-colors duration-200"
1093
+ :disabled =" !editMode[key]"
1094
+ class =" block w-full h-10 text-sm border-0 rounded-md bg-gray-50 dark:bg-blue-gray-600 py-2 px-3 text-gray-900 dark:text-gray-100 ring-1 ring-inset ring-gray-300 dark:ring-gray-600 focus:ring-2 focus:ring-blue-600 transition-colors duration-200 disabled:opacity-50 disabled:cursor-not-allowed"
1013
1095
>
1014
1096
<option v-for =" type in serverTypes" :key =" type.value" :value =" type.value" >
1015
1097
{{ type.label }}
1016
1098
</option >
1017
1099
</select >
1018
1100
</div >
1019
- <div v-if =" server.type" class =" mt-2" >
1020
- <div class =" flex flex-wrap gap-2" >
1021
- <span
1022
- v-for =" badge in serverTypes.find((t: ServerType) => t.value === server.type)?.badges"
1023
- :key =" badge"
1024
- class =" inline-flex items-center px-2 py-1 rounded-md text-xs font-medium"
1025
- :class =" {
1026
- 'bg-blue-100 text-blue-700 dark:bg-blue-900 dark:text-blue-300': badge === 'Bun',
1027
- 'bg-green-100 text-green-700 dark:bg-green-900 dark:text-green-300': badge === 'Nginx',
1028
- 'bg-purple-100 text-purple-700 dark:bg-purple-900 dark:text-purple-300': badge === 'Database',
1029
- 'bg-red-100 text-red-700 dark:bg-red-900 dark:text-red-300': badge === 'Redis' || badge === 'Memcached',
1030
- 'bg-yellow-100 text-yellow-700 dark:bg-yellow-900 dark:text-yellow-300': badge === 'Search Engine'
1031
- }"
1032
- >
1033
- {{ badge }}
1034
- </span >
1035
- </div >
1036
- <p class =" mt-1 text-sm text-gray-500 dark:text-gray-400" >
1037
- {{ serverTypes.find((t: ServerType) => t.value === server.type)?.description }}
1038
- </p >
1039
- </div >
1040
1101
</div >
1041
-
1042
1102
<div >
1043
1103
<label class =" block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1" >Bun Version</label >
1044
1104
<select
@@ -1050,7 +1110,6 @@ const saveWorkerConfig = async () => {
1050
1110
</option >
1051
1111
</select >
1052
1112
</div >
1053
-
1054
1113
<div >
1055
1114
<label class =" block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1" >Database</label >
1056
1115
<select
@@ -1064,7 +1123,6 @@ const saveWorkerConfig = async () => {
1064
1123
<option value =" mongodb" >MongoDB</option >
1065
1124
</select >
1066
1125
</div >
1067
-
1068
1126
<div v-if =" server.database" >
1069
1127
<label class =" block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1" >Database Name</label >
1070
1128
<input
@@ -1074,26 +1132,6 @@ const saveWorkerConfig = async () => {
1074
1132
placeholder =" my_database"
1075
1133
>
1076
1134
</div >
1077
-
1078
- <div >
1079
- <label class =" block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1" >Size</label >
1080
- <div class =" relative" >
1081
- <select
1082
- v-model =" server.size"
1083
- class =" block w-full h-10 text-sm border-0 rounded-md bg-gray-50 dark:bg-blue-gray-600 py-2 px-3 text-gray-900 dark:text-gray-100 ring-1 ring-inset ring-gray-300 dark:ring-gray-600 focus:ring-2 focus:ring-blue-600 transition-colors duration-200"
1084
- >
1085
- <option v-for =" size in instanceTypes" :key =" size" :value =" size" >
1086
- {{ (workerSizes[size as keyof typeof workerSizes].ram / 1024).toFixed(0) }}GB RAM ({{ size }}) (64-bit {{ size.includes('g.') ? 'arm' : 'x86' }}) - {{ workerSizes[size as keyof typeof workerSizes].vcpu }} vCPUs
1087
- </option >
1088
- </select >
1089
- <div class =" absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none" >
1090
- <svg xmlns =" http://www.w3.org/2000/svg" fill =" none" viewBox =" 0 0 24 24" stroke-width =" 1.5" stroke =" currentColor" class =" w-5 h-5 text-gray-400" >
1091
- <path stroke-linecap =" round" stroke-linejoin =" round" d =" M8.25 15L12 18.75 15.75 15m-7.5-6L12 5.25 15.75 9" />
1092
- </svg >
1093
- </div >
1094
- </div >
1095
- </div >
1096
-
1097
1135
<div >
1098
1136
<label class =" block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1" >Operating System</label >
1099
1137
<select
@@ -1105,7 +1143,6 @@ const saveWorkerConfig = async () => {
1105
1143
</option >
1106
1144
</select >
1107
1145
</div >
1108
-
1109
1146
<div >
1110
1147
<label class =" block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1" >Disk Size (GB)</label >
1111
1148
<input
@@ -1115,7 +1152,6 @@ const saveWorkerConfig = async () => {
1115
1152
class =" block w-full h-10 text-sm border-0 rounded-md bg-gray-50 dark:bg-blue-gray-600 py-2 px-3 text-gray-900 dark:text-gray-100 ring-1 ring-inset ring-gray-300 dark:ring-gray-600 focus:ring-2 focus:ring-blue-600 transition-colors duration-200"
1116
1153
>
1117
1154
</div >
1118
-
1119
1155
<div class =" sm:col-span-2 lg:col-span-3" >
1120
1156
<label class =" block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1" >User Data Script</label >
1121
1157
<textarea
0 commit comments