Initial rewrite of the apps view

This commit is contained in:
Johannes Zellner
2024-12-29 00:36:48 +01:00
parent a42c7e4735
commit 55e0d734df
6 changed files with 164 additions and 14 deletions

View File

@@ -0,0 +1,129 @@
<template>
<div class="content">
<h1 class="section-header">{{ $t('apps.title') }}</h1>
<div class="grid">
<a v-for="app in apps" :key="app.id" class="item" :href="'https://' + app.fqdn" target="_blank" v-tooltip="app.fqdn">
<img :src="API_ORIGIN + app.iconUrl"/>
<div class="label">{{ app.label || app.subdomain || app.fqdn }}</div>
<a class="config" :href="`#/app/${app.id}/info`"><Icon icon="fa-solid fa-cog" /></a>
</a>
</div>
</div>
</template>
<script>
import { Button, Icon } from 'pankow';
import AppsModel from '../models/AppsModel.js';
const API_ORIGIN = import.meta.env.VITE_API_ORIGIN ? import.meta.env.VITE_API_ORIGIN : window.location.origin;
const accessToken = localStorage.token;
const appsModel = AppsModel.create(API_ORIGIN, accessToken);
export default {
name: 'AppsView',
components: {
Button,
Icon,
},
data() {
return {
API_ORIGIN,
ready: false,
apps: [],
};
},
methods: {
},
async mounted() {
this.apps = await appsModel.list();
console.log(this.apps)
this.ready = true;
}
};
</script>
<style scoped>
.grid {
display: flex;
height: 100%;
width: 100%;
transition: 300ms;
flex-wrap: wrap;
justify-content: start;
align-content: start;
}
.item {
position: relative;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 190px;
height: 180px;
margin: 10px;
overflow: hidden;
border-radius: 10px;
background-color: var(--card-background);
}
.item:focus,
.item:hover {
box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.1);
background-color: var(--pankow-color-background-hover);
text-decoration: none;
}
.item img {
width: 80px;
height: 80px;
}
.label {
font-size: 18px;
font-weight: 100;
margin: 10px;
color: var(--pankow-text-color);
}
.item:focus .label,
.item:hover .label {
text-decoration: none;
color: var(--accent-color);;
}
.config {
position: absolute;
color: var(--pankow-text-color);
font-size: 18px;
cursor: pointer;
width: 50px;
height: 50px;
border-top-right-radius: 10px;
right: 0;
top: 0;
opacity: 0;
display: flex;
justify-content: center;
align-items: center;
}
.config:focus,
.config:hover {
text-decoration: none;
color: var(--accent-color);;
opacity: 1;
}
.item:focus .config,
.item:hover .config {
opacity: 1;
}
</style>

View File

@@ -1,6 +1,7 @@
<template>
<div>
<Notification />
<AppsView v-if="view === VIEWS.APPS" />
<SupportView v-if="view === VIEWS.SUPPORT" />
<VolumesView v-if="view === VIEWS.VOLUMES" />
</div>
@@ -10,10 +11,12 @@
import { Notification } from 'pankow';
import AppsView from './AppsView.vue';
import SupportView from './SupportView.vue';
import VolumesView from './VolumesView.vue';
const VIEWS = {
APPS: 'apps',
SUPPORT: 'support',
VOLUMES: 'volumes',
};
@@ -21,6 +24,7 @@ const VIEWS = {
export default {
name: 'Index',
components: {
AppsView,
Notification,
SupportView,
VolumesView,
@@ -44,7 +48,9 @@ export default {
function onHashChange() {
const view = location.hash.slice(2);
if (view === VIEWS.SUPPORT) {
if (view === VIEWS.APPS) {
that.view = VIEWS.APPS;
} else if (view === VIEWS.SUPPORT) {
that.view = VIEWS.SUPPORT;
} else if (view === VIEWS.VOLUMES) {
that.view = VIEWS.VOLUMES;

View File

@@ -30,7 +30,7 @@
import { Button, InputDialog, TopBar, MainLayout } from 'pankow';
import LogsModel from '../models/LogsModel.js';
import AppModel from '../models/AppModel.js';
import AppsModel from '../models/AppsModel.js';
const API_ORIGIN = import.meta.env.VITE_API_ORIGIN ? import.meta.env.VITE_API_ORIGIN : window.location.origin;
@@ -46,7 +46,7 @@ export default {
return {
accessToken: localStorage.token,
logsModel: null,
appModel: null,
appsModel: null,
busyRestart: false,
showRestart: false,
showFilemanager: false,
@@ -79,7 +79,7 @@ export default {
this.busyRestart = true;
await this.appModel.restart();
await this.appsModel.restart();
this.busyRestart = false;
}
@@ -126,10 +126,10 @@ export default {
this.logsModel = LogsModel.create(API_ORIGIN, this.accessToken, this.type, this.id);
if (this.type === 'app') {
this.appModel = AppModel.create(API_ORIGIN, this.accessToken, this.id);
this.appsModel = AppsModel.create(API_ORIGIN, this.accessToken, this.id);
try {
const app = await this.appModel.get();
const app = await this.appsModel.get();
this.name = `${app.label || app.fqdn} (${app.manifest.title})`;
this.showFilemanager = !!app.manifest.addons.localstorage;
this.showTerminal = app.manifest.id !== 'io.cloudron.builtin.appproxy';

View File

@@ -55,7 +55,7 @@ import { Terminal } from '@xterm/xterm';
import { AttachAddon } from '@xterm/addon-attach';
import { FitAddon } from '@xterm/addon-fit';
import { create } from '../models/AppModel.js';
import AppsModel from '../models/AppsModel.js';
import { createDirectoryModel } from '../models/DirectoryModel.js';
const API_ORIGIN = import.meta.env.VITE_API_ORIGIN ? import.meta.env.VITE_API_ORIGIN : window.location.origin;
@@ -73,7 +73,7 @@ export default {
data() {
return {
accessToken: localStorage.token,
appModel: null,
appsModel: null,
directoryModel: null,
fatalError: false,
busyRestart: false,
@@ -197,7 +197,7 @@ export default {
if (!confirmed) return;
this.busyRestart = true;
await this.appModel.restart();
await this.appsModel.restart();
this.busyRestart = false;
},
async connect(retry = false) {
@@ -269,11 +269,11 @@ export default {
this.id = id;
this.name = id;
this.appModel = create(API_ORIGIN, this.accessToken, this.id);
this.appsModel = AppsModel.create(API_ORIGIN, this.accessToken, this.id);
this.directoryModel = createDirectoryModel(API_ORIGIN, this.accessToken, `apps/${id}`);
try {
const app = await this.appModel.get();
const app = await this.appsModel.get();
this.name = `${app.label || app.fqdn} (${app.manifest.title})`;
this.addons = app.manifest.addons;
this.manifestVersion = app.manifest.manifestVersion;