Skip to content

Commit e928a38

Browse files
authored
feat: tooling mounts (#43)
1 parent 4728ebf commit e928a38

2 files changed

Lines changed: 314 additions & 33 deletions

File tree

src/components/MountsControl.vue

Lines changed: 99 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ const newMount = ref({
2929
readonly: false,
3030
});
3131
32+
const editingIndex = ref<number | null>(null);
33+
3234
function addMount() {
3335
if (!newMount.value.source || !newMount.value.target) return;
3436
@@ -40,7 +42,15 @@ function addMount() {
4042
...(newMount.value.readonly ? { readonly: true } : {}),
4143
};
4244
43-
emit("update:mounts", [...props.mounts, mount]);
45+
const updatedMounts = [...props.mounts];
46+
if (editingIndex.value !== null) {
47+
updatedMounts[editingIndex.value] = mount;
48+
editingIndex.value = null;
49+
} else {
50+
updatedMounts.push(mount);
51+
}
52+
53+
emit("update:mounts", updatedMounts);
4454
4555
newMount.value = {
4656
source: "",
@@ -51,15 +61,80 @@ function addMount() {
5161
};
5262
}
5363
54-
function removeMount(index: number) {
64+
function removeMount(index: number, event?: Event) {
65+
if (event) event.stopPropagation();
5566
const updated = [...props.mounts];
5667
updated.splice(index, 1);
68+
if (editingIndex.value === index) editingIndex.value = null;
69+
else if (editingIndex.value !== null && editingIndex.value > index)
70+
editingIndex.value--;
5771
emit("update:mounts", updated.length > 0 ? updated : undefined);
5872
}
5973
74+
function selectMountToEdit(mount: any, index: number) {
75+
editingIndex.value = index;
76+
if (typeof mount === "string") {
77+
const parts = mount.split(",");
78+
const sourcePart = parts.find((p) => p.startsWith("source="));
79+
const targetPart = parts.find((p) => p.startsWith("target="));
80+
const typePart = parts.find((p) => p.startsWith("type="));
81+
const isRO = parts.includes("readonly");
82+
83+
const rawType = typePart ? typePart.split("=")[1] : "bind";
84+
const type = ["bind", "volume"].includes(rawType)
85+
? (rawType as "bind" | "volume")
86+
: ("bind" as const);
87+
88+
newMount.value = {
89+
source: sourcePart ? sourcePart.split("=")[1] : "",
90+
target: targetPart ? targetPart.split("=")[1] : "",
91+
type,
92+
options: parts
93+
.filter((p) => {
94+
const [k] = p.split("=");
95+
return !["source", "target", "type", "readonly"].includes(k);
96+
})
97+
.join(","),
98+
readonly: isRO,
99+
};
100+
} else {
101+
const rawType = (mount as any).type || "bind";
102+
const type = ["bind", "volume"].includes(rawType)
103+
? (rawType as "bind" | "volume")
104+
: ("bind" as const);
105+
106+
newMount.value = {
107+
source: mount.source,
108+
target: mount.target,
109+
type,
110+
options: mount.options || "",
111+
readonly: !!mount.readonly,
112+
};
113+
}
114+
}
115+
60116
function getMountLabel(mount: any) {
61-
if (typeof mount === "string") return mount;
62-
return `${mount.source} ➔ ${mount.target}`;
117+
if (typeof mount !== "string") return `${mount.source} ➔ ${mount.target}`;
118+
119+
const parts = mount.split(",");
120+
const sourcePart = parts.find((p) => p.startsWith("source="));
121+
const targetPart = parts.find((p) => p.startsWith("target="));
122+
123+
if (sourcePart && targetPart) {
124+
return `${sourcePart.split("=")[1]} ➔ ${targetPart.split("=")[1]}`;
125+
}
126+
return mount;
127+
}
128+
129+
function getMountType(mount: any) {
130+
if (typeof mount !== "string") return mount.type;
131+
const typePart = mount.split(",").find((p) => p.startsWith("type="));
132+
return typePart ? typePart.split("=")[1] : "RAW";
133+
}
134+
135+
function isReadonly(mount: any) {
136+
if (typeof mount !== "string") return !!mount.readonly;
137+
return mount.split(",").includes("readonly");
63138
}
64139
</script>
65140

@@ -120,9 +195,14 @@ function getMountLabel(mount: any) {
120195
<div class="flex items-end col-span-2 lg:col-span-1">
121196
<button
122197
@click="addMount"
123-
class="bg-ide-accent text-ide-bg px-3 py-1.5 rounded-sm text-[9px] font-black uppercase tracking-widest hover:bg-white transition-all shadow-lg shadow-ide-accent/10 h-[28px] w-full"
198+
class="text-ide-bg px-3 py-1.5 rounded-sm text-[9px] font-black uppercase tracking-widest hover:bg-white transition-all shadow-lg shadow-ide-accent/10 h-[28px] w-full"
199+
:class="
200+
editingIndex !== null
201+
? 'bg-ide-orange shadow-ide-orange/10'
202+
: 'bg-ide-accent'
203+
"
124204
>
125-
Add
205+
{{ editingIndex !== null ? "Update" : "Add" }}
126206
</button>
127207
</div>
128208
</div>
@@ -131,15 +211,24 @@ function getMountLabel(mount: any) {
131211
<div
132212
v-for="(mount, index) in mounts"
133213
:key="index"
134-
class="flex items-center justify-between p-2 pl-3 bg-ide-activity/30 border border-ide-border/50 rounded group hover:border-ide-accent/30 transition-colors"
214+
role="button"
215+
tabindex="0"
216+
aria-label="Select mount to edit"
217+
@click="selectMountToEdit(mount, index)"
218+
@keydown.enter.space.prevent="selectMountToEdit(mount, index)"
219+
class="flex items-center justify-between p-2 pl-3 bg-ide-activity/30 border border-ide-border/50 rounded group hover:border-ide-accent/30 transition-all cursor-pointer outline-none focus-visible:ring-1 focus-visible:ring-ide-accent"
220+
:class="{
221+
'border-ide-accent/60 bg-ide-accent/5 ring-1 ring-ide-accent/20':
222+
editingIndex === index,
223+
}"
135224
>
136225
<div class="flex flex-col gap-0.5">
137226
<div class="flex items-center gap-2">
138227
<span class="text-[10px] font-mono text-ide-text-bright">{{
139228
getMountLabel(mount)
140229
}}</span>
141230
<span
142-
v-if="typeof mount !== 'string' && mount.readonly"
231+
v-if="isReadonly(mount)"
143232
class="px-1 py-0.5 bg-ide-orange/20 text-ide-orange text-[6px] font-black rounded-sm uppercase tracking-tighter"
144233
>Read Only</span
145234
>
@@ -149,7 +238,7 @@ function getMountLabel(mount: any) {
149238
>
150239
<span
151240
class="text-[7px] font-black uppercase tracking-widest bg-ide-border px-1 rounded-sm"
152-
>{{ typeof mount === "string" ? "RAW" : mount.type }}</span
241+
>{{ getMountType(mount) }}</span
153242
>
154243
<span
155244
v-if="typeof mount !== 'string' && mount.options"
@@ -159,7 +248,7 @@ function getMountLabel(mount: any) {
159248
</div>
160249
</div>
161250
<button
162-
@click="removeMount(index)"
251+
@click="removeMount(index, $event)"
163252
class="p-1.5 text-ide-text-muted hover:text-ide-orange transition-colors"
164253
>
165254
<svg

0 commit comments

Comments
 (0)