Skip to content

Commit a26b4c3

Browse files
committed
feat(ui): enhance Applications Center with data table for modules
1 parent 0ee8854 commit a26b4c3

File tree

1 file changed

+198
-63
lines changed

1 file changed

+198
-63
lines changed

core/ui/src/views/ApplicationsCenter.vue

Lines changed: 198 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,7 @@
1717
:icon="Application20"
1818
@click="showSoftwareCenterCoreApps()"
1919
class="page-toolbar-item"
20-
>{{
21-
$t('applications_center.core_apps')
22-
}}</NsButton
20+
>{{ $t("applications_center.core_apps") }}</NsButton
2321
>
2422
</div>
2523
</cv-column>
@@ -34,7 +32,7 @@
3432
/>
3533
</cv-column>
3634
</cv-row>
37-
{{ modules }}
35+
{{ modules }}
3836
<!-- <cv-row v-if="error.listCoreModules">
3937
<cv-column>
4038
<NsInlineNotification
@@ -122,9 +120,133 @@
122120
</cv-column>
123121
</cv-row> -->
124122

125-
123+
<cv-row>
124+
<cv-column>
125+
<cv-tile light>
126+
<cv-row>
127+
<cv-column>
128+
<NsDataTable
129+
:allRows="modules"
130+
:columns="i18nTableColumns"
131+
:rawColumns="tableColumns"
132+
:sortable="true"
133+
:pageSizes="[10, 25, 50, 100]"
134+
isSearchable
135+
:searchPlaceholder="$t('firewall.search_service_or_port')"
136+
:searchClearLabel="$t('common.clear_search')"
137+
:noSearchResultsLabel="$t('common.no_search_results')"
138+
:noSearchResultsDescription="
139+
$t('common.no_search_results_description')
140+
"
141+
:isLoading="loading.listModules"
142+
:skeletonRows="5"
143+
:isErrorShown="!!error.listModules"
144+
:errorTitle="$t('action.get-firewall-status')"
145+
:errorDescription="error.listModules"
146+
:itemsPerPageLabel="$t('pagination.items_per_page')"
147+
:rangeOfTotalItemsLabel="
148+
$t('pagination.range_of_total_items')
149+
"
150+
:ofTotalPagesLabel="$t('pagination.of_total_pages')"
151+
:backwardText="$t('pagination.previous_page')"
152+
:forwardText="$t('pagination.next_page')"
153+
:pageNumberLabel="$t('pagination.page_number')"
154+
@updatePage="tablePage = $event"
155+
>
156+
<template slot="empty-state">
157+
<NsEmptyState :title="$t('firewall.no_service')">
158+
<template #description>
159+
<div>
160+
{{ $t("firewall.no_service_description") }}
161+
</div>
162+
</template>
163+
</NsEmptyState>
164+
</template>
165+
<template slot="data">
166+
<cv-data-table-row
167+
v-for="(row, rowIndex) in tablePage"
168+
:key="`${rowIndex}`"
169+
:value="`${rowIndex}`"
170+
>
171+
<cv-data-table-cell>
172+
<span>
173+
{{
174+
row.ui_name
175+
? row.ui_name + " (" + row.id + ")"
176+
: row.id
177+
}}
178+
</span>
179+
</cv-data-table-cell>
180+
<cv-data-table-cell>
181+
<img :src="getLogoSrc(row.logo)" :alt="row.module" style="height: 32px; vertical-align: middle; margin-right: 8px;" />
182+
<span>{{ row.module }}</span>
183+
</cv-data-table-cell>
184+
<cv-data-table-cell>
185+
<span>{{ row.node_ui_name ? $t('common.node') + ' ' + row.node + ' (' + row.node_ui_name + ')' : $t('common.node') + ' ' + row.node }}</span>
186+
</cv-data-table-cell>
187+
<cv-data-table-cell>
188+
<span>{{ row.version }}</span>
189+
</cv-data-table-cell>
190+
<cv-data-table-cell class="table-overflow-menu-cell">
191+
<!-- <cv-overflow-menu
192+
flip-menu
193+
class="table-overflow-menu"
194+
:data-test-id="row.localuser + '-menu'"
195+
>
196+
<cv-overflow-menu-item
197+
@click="toggleEditTask(row)"
198+
:data-test-id="row.localuser + '-edit-task'"
199+
>
200+
<NsMenuItem
201+
:icon="Edit20"
202+
:label="$t('tasks.edit')"
203+
/>
204+
</cv-overflow-menu-item>
205+
<cv-overflow-menu-item
206+
v-if="row.remoteusername !== ''"
207+
@click="toggleActionTask(row)"
208+
:data-test-id="row.localuser + '-action-task'"
209+
>
210+
<NsMenuItem
211+
:icon="row.service ? Stop20 : Play20"
212+
:label="
213+
row.service
214+
? $t('tasks.stop')
215+
: $t('tasks.start')
216+
"
217+
/>
218+
</cv-overflow-menu-item>
219+
<cv-overflow-menu-item
220+
v-if="row.remoteusername !== ''"
221+
@click="toggleDeleteTask(row)"
222+
:data-test-id="row.localuser + '-delete-task'"
223+
>
224+
<NsMenuItem
225+
:icon="TrashCan20"
226+
:label="$t('tasks.delete')"
227+
/>
228+
</cv-overflow-menu-item>
229+
<cv-overflow-menu-item
230+
v-if="row.remoteusername !== ''"
231+
@click="toggleInformations(row)"
232+
:data-test-id="row.localuser + '-list-informations'"
233+
>
234+
<NsMenuItem
235+
:icon="Information20"
236+
:label="$t('tasks.informations')"
237+
/>
238+
</cv-overflow-menu-item>
239+
</cv-overflow-menu>-->
240+
</cv-data-table-cell>
241+
</cv-data-table-row>
242+
</template>
243+
</NsDataTable>
244+
</cv-column>
245+
</cv-row>
246+
</cv-tile>
247+
</cv-column>
248+
</cv-row>
126249
</cv-grid>
127-
128250
</div>
129251
</template>
130252

@@ -142,9 +264,7 @@ import { mapState, mapActions } from "vuex";
142264
143265
export default {
144266
name: "SoftwareCenter",
145-
components: {
146-
147-
},
267+
components: {},
148268
mixins: [
149269
IconService,
150270
QueryParamService,
@@ -165,6 +285,8 @@ export default {
165285
view: "all",
166286
},
167287
modules: [],
288+
tableColumns: ["name", "module", "node", "version"],
289+
tablePage: [],
168290
loading: {
169291
listModules: true,
170292
},
@@ -191,6 +313,11 @@ export default {
191313
return app.installed.length;
192314
});
193315
},
316+
i18nTableColumns() {
317+
return this.tableColumns.map((column) => {
318+
return this.$t("firewall." + column);
319+
});
320+
},
194321
// numInstancesToUpdate() {
195322
// let numInstancesToUpdate = 0;
196323
@@ -236,6 +363,13 @@ export default {
236363
},
237364
methods: {
238365
...mapActions(["setUpdateInProgressInStore"]),
366+
getLogoSrc(logoPath) {
367+
// Rewrite backend absolute path to public path
368+
if (logoPath && logoPath.startsWith('/var/lib/nethserver/cluster/ui/apps/')) {
369+
return logoPath.replace('/var/lib/nethserver/cluster/ui/apps/', '/apps/');
370+
}
371+
return logoPath;
372+
},
239373
async listModules() {
240374
this.loading.listModules = true;
241375
this.error.listModules = "";
@@ -303,63 +437,64 @@ export default {
303437
// console.log("modules", this.modules);
304438
// console.log("appUpdates", this.appUpdates);
305439
// function extractModules(data) {
306-
// if (!data || !Array.isArray(data.installed)) {
307-
// return [];
308-
// }
309-
310-
function extractModulesWithUpdates(taskResult) {
311-
if (!taskResult || !Array.isArray(taskResult.output)) return [];
312-
313-
const modules = [];
314-
315-
for (const obj of taskResult.output) {
316-
const disabledReason = obj.disabled_updates_reason || "";
317-
const updates = Array.isArray(obj.updates) ? obj.updates : [];
318-
319-
if (Array.isArray(obj.installed)) {
320-
for (const item of obj.installed) {
321-
// chercher update correspondant par id
322-
const updateEntry = updates.find(u => u.id === item.id);
323-
console.log("item", item);
324-
console.log("updateEntry", updateEntry);
325-
// if found, merge data from updateEntry into item
326-
const source = updateEntry || item;
327-
328-
modules.push({
329-
digest: source.digest || "",
330-
rootfull: source.flags ? source.flags.includes('rootfull') : false,
331-
id: source.id || "",
332-
logo: source.logo || "",
333-
module: source.module || "",
334-
node: source.node || "",
335-
node_ui_name: source.node_ui_name || "",
336-
source: source.source || "",
337-
ui_name: source.ui_name || "",
338-
version: source.version || "",
339-
disabled_updates_reason: disabledReason,
340-
update: source.update || ""
341-
});
342-
}
343-
}
344-
}
345-
346-
// sort by id
347-
modules.sort((a, b) => a.id.localeCompare(b.id));
440+
// if (!data || !Array.isArray(data.installed)) {
441+
// return [];
442+
// }
443+
444+
function extractModulesWithUpdates(taskResult) {
445+
if (!taskResult || !Array.isArray(taskResult.output)) return [];
446+
447+
const modules = [];
448+
449+
for (const obj of taskResult.output) {
450+
const disabledReason = obj.disabled_updates_reason || "";
451+
const updates = Array.isArray(obj.updates) ? obj.updates : [];
452+
453+
if (Array.isArray(obj.installed)) {
454+
for (const item of obj.installed) {
455+
// chercher update correspondant par id
456+
const updateEntry = updates.find((u) => u.id === item.id);
457+
console.log("item", item);
458+
console.log("updateEntry", updateEntry);
459+
// if found, merge data from updateEntry into item
460+
const source = updateEntry || item;
461+
462+
modules.push({
463+
digest: source.digest || "",
464+
rootfull: source.flags
465+
? source.flags.includes("rootfull")
466+
: false,
467+
id: source.id || "",
468+
logo: source.logo || "",
469+
module: source.module || "",
470+
node: source.node || "",
471+
node_ui_name: source.node_ui_name || "",
472+
source: source.source || "",
473+
ui_name: source.ui_name || "",
474+
version: source.version || "",
475+
disabled_updates_reason: disabledReason,
476+
update: source.update || "",
477+
});
478+
}
479+
}
480+
}
348481
349-
return modules;
350-
}
482+
// sort by id
483+
modules.sort((a, b) => a.id.localeCompare(b.id));
351484
352-
this.modules = extractModulesWithUpdates(taskResult);
353-
console.log("extracted modules", this.modules);
354-
// return modules;
355-
// }
356-
// console.log("extracted modules", extractModules(taskResult));
357-
// this.modules = extractModules(taskResult);
358-
// // perform search on browser history navigation (e.g. going back to software center)
359-
// if (this.q.search) {
360-
// this.searchApp(this.q.search);
361-
// }
485+
return modules;
486+
}
362487
488+
this.modules = extractModulesWithUpdates(taskResult);
489+
console.log("extracted modules", this.modules);
490+
// return modules;
491+
// }
492+
// console.log("extracted modules", extractModules(taskResult));
493+
// this.modules = extractModules(taskResult);
494+
// // perform search on browser history navigation (e.g. going back to software center)
495+
// if (this.q.search) {
496+
// this.searchApp(this.q.search);
497+
// }
363498
},
364499
// async listCoreModules() {
365500
// this.error.listCoreModules = "";

0 commit comments

Comments
 (0)