Skip to content
This repository was archived by the owner on Oct 2, 2023. It is now read-only.
Open
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"dependencies": {
"@aarondewes/vue-slider-component": "^3.2.16",
"@bitcoin-design/bitcoin-icons-vue": "^0.1.9",
"@runcitadel/sdk": "^0.5.0",
"@runcitadel/sdk": "^0.5.1",
"@vue/compat": "^3.2.31",
"bignumber.js": "^9.0.2",
"bootstrap": "^5.1.3",
Expand Down
5 changes: 5 additions & 0 deletions src/components/CardWidget.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
footer-tag="footer"
no-body
class="mb-4 card-custom"
:class="highlighted ? 'highlight' : ''"
>
<div v-if="loading" class="card-custom-loading-bar"></div>
<!-- <template v-slot:header></template> -->
Expand Down Expand Up @@ -92,6 +93,10 @@ const props = defineProps({
type: String,
default: '',
},
highlighted: {
type: Boolean,
default: false,
},
status: {
type: Object as PropType<
| {
Expand Down
219 changes: 219 additions & 0 deletions src/components/ChannelSelector.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
<template>
<b-modal
id="channel-selector-modal"
ref="mainModal"
centered
hide-footer
scrollable
>
<template #modal-header="{close}">
<div class="px-2 px-sm-3 pt-2 d-flex justify-content-between w-100">
<h3>features</h3>
<!-- Emulate built in modal header close button action -->
<a href="#" class="align-self-center" @click.stop.prevent="close">
<svg
width="18"
height="18"
viewBox="0 0 18 18"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M13.6003 4.44197C13.3562 4.19789 12.9605 4.19789 12.7164 4.44197L9.02116 8.1372L5.32596 4.442C5.08188 4.19792 4.68615 4.19792 4.44207 4.442C4.198 4.68607 4.198 5.0818 4.44207 5.32588L8.13728 9.02109L4.44185 12.7165C4.19777 12.9606 4.19777 13.3563 4.44185 13.6004C4.68592 13.8445 5.08165 13.8445 5.32573 13.6004L9.02116 9.90497L12.7166 13.6004C12.9607 13.8445 13.3564 13.8445 13.6005 13.6004C13.8446 13.3563 13.8446 12.9606 13.6005 12.7165L9.90505 9.02109L13.6003 5.32585C13.8444 5.08178 13.8444 4.68605 13.6003 4.44197Z"
fill="#6c757d"
/>
</svg>
</a>
</div>
</template>
<p v-if="!supportedChannels.includes(selected)">
You are currently on this update channel: {{ selected }}. If you choose
another one, you can not go back to your current update channel from the
dashboard.
</p>
<div class="card-grid" :class="columnClass">
<card-widget
:highlighted="selected === 'stable'"
header="Stability: "
:status="{text: 'Most stable', variant: 'success', blink: false}"
title="stable"
sub-title="The most stable features"
>
<div class="px-3 px-lg-4 pb-3 channel-info">
<ul>
<li>All stable features</li>
<li>Stable apps with all security updates</li>
<li>Less bugs</li>
<li>Mostly stable</li>
</ul>
<b-button
v-if="selected !== 'stable'"
variant="primary"
class="channel-button"
@click="selectChannel('stable')"
>Select this channel</b-button
>
<b-button v-else variant="success" disabled class="channel-button"
>Current channel</b-button
>
</div>
</card-widget>
<card-widget
:highlighted="selected === 'beta'"
header="Stability: "
:status="{text: 'Preview', variant: 'primary', blink: false}"
title="beta"
sub-title="Early access to new features"
>
<div class="px-3 px-lg-4 pb-3 channel-info">
<ul>
<li>Latest features</li>
<li>New apps</li>
<li>Earlier app updates</li>
<li>May have more bugs</li>
</ul>
<b-button
v-if="selected !== 'beta'"
variant="primary"
class="channel-button"
@click="selectChannel('beta')"
>Select this channel</b-button
>
<b-button v-else variant="success" disabled class="channel-button"
>Current channel</b-button
>
</div>
</card-widget>
<card-widget
:highlighted="selected === 'core-ln'"
header="Stability: "
:status="{text: 'Experimental', variant: 'warning', blink: false}"
title="core lightning"
sub-title="An alternative Lightning backend"
>
<div class="px-3 px-lg-4 pb-3 channel-info">
<ul>
<li>More Lightning-related features like bolt12</li>
<li>Less available apps</li>
<li>Unstable, bugs will occur</li>
<li>Wallet and channels can not be migrated</li>
</ul>
<b-button
v-if="selected !== 'core-ln'"
variant="primary"
class="channel-button"
@click="selectChannel('core-ln')"
>Select this channel</b-button
>
<b-button v-else variant="success" disabled class="channel-button"
>Current channel</b-button
>
</div>
</card-widget>
</div>
</b-modal>
</template>

<script lang="ts" setup>
import {watch, ref, nextTick, onUpdated} from 'vue';
import CardWidget from './CardWidget.vue';
import useSystemStore from '../store/system';
import useToast from '../utils/toast';
import delay from '../helpers/delay';

const systemStore = useSystemStore();
const toast = useToast();
const supportedChannels = ['stable', 'beta', 'c-lightning'];

const mainModal = ref<null | {show: () => void; hide: () => void}>();
const selected = ref<'stable' | 'beta' | 'core-ln'>('stable');
const props = defineProps({
showModal: {
type: Boolean,
required: true,
},
});

const columnClass = ref('grid-1-column');

const getCorrectSize = () => {
const width = document.querySelector('#channel-selector-modal .modal-content')
?.clientWidth as number;
if (width > 900) {
columnClass.value = 'grid-3-column';
} else if (width > 600) {
columnClass.value = 'grid-2-column';
} else {
columnClass.value = 'grid-1-column';
}
};

watch([props], async () => {
if (props.showModal) {
mainModal.value?.show();
await nextTick();
await nextTick();
getCorrectSize();
window.addEventListener('resize', getCorrectSize);
} else {
mainModal.value?.hide();
window.removeEventListener('resize', getCorrectSize);
}
});

function selectChannel(channel: 'stable' | 'beta' | 'core-ln') {
selected.value = channel;
systemStore.setUpdateChannel(channel);
toast.success(
'Update channel set successfully',
"You'll now receive updates from this channel",
);
delay(3000).then(() => {
// The manager will be rebooting in the background.
window.location.reload();
});
}

systemStore.getUpdateChannel().then(() => {
if (['stable', 'beta', 'core-ln'].includes(systemStore.updateChannel)) {
selected.value = systemStore.updateChannel as 'stable' | 'beta' | 'core-ln';
}
});

onUpdated(() => {
getCorrectSize();
});
</script>
<style lang="scss" scoped>
.card-grid {
display: grid;
}

.grid-1-column {
grid-template-columns: 1fr;
}

.grid-2-column {
grid-template-columns: 1fr 1fr;
}
.grid-3-column {
grid-template-columns: 1fr 1fr 1fr;
}

.channel-button {
width: 100%;
position: absolute;
left: 0;
bottom: 0;
height: 3rem;
border-top-left-radius: 0px;
border-top-right-radius: 0px;
}

.channel-info {
// 3rem for the button and 1 to leave some more space
margin-bottom: 4rem;
}
</style>
11 changes: 11 additions & 0 deletions src/global-styles/custom.scss
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,12 @@ button {
&:hover {
box-shadow: var(--card-shadow-hover);
}
&.highlight {
box-shadow: var(--card-shadow), 0 0 0 3px var(--bs-primary);
&:hover {
box-shadow: var(--card-shadow-hover), 0 0 0 3px var(--bs-primary);
}
}
border: none !important;
outline: 0 !important;
// Loading bar safari bug https://gist.github.com/ayamflow/b602ab436ac9f05660d9c15190f4fd7b
Expand Down Expand Up @@ -914,3 +920,8 @@ html[data-theme='dark'] {
.btn svg {
width: 24px;
}

.card-grid {
display: grid;
grid-column-gap: 1rem;
}
54 changes: 7 additions & 47 deletions src/store/apps.ts
Original file line number Diff line number Diff line change
@@ -1,50 +1,10 @@
import {defineStore} from 'pinia';
import type {app as appType} from '@runcitadel/sdk';

import useSdkStore from './sdk';

/** A dependency an app could have */
export type Dependency = 'bitcoind' | 'electrum' | 'lnd' | 'c-lightning';
/**
* Defines an app
*/
export type app = {
/** The id of the app, the name as a simple string without spaces */
export type app = appType & {
id: string;
/** A category for the app, used for grouping apps on the dashboard */
category: string;
/** The name of the app */
name: string;
/** The version of the app */
version: string;
/** A One line description of the app (max 50 characters) */
tagline: string;
/** A longer description of the app (50 to 200 words) */
description: string;
/** The person(s) who created the app */
developer?: string;
/** The person(s) who created the app */
developers?: Record<string, string>;
/** The dependencies of the app */
dependencies: (Dependency | Dependency[])[];
/** The url to the app's Git repository */
repo: string | Record<string, string>;
/** The url to the app's support website/chat */
support: string;
/** The port the app's web UI uses */
port: number;
/** A list of links to app promotional images, if no domain is provided, https://runcitadel.github.io/old-apps-gallery/${app.id}/ will be put in front of the path */
gallery: string[];
/** The path of the app the open button should open */
path: string;
/** The app's default password */
defaultPassword: string;
torOnly?: boolean;
/** Automatically added */
hiddenService?: string;
/** Automatically added */
installed?: boolean;
/** Automatically added */
compatible: boolean;
icon?: string;
};

export interface State {
Expand All @@ -70,7 +30,7 @@ export default defineStore('apps', {
async getInstalledApps() {
const {apps} = await this.sdkStore.citadel.manager.apps.list(true);
if (apps) {
this.installed = apps;
this.installed = apps as app[];
}
},
async getAppStore() {
Expand All @@ -82,7 +42,7 @@ export default defineStore('apps', {
this.sdkStore.setJwt(jwt);

if (apps) {
this.store = apps;
this.store = apps as app[];
}
},
async uninstall(appId: string) {
Expand All @@ -91,7 +51,7 @@ export default defineStore('apps', {

const poll = window.setInterval(async () => {
await this.getInstalledApps();
const index = this.installed.findIndex((app) => app.id === appId);
const index = this.installed.findIndex((app) => app?.id === appId);
if (index === -1) {
this.uninstalling.splice(this.uninstalling.indexOf(appId), 1);
window.clearInterval(poll);
Expand All @@ -104,7 +64,7 @@ export default defineStore('apps', {

const poll = window.setInterval(async () => {
await this.getInstalledApps();
const index = this.installed.findIndex((app) => app.id === appId);
const index = this.installed.findIndex((app) => app?.id === appId);
if (index !== -1) {
this.installing.splice(this.installing.indexOf(appId), 1);
window.clearInterval(poll);
Expand Down
5 changes: 2 additions & 3 deletions src/store/system.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,8 @@ export default defineStore('system', {
}
},
async getUpdateChannel() {
const data = await this.sdkStore.citadel.manager.system.getUpdateChannel(
'',
);
const data =
await this.sdkStore.citadel.manager.system.getUpdateChannel();
if (data) {
this.updateChannel = data;
}
Expand Down
Loading