Skip to content

Commit 18b727a

Browse files
Merge branch 'next' of https://github.com/Geode-solutions/Vease into fix/test_extension
2 parents 07ea67e + 5785010 commit 18b727a

54 files changed

Lines changed: 727 additions & 63 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,5 @@ node_modules/
4242
package-lock.json
4343
# Local Netlify folder
4444
.netlify
45+
46+
extensions

app/components/Extension.vue

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,30 @@ import DragAndDrop from "@ogw_front/components/DragAndDrop";
33
import GlassCard from "@ogw_front/components/GlassCard";
44
import { appMode } from "@ogw_front/utils/local/app_mode";
55
import { importExtensionFile } from "@ogw_front/utils/extension";
6+
import { useAppStore } from "@ogw_front/stores/app";
67
import { useInfraStore } from "@ogw_front/stores/infra";
78
89
import { formatRelativeTime } from "@/utils/format_date";
910
import { useExtensionMetadata } from "@/composables/extension_metadata";
10-
import { useExtensionsStore } from "@vease/stores/extensions";
11+
12+
const { hideHeader } = defineProps({
13+
hideHeader: {
14+
type: Boolean,
15+
default: false,
16+
},
17+
});
1118
1219
const MESSAGE_TIMEOUT = 4000;
1320
14-
const extensionsStore = useExtensionsStore();
21+
const appStore = useAppStore();
1522
const infraStore = useInfraStore();
1623
const loading = ref(false);
1724
const errorMessage = ref("");
1825
const successMessage = ref("");
1926
const showRemoveDialog = ref(false);
2027
const extensionToRemove = ref(undefined);
2128
22-
const loadedExtensions = computed(() => extensionsStore.getLoadedExtensions());
29+
const loadedExtensions = computed(() => appStore.getLoadedExtensions());
2330
2431
const {
2532
getExtensionName,
@@ -63,7 +70,7 @@ async function processFiles(filesToProcess) {
6370
}
6471
6572
function toggleExtensionState(extension) {
66-
extensionsStore.toggleExtension(extension.id);
73+
appStore.toggleExtension(extension.id);
6774
}
6875
6976
function formatDate(dateString) {
@@ -77,7 +84,7 @@ function confirmRemove(extension) {
7784
7885
function removeExtension() {
7986
if (extensionToRemove.value) {
80-
extensionsStore.unloadExtension(extensionToRemove.value.id);
87+
appStore.unloadExtension(extensionToRemove.value.id);
8188
showRemoveDialog.value = false;
8289
extensionToRemove.value = undefined;
8390
}
@@ -86,7 +93,7 @@ function removeExtension() {
8693

8794
<template>
8895
<v-card flat color="transparent" class="d-flex flex-column fill-height" theme="dark">
89-
<div class="pa-4 pb-2">
96+
<div v-if="!hideHeader" class="pa-4 pb-2">
9097
<div class="d-flex align-center mb-1">
9198
<v-icon icon="mdi-puzzle" class="mr-2 text-secondary" size="24"></v-icon>
9299
<h2 class="text-h6 font-weight-bold text-white mb-0">Extensions</h2>
@@ -101,15 +108,15 @@ function removeExtension() {
101108
Feature disabled in cloud mode
102109
</p>
103110
</v-card-text>
104-
<v-card-text v-else class="px-4 pb-4 overflow-y-auto">
111+
<v-card-text v-else class="px-4 pb-4 overflow-y-auto" :class="{ 'pt-4': hideHeader }">
105112
<DragAndDrop
106113
:multiple="true"
107114
accept=".vext"
108115
:loading="loading"
109116
:show-extensions="true"
110117
:fullscreen="false"
111118
:show-overlay="false"
112-
idle-text="Click or Drag & Drop Extension"
119+
idle-text="Click or drag and drop"
113120
drop-text="Drop to Install"
114121
loading-text="Loading Extension..."
115122
@files-selected="processFiles"
@@ -168,6 +175,7 @@ function removeExtension() {
168175
:style="{
169176
transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
170177
opacity: extension.enabled ? 1 : 0.6,
178+
background: 'rgba(0, 0, 0, 0.2)',
171179
}"
172180
>
173181
<v-expansion-panel-title class="pa-3">
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
<script setup>
2+
import GlassCard from "@ogw_front/components/GlassCard";
3+
import MarketplaceDetails from "./MarketplaceDetails.vue";
4+
import MarketplaceSidebar from "./MarketplaceSidebar.vue";
5+
import { useAuth } from "@vease/composables/auth";
6+
import { useExtensions } from "@vease/composables/extensions";
7+
8+
const { allowedExtensions } = useExtensions();
9+
const { user } = useAuth();
10+
11+
const {
12+
data: extensions,
13+
pending,
14+
error: fetchError,
15+
} = await useAsyncData("extensions", () => allowedExtensions(), {
16+
watch: [user],
17+
});
18+
19+
const selectedExtension = ref(undefined);
20+
</script>
21+
22+
<template>
23+
<v-row v-if="user" class="responsive-height-row ma-0 pt-4">
24+
<v-col
25+
cols="12"
26+
md="4"
27+
lg="3"
28+
class="d-flex flex-column pa-0 pr-md-4 pb-4 pb-md-0"
29+
style="min-height: 0"
30+
>
31+
<MarketplaceSidebar
32+
v-model="selectedExtension"
33+
:extensions="extensions || []"
34+
:pending="pending"
35+
:fetch-error="fetchError"
36+
/>
37+
</v-col>
38+
39+
<v-col cols="12" md="8" lg="9" class="d-flex flex-column pa-0 pl-md-2" style="min-height: 0">
40+
<MarketplaceDetails :extension="selectedExtension" />
41+
</v-col>
42+
</v-row>
43+
44+
<v-row v-else class="responsive-height-row ma-0 pt-4 align-center justify-center">
45+
<v-col cols="12" sm="8" md="6" lg="5" class="d-flex justify-center">
46+
<GlassCard
47+
variant="ui"
48+
padding="pa-8"
49+
class="d-flex flex-column align-center text-center border-white border-opacity-10 w-100"
50+
>
51+
<v-sheet
52+
class="mx-auto mb-6 d-flex align-center justify-center"
53+
rounded="circle"
54+
color="rgba(255,255,255,0.05)"
55+
width="96"
56+
height="96"
57+
>
58+
<v-icon icon="mdi-lock-outline" size="48" color="white" class="opacity-80"></v-icon>
59+
</v-sheet>
60+
61+
<h2 class="text-h5 font-weight-bold text-white mb-3">Authentication Required</h2>
62+
63+
<p class="text-body-1 text-white opacity-80 mb-8">
64+
You must be logged in to access the marketplace, browse available extensions, and install
65+
them on your project.
66+
</p>
67+
68+
<v-btn
69+
color="white"
70+
variant="elevated"
71+
prepend-icon="mdi-login"
72+
elevation="4"
73+
rounded="pill"
74+
class="text-none px-8 font-weight-bold text-black"
75+
to="/login"
76+
>
77+
Sign In
78+
</v-btn>
79+
</GlassCard>
80+
</v-col>
81+
</v-row>
82+
</template>
83+
84+
<style scoped>
85+
.responsive-height-row {
86+
min-height: 0;
87+
}
88+
89+
@media (min-width: 960px) {
90+
.responsive-height-row {
91+
height: 100%;
92+
}
93+
}
94+
</style>
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
<script setup>
2+
import GlassCard from "@ogw_front/components/GlassCard";
3+
import { importExtensionFile } from "@ogw_front/utils/extension";
4+
import { useAppStore } from "@ogw_front/stores/app";
5+
6+
import { useExtensions } from "@vease/composables/extensions";
7+
8+
const { extension } = defineProps({
9+
extension: {
10+
type: Object,
11+
default: undefined,
12+
},
13+
});
14+
15+
const MESSAGE_TIMEOUT = 5000;
16+
17+
const { downloadExtension } = useExtensions();
18+
const appStore = useAppStore();
19+
20+
const installing = ref(false);
21+
const installError = ref("");
22+
const installSuccess = ref("");
23+
const installed = computed(() => {
24+
if (!appStore.getExtension(extension.id)) {
25+
return false;
26+
}
27+
return true;
28+
});
29+
console.log({ installed });
30+
31+
async function installSelectedExtension() {
32+
if (!extension) {
33+
return;
34+
}
35+
36+
installError.value = "";
37+
installSuccess.value = "";
38+
installing.value = true;
39+
40+
try {
41+
const file = await downloadExtension(extension.id);
42+
console.log({ file });
43+
await importExtensionFile(file);
44+
installSuccess.value = "Extension installed successfully!";
45+
} catch (error) {
46+
console.error(error);
47+
installError.value = error.message || "Failed to install extension.";
48+
} finally {
49+
installing.value = false;
50+
setTimeout(() => {
51+
installSuccess.value = "";
52+
installError.value = "";
53+
}, MESSAGE_TIMEOUT);
54+
}
55+
}
56+
</script>
57+
<template>
58+
<GlassCard
59+
variant="ui"
60+
padding="pa-0"
61+
class="d-flex flex-column fill-height border-white border-opacity-10 relative overflow-hidden"
62+
style="min-height: 0"
63+
>
64+
<template v-if="extension">
65+
<v-sheet color="rgba(0,0,0,0.2)" class="pa-6 pa-sm-8 border-b border-white border-opacity-10">
66+
<v-sheet
67+
color="transparent"
68+
class="d-flex flex-column flex-sm-row align-center align-sm-start text-center text-sm-left"
69+
>
70+
<v-avatar
71+
color="rgba(255,255,255,0.05)"
72+
size="96"
73+
rounded="xl"
74+
class="mb-4 mb-sm-0 mr-sm-6 border border-white border-opacity-10 shadow-sm glass-icon flex-shrink-0"
75+
>
76+
<v-icon icon="mdi-puzzle" size="48" color="white"></v-icon>
77+
</v-avatar>
78+
79+
<v-sheet color="transparent" class="flex-grow-1 w-100" style="min-width: 0">
80+
<v-sheet
81+
color="transparent"
82+
class="d-flex flex-column flex-sm-row align-center mb-2 justify-center justify-sm-start"
83+
>
84+
<h1
85+
class="text-h5 text-sm-h4 font-weight-bold text-white mb-2 mb-sm-0 mr-sm-4"
86+
style="word-break: break-word"
87+
>
88+
{{ extension.id }}
89+
</h1>
90+
<v-chip size="small" variant="outlined" color="white" class="font-weight-medium">
91+
v{{ extension.version }}
92+
</v-chip>
93+
</v-sheet>
94+
95+
<v-sheet color="transparent" class="text-subtitle-1 text-white opacity-80 mb-4">
96+
Marketplace Extension
97+
</v-sheet>
98+
99+
<v-sheet
100+
color="transparent"
101+
class="d-flex align-center justify-center justify-sm-start ga-3 mt-4"
102+
>
103+
<v-btn
104+
color="white"
105+
variant="elevated"
106+
prepend-icon="mdi-download"
107+
elevation="4"
108+
rounded="pill"
109+
class="text-none px-6 font-weight-bold text-black"
110+
:loading="installing"
111+
@click="installSelectedExtension"
112+
:disabled="installed"
113+
>
114+
<span v-if="installed">Already installed</span>
115+
<span v-else>Install Extension</span>
116+
</v-btn>
117+
</v-sheet>
118+
119+
<v-slide-y-transition>
120+
<v-alert
121+
v-if="installSuccess"
122+
type="success"
123+
density="compact"
124+
variant="tonal"
125+
class="mt-4 text-caption"
126+
>
127+
{{ installSuccess }}
128+
</v-alert>
129+
</v-slide-y-transition>
130+
131+
<v-slide-y-transition>
132+
<v-alert
133+
v-if="installError"
134+
type="error"
135+
density="compact"
136+
variant="tonal"
137+
class="mt-4 text-caption"
138+
>
139+
{{ installError }}
140+
</v-alert>
141+
</v-slide-y-transition>
142+
</v-sheet>
143+
</v-sheet>
144+
</v-sheet>
145+
146+
<v-sheet
147+
color="transparent"
148+
class="flex-grow-1 pa-6 pa-sm-8 overflow-y-auto custom-scrollbar"
149+
>
150+
<h3 class="text-h6 font-weight-semibold text-white mb-4 d-flex align-center">
151+
<v-icon icon="mdi-file-document-outline" class="mr-2" size="24"></v-icon>
152+
Details
153+
</h3>
154+
<v-sheet color="transparent" class="readme-content text-body-1 text-white opacity-80">
155+
<v-sheet
156+
v-if="extension.readme"
157+
color="transparent"
158+
style="white-space: pre-wrap; line-height: 1.6"
159+
>
160+
{{ extension.readme }}
161+
</v-sheet>
162+
<v-sheet v-else color="transparent" class="text-center py-10 opacity-60">
163+
<p>No README provided for this extension.</p>
164+
</v-sheet>
165+
</v-sheet>
166+
</v-sheet>
167+
</template>
168+
169+
<v-sheet
170+
v-else
171+
color="transparent"
172+
class="fill-height d-flex flex-column align-center justify-center text-center pa-6"
173+
>
174+
<v-sheet
175+
class="mx-auto mb-6 d-flex align-center justify-center"
176+
rounded="circle"
177+
color="rgba(255,255,255,0.05)"
178+
width="120"
179+
height="120"
180+
>
181+
<v-icon icon="mdi-storefront-outline" size="64" color="white" class="opacity-80"></v-icon>
182+
</v-sheet>
183+
<h2 class="text-h5 font-weight-medium text-white mb-2">Marketplace</h2>
184+
<p class="text-body-1 text-white opacity-70">
185+
Select an extension from the list to view its details and install it.
186+
</p>
187+
</v-sheet>
188+
</GlassCard>
189+
</template>
190+
191+
<style scoped>
192+
.glass-icon {
193+
backdrop-filter: blur(10px);
194+
}
195+
196+
.custom-scrollbar::-webkit-scrollbar {
197+
width: 8px;
198+
}
199+
.custom-scrollbar::-webkit-scrollbar-track {
200+
background: transparent;
201+
}
202+
.custom-scrollbar::-webkit-scrollbar-thumb {
203+
background: rgba(255, 255, 255, 0.1);
204+
border-radius: 4px;
205+
}
206+
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
207+
background: rgba(255, 255, 255, 0.2);
208+
}
209+
</style>

0 commit comments

Comments
 (0)