feat: KeyActions component & general progress

This commit is contained in:
Zack Spear
2023-06-01 20:12:26 -07:00
parent d7829aadd1
commit 52bbcbc984
21 changed files with 428 additions and 180 deletions

View File

@@ -29,7 +29,7 @@ const blacklistedGuid = '154B-00EE-0700-9B50CF819816';
// EBLACKLISTED1
// EBLACKLISTED2
// ENOCONN
const state: string = 'ENOKEYFILE2';
const state: string = 'TRIAL';
const uptime = Date.now() - 60 * 60 * 1000; // 1 hour ago
let expireTime = 0;
@@ -46,8 +46,8 @@ const serverState = {
expireTime,
lanIp: '192.168.0.1',
locale: 'en',
pluginInstalled: true,
registered: false,
pluginInstalled: false,
registered: true,
site: 'http://localhost:4321',
state,
uptime,

22
app.vue
View File

@@ -12,32 +12,52 @@ onBeforeMount(() => {
<client-only>
<div class="flex flex-col gap-6 p-6">
<h2>Vue Components</h2>
<h3>UserProfileCe</h3>
<UserProfileCe :server="serverState" />
<h3>DownloadApiLogsCe</h3>
<DownloadApiLogsCe />
<h3>AuthCe</h3>
<AuthCe />
<h3>KeyActionsCe</h3>
<KeyActionsCe />
<h3>LaunchpadCe</h3>
<LaunchpadCe />
<h3>PluginPromoCe</h3>
<PluginPromoCe />
<h3>WanIpCheckCe</h3>
<WanIpCheckCe />
<h3>CallbackHandlerCe</h3>
<CallbackHandlerCe />
</div>
<div class="flex flex-col gap-6 p-6">
<h2>Web Components</h2>
<h3>UserProfileCe</h3>
<connect-user-profile :server="JSON.stringify(serverState)"></connect-user-profile>
<h3>DownloadApiLogsCe</h3>
<connect-download-api-logs></connect-download-api-logs>
<h3>AuthCe</h3>
<connect-auth></connect-auth>
<h3>KeyActionsCe</h3>
<connect-key-actions></connect-key-actions>
<h3>LaunchpadCe</h3>
<connect-launchpad></connect-launchpad>
<h3>PluginPromoCe</h3>
<connect-plugin-promo></connect-plugin-promo>
<h3>WanIpCheckCe</h3>
<connect-wan-ip-check></connect-wan-ip-check>
<h3>CallbackHandlerCe</h3>
<connect-callback-handler></connect-callback-handler>
</div>
</client-only>
</div>
</template>
<style lang="postcss">
<style lang="postcss" scoped>
h2 {
@apply text-xl font-semibold font-mono;
}
h3 {
@apply text-lg font-semibold font-mono;
}
</style>

View File

@@ -2,6 +2,18 @@
@tailwind components;
@tailwind utilities;
/*
darkTheme
alpha: '#1c1b1b',
beta: '#f2f2f2',
gamma: '#999999',
lightTheme
alpha: '#f2f2f2',
beta: '#1c1b1b',
gamma: '#999999',
*/
body {
--color-alpha: #1c1b1b;
--color-beta: #f2f2f2;
@@ -23,7 +35,7 @@ body {
width: 0;
height: 0;
top: -10px;
right: 37px;
right: 40px;
border-right: 11px solid transparent;
border-bottom: 11px solid var(--color-alpha);
border-left: 11px solid transparent;

View File

@@ -1,12 +1,27 @@
<script lang="ts" setup>
import { storeToRefs } from 'pinia';
import { useServerStore } from '~/store/server';
import 'tailwindcss/tailwind.css';
import '~/assets/main.css';
const { keyActions } = storeToRefs(useServerStore());
</script>
<template>
<div class="text-white font-semibold p-4 bg-orange-400 rounded-lg">
KeyActions.ce
</div>
<template v-if="keyActions">
<component
v-for="action in keyActions" :key="action.name"
:is="action.click ? 'button' : 'a'"
@click="action.click()"
rel="noopener noreferrer"
class="text-white text-14px text-center w-full flex-none flex flex-row items-center justify-center gap-x-8px px-8px py-8px cursor-pointer rounded-md bg-gradient-to-r from-red to-orange hover:from-red/60 hover:to-orange/60 focus:from-red/60 focus:to-orange/60"
target="_blank"
download
>
<component v-if="action.icon" :is="action.icon" class="flex-shrink-0 w-14px" />
{{ action.text }}
</component>
</template>
</template>
<style lang="postcss">

View File

@@ -46,7 +46,7 @@ const installButtonClasses = 'text-white text-14px text-center w-full flex flex-
</script>
<template>
<div class="Promo TopBlip text-beta bg-alpha border-grey-darkest text-center relative z-10 w-full max-w-800px mr-8px p-24px sm:p-32px lg:px-40px shadow-md rounded-lg">
<div class="text-beta bg-alpha border-grey-darkest text-center relative z-10 w-full max-w-800px mr-8px p-24px sm:p-32px lg:px-40px shadow-md rounded-lg">
<h2 class="text-24px font-semibold my-0">
Enhance your Unraid experience with these <span class="inline-flex flex-row items-end gap-x-4px"><br class="hidden sm:block"/>Connect <span><UpcBeta /></span></span> features
</h2>

View File

@@ -24,13 +24,7 @@ const toggleDropdown = useToggle(dropdownOpen);
onClickOutside(dropdown, (_event) => dropdownOpen.value = false);
const serverStore = useServerStore();
const { name, description, lanIp, uptime, expireTime, state } = storeToRefs(serverStore);
const uptimeOrExpiredTime = computed(() => {
return (state.value === 'TRIAL' || state.value === 'EEXPIRED') && expireTime.value && expireTime.value > 0
? expireTime.value
: uptime.value;
});
const { name, description, lanIp } = storeToRefs(serverStore);
/**
* Copy LAN IP on server name click
@@ -72,9 +66,9 @@ onBeforeMount(() => {
</script>
<template>
<div id="UserProfile" class="text-alpha relative z-20 flex flex-col h-full pl-80px rounded">
<div id="UserProfile" class="text-alpha relative z-20 flex flex-col h-full gap-y-4px pl-40px rounded">
<div class="text-gamma text-12px text-right font-semibold leading-normal flex flex-row items-baseline justify-end gap-x-12px">
<UpcUptimeExpire :time="uptimeOrExpiredTime" :state="state" />
<UpcUptimeExpire />
<span>&bull;</span>
<UpcServerState />
</div>

View File

@@ -1,115 +1,18 @@
<script setup lang="ts">
import { storeToRefs } from 'pinia';
import { ArrowRightOnRectangleIcon, ArrowTopRightOnSquareIcon, CogIcon, InformationCircleIcon, UserIcon } from '@heroicons/vue/24/solid';
import { ACCOUNT, CONNECT_DASHBOARD, PLUGIN_SETTINGS } from '~/helpers/urls';
import { useServerStore } from '~/store/server';
import type { ServerStateDataAction } from '~/types/server';
import type { UserProfileLink } from '~/types/userProfile';
const myServersEnv = ref<string>('Staging');
const devEnv = ref<string>('development');
const { pluginInstalled, registered } = storeToRefs(useServerStore());
const serverStore = useServerStore();
const { pluginInstalled, registered, stateData } = storeToRefs(serverStore);
// Intended to hide sign in and sign out from actions v-for in UPC dropdown so we can display them separately
const stateDataKeyActions = computed((): ServerStateDataAction[] | undefined => {
const notAllowed = ['signIn', 'signOut'];
if (!stateData.value.actions) return;
return stateData.value.actions.filter(action => !notAllowed.includes(action.name));
const showLaunchpad = computed(() => {
return pluginInstalled.value && !registered.value;
});
console.log('[registered]', registered.value);
const links = computed(():UserProfileLink[] => {
return [
...(registered.value && pluginInstalled.value
? [
{
emphasize: true,
external: true,
href: CONNECT_DASHBOARD,
icon: ArrowTopRightOnSquareIcon,
text: 'Go to Connect',
title: 'Opens Connect in new tab',
},
{
external: true,
href: ACCOUNT,
icon: ArrowTopRightOnSquareIcon,
text: 'Manage Unraid.net Account',
title: 'Manage Unraid.net Account in new tab',
},
{
href: PLUGIN_SETTINGS,
icon: CogIcon,
text: 'Settings',
title: 'Go to Connect plugin settings',
},
{
click: () => { console.debug('signOut') },
external: true,
icon: ArrowRightOnRectangleIcon,
text: 'Sign Out',
title: 'Sign Out to Unregister your server with Connect',
},
]
: []
),
...(!registered.value && pluginInstalled.value
? [
{
click: () => { console.debug('signIn') },
external: true,
icon: UserIcon,
text: 'Sign In with Unraid.net Account',
title: 'Sign In with Unraid.net Account',
},
]
: []
),
...(!pluginInstalled.value
? [
{
click: () => { console.debug('promo') },
icon: InformationCircleIcon,
text: 'Enhance your Unraid experience with Connect',
title: 'Enhance your Unraid experience with Connect',
},
]
: []
),
];
})
</script>
<template>
<UpcDropdownWrapper class="DropdownWrapper_blip text-beta absolute z-30 top-full right-0 min-w-300px max-w-350px">
<header class="flex flex-row items-start justify-between mt-8px mx-8px">
<h3 class="text-18px leading-none inline-flex flex-row gap-x-8px items-center">
<span class="font-semibold">Connect</span>
<UpcBeta />
<span v-if="myServersEnv" :title="`API • ${myServersEnv}`"></span>
<span v-if="devEnv" :title="`UPC • ${devEnv}`"></span>
</h3>
</header>
<ul class="list-reset flex flex-col gap-y-4px p-0">
<template v-if="stateDataKeyActions">
<li v-for="action in stateDataKeyActions" :key="action.name">
<UpcDropdownItem :item="action" />
</li>
</template>
<li class="m-8px">
<UpcKeyline />
</li>
<template v-if="links">
<li v-for="(link, index) in links" :key="`link_${index}`">
<UpcDropdownItem :item="link" />
</li>
</template>
</ul>
<UpcDropdownWrapper class="DropdownWrapper_blip text-beta absolute z-30 top-full right-0">
<UpcDropdownContent v-if="!showLaunchpad" />
<UpcDropdownLaunchpad v-else />
</UpcDropdownWrapper>
</template>

View File

@@ -0,0 +1,24 @@
<script setup lang="ts">
import { ExclamationTriangleIcon } from '@heroicons/vue/24/solid';
// import { storeToRefs } from 'pinia';
// import { useServerStore } from '~/store/server';
// const { stateData } = storeToRefs(useServerStore());
type ApiOnlineStatus = 'online'|'offline';
const onlineStatus = ref<ApiOnlineStatus>('online');
const apiLoading = ref(false);
</script>
<template>
<li class="mb-8px px-8px flex flex-col items-center">
<template v-if="apiLoading">
<BrandLoading class="w-36px mx-auto" :height="21" />
<span class="text-12px italic opacity-80">{{ 'Loading Connect status…' }}</span>
</template>
<span v-else class="w-full flex flex-row justify-start items-center gap-x-8px">
<ExclamationTriangleIcon v-if="onlineStatus !== 'online'" class="text-red w-16px h-16px" />
<span v-else class="block w-12px h-12px bg-green rounded-full"></span>
<span>{{ onlineStatus !== 'online' ? 'Disconnected' : 'Connected' }}</span>
</span>
</li>
</template>

View File

@@ -0,0 +1,109 @@
<script setup lang="ts">
import { storeToRefs } from 'pinia';
import { ArrowRightOnRectangleIcon, ArrowTopRightOnSquareIcon, CogIcon, InformationCircleIcon, UserIcon } from '@heroicons/vue/24/solid';
import { ACCOUNT, CONNECT_DASHBOARD, PLUGIN_SETTINGS } from '~/helpers/urls';
import { usePromoStore } from '~/store/promo';
import { useServerStore } from '~/store/server';
import type { UserProfileLink } from '~/types/userProfile';
const myServersEnv = ref<string>('Staging');
const devEnv = ref<string>('development');
const promoStore = usePromoStore();
const { keyActions, pluginInstalled, registered, stateData } = storeToRefs(useServerStore());
const links = computed(():UserProfileLink[] => {
return [
...(registered.value && pluginInstalled.value
? [
{
emphasize: true,
external: true,
href: CONNECT_DASHBOARD,
icon: ArrowTopRightOnSquareIcon,
text: 'Go to Connect',
title: 'Opens Connect in new tab',
},
{
external: true,
href: ACCOUNT,
icon: ArrowTopRightOnSquareIcon,
text: 'Manage Unraid.net Account',
title: 'Manage Unraid.net Account in new tab',
},
{
href: PLUGIN_SETTINGS,
icon: CogIcon,
text: 'Settings',
title: 'Go to Connect plugin settings',
},
{
click: () => { console.debug('signOut') },
external: true,
icon: ArrowRightOnRectangleIcon,
text: 'Sign Out',
title: 'Sign Out to Unregister your server with Connect',
},
]
: []
),
...(!registered.value && pluginInstalled.value
? [
{
click: () => { console.debug('signIn') },
external: true,
icon: UserIcon,
text: 'Sign In with Unraid.net Account',
title: 'Sign In with Unraid.net Account',
},
]
: []
),
...(!pluginInstalled.value
? [
{
click: () => { promoStore.show() },
icon: InformationCircleIcon,
text: 'Enhance your Unraid experience with Connect',
title: 'Enhance your Unraid experience with Connect',
},
]
: []
),
];
})
</script>
<template>
<div class="flex flex-col gap-y-8px min-w-300px max-w-350px">
<header class="flex flex-row items-start justify-between mt-8px mx-8px">
<h2 class="text-18px leading-none inline-flex flex-row gap-x-8px items-center">
<span class="font-semibold">Connect</span>
<UpcBeta />
<span v-if="myServersEnv" :title="`API • ${myServersEnv}`"></span>
<span v-if="devEnv" :title="`UPC • ${devEnv}`"></span>
</h2>
</header>
<ul class="list-reset flex flex-col gap-y-4px p-0">
<template v-if="keyActions">
<li v-for="action in keyActions" :key="action.name">
<UpcDropdownItem :item="action" />
</li>
</template>
<li class="m-8px">
<UpcKeyline />
</li>
<UpcDropdownError v-if="stateData.error" />
<UpcDropdownConnectStatus v-else-if="registered && pluginInstalled" />
<template v-if="links">
<li v-for="(link, index) in links" :key="`link_${index}`">
<UpcDropdownItem :item="link" />
</li>
</template>
</ul>
</div>
</template>

View File

@@ -0,0 +1,32 @@
<script setup lang="ts">
import { storeToRefs } from 'pinia';
import { InformationCircleIcon } from '@heroicons/vue/24/solid';
import { useServerStore } from '~/store/server';
import type { UserProfileLink } from '~/types/userProfile';
const { stateData } = storeToRefs(useServerStore());
const links = ref<UserProfileLink[]>([
{
click: () => console.debug('Placeholder Button'),
external: true,
icon: InformationCircleIcon,
text: 'Placeholder Button',
},
{
click: () => console.debug('Support Button'),
external: true,
icon: InformationCircleIcon,
text: 'Support Button',
},
]);
</script>
<template>
<ul v-if="stateData.error" class="list-reset flex flex-col gap-y-4px p-12px -mx-4px bg-red/20">
<h3>{{ stateData.error.heading }}</h3>
<p>{{ stateData.error.message }}</p>
<li v-for="(link, index) in links" :key="`link_${index}`" class="-mx-8px">
<UpcDropdownItem :item="link" />
</li>
</ul>
</template>

View File

@@ -28,7 +28,7 @@ const showExternalIconOnHover = computed(() => props.item?.external && props.ite
}"
>
<span class="leading-snug inline-flex flex-row items-center gap-x-8px">
<component :is="item?.icon" class="flex-shrink-0 fill-current w-16px h-16px" aria-hidden="true" />
<component :is="item?.icon" class="flex-shrink-0 text-current w-16px h-16px" aria-hidden="true" />
{{ item?.text }}
</span>
<ArrowTopRightOnSquareIcon

View File

@@ -0,0 +1,43 @@
<script lang="ts" setup>
import { storeToRefs } from 'pinia';
import { useServerStore } from '~/store/server';
import 'tailwindcss/tailwind.css';
import '~/assets/main.css';
const { expireTime, state, stateData } = storeToRefs(useServerStore());
const showExpireTime = computed(() => {
return (state.value === 'TRIAL' || state.value === 'EEXPIRED') && expireTime.value > 0;
});
</script>
<template>
<div class="flex flex-col gap-y-24px w-full min-w-300px md:min-w-[550px] max-w-4xl mr-8px p-16px md:py-24px md:px-32px lg:px-40px shadow-md rounded-lg">
<header class="text-center">
<h2 class="text-24px font-semibold">Thank you for installing Connect!</h2>
<h3>Sign In to your Unraid.net account to register your server</h3>
<UpcUptimeExpire v-if="showExpireTime" class="opacity-75 mt-12px" />
</header>
<ul class="list-reset flex flex-col gap-y-8px" v-if="stateData.actions">
<li v-for="action in stateData.actions" :key="action.name">
<component
:is="action.click ? 'button' : 'a'"
@click="action.click()"
rel="noopener noreferrer"
class="text-white text-14px text-center w-full flex-none flex flex-row items-center justify-center gap-x-8px px-8px py-8px cursor-pointer rounded-md bg-gradient-to-r from-red to-orange hover:from-red/60 hover:to-orange/60 focus:from-red/60 focus:to-orange/60"
target="_blank"
download
>
<component v-if="action.icon" :is="action.icon" class="flex-shrink-0 w-14px" />
{{ action.text }}
</component>
</li>
</ul>
</div>
</template>
<style lang="postcss">
@tailwind base;
@tailwind components;
@tailwind utilities;
</style>

View File

@@ -0,0 +1,91 @@
<script lang="ts" setup>
import type { UserProfilePromoFeature } from '~/types/userProfile';
import 'tailwindcss/tailwind.css';
import '~/assets/main.css';
const features = ref<UserProfilePromoFeature[]>([
{
title: 'Dynamic Remote Access',
copy: 'Toggle on/off server accessibility with dynamic remote access. Automatically turn on UPnP and open a random WAN port on your router at the click of a button and close off access in seconds.',
},
{
title: 'Manage Your Server Within Connect',
copy: 'Servers equipped with a myunraid.net certificate can be managed directly from within the Connect web UI. Manage multiple servers from your phone, tablet, laptop, or PC in the same browser window.',
},
{
title: 'Deep Linking',
copy: 'The Connect dashboard links to relevant sections of the webgui, allowing quick access to those settings and server sections.',
},
{
title: 'Online Flash Backup',
copy: 'Never ever be left without a backup of your config. If you need to change flash drives, generate a backup from Connect and be up and running in minutes.',
},
{
title: 'Real-time Monitoring',
copy: 'Get an overview of your server\'s state, storage space, apps and VMs status, and more.',
},
{
title: 'Customizable Dashboard Tiles',
copy: 'Set custom server tiles how you like and automatically display your server\'s banner image on your Connect Dashboard.',
},
{
title: 'License Management',
copy: 'Manage your license keys at any time via the My Keys section.',
},
{
title: 'Plus more on the way',
copy: 'All you need is an active internet connection, an Unraid.net account, and the Connect plugin. Get started by installing the plugin.',
},
]);
const installPlugin = (staging = false) => {
return console.debug(staging ? 'dynamix.unraid.net.staging.plg' : 'dynamix.unraid.net.plg');
};
const installButtonClasses = 'text-white text-14px text-center w-full flex flex-row items-center justify-center gap-x-8px px-8px py-8px cursor-pointer rounded-md bg-gradient-to-r from-red to-orange hover:from-red/60 hover:to-orange/60 focus:from-red/60 focus:to-orange/60';
</script>
<template>
<div class="text-center relative z-10 w-full max-w-800px p-24px sm:p-32px lg:px-40px">
<h2 class="text-24px font-semibold my-0">
Enhance your Unraid experience with these <span class="inline-flex flex-row items-end gap-x-4px"><br class="hidden sm:block"/>Connect <span><UpcBeta /></span></span> features
</h2>
<div class="text-12px flex flex-wrap justify-center my-16px">
<UpcPromoFeature
v-for="(feature, index) in features"
:key="index"
:title="feature.title"
:copy="feature.copy"
/>
</div>
<div class="w-full max-w-xs flex flex-col gap-y-8px mx-auto">
<!-- v-if="devEnv" -->
<button @click="installPlugin(true)" :class="installButtonClasses">Install Staging</button>
<button @click="installPlugin()" :class="installButtonClasses">{{ 'Install Connect' }}</button>
<div>
<a
href="https://docs.unraid.net/category/unraid-connect"
class="text-12px tracking-wide inline-block mx-8px opacity-60 hover:opacity-100 focus:opacity-100 underline transition"
target="_blank"
rel="noopener noreferrer"
:title="'Checkout the Connect Documentation'"
>{{ 'Learn More' }}</a>
<button
@click="console.debug('Close Promo')"
class="text-12px tracking-wide inline-block mx-8px opacity-60 hover:opacity-100 focus:opacity-100 underline transition"
:title="'Close Promo'"
>
{{ 'No thanks' }}
</button>
</div>
</div>
</div>
</template>
<style lang="postcss">
@tailwind base;
@tailwind components;
@tailwind utilities;
</style>

View File

@@ -1,10 +0,0 @@
<script setup lang="ts">
</script>
<template>
<div>
<span class="block w-12px h-12px mr-8px bg-green rounded-full"></span>
Connected
</div>
</template>

View File

@@ -51,18 +51,15 @@ const title = computed((): string => {
class="group text-18px hover:text-alpha focus:text-alpha border border-transparent flex flex-row justify-end items-center h-full gap-x-8px outline-none focus:outline-none"
:title="title"
>
<!-- show info icon for non-error of myServersOutOfDate b/c it still allows the API to connect -->
<InformationCircleIcon v-if="pluginOutdated" class="text-red fill-current relative w-24px h-24px" />
<!-- v-else-if="showWarning" -->
<ExclamationTriangleIcon class="text-red fill-current relative w-24px h-24px" />
<span class="flex flex-row items-center gap-x-8px">
{{ text }}
<UpcTriangleDown v-if="registeredAndPluginInstalled" :open="open" />
<span class="leading-none">{{ text }}</span>
<UpcTriangleDown :open="open" />
</span>
<BrandAvatar />
<UpcTriangleDown v-if="!registeredAndPluginInstalled" :open="open" />
</button>
</div>
</template>

View File

@@ -1,4 +1,6 @@
<script setup lang="ts">
import { Bars3Icon, XMarkIcon } from "@heroicons/vue/24/solid";
export interface Props {
open?: boolean;
}
@@ -7,11 +9,6 @@ const props = withDefaults(defineProps<Props>(), {
});
</script>
<template>
<span
class="w-0 h-0 border-t-[4px] border-l-[4px] border-r-[4px] border-t-solid border-t-black border-l-solid border-l-transparent border-r-solid border-r-transparent transition-transform"
:class="{
'-rotate-180': open,
'rotate-0': !open,
}"
/>
<Bars3Icon v-if="!open" class="w-16px" />
<XMarkIcon v-else class="w-16px" />
</template>

View File

@@ -1,31 +1,35 @@
<script setup lang="ts">
import { storeToRefs } from 'pinia';
import dateDiff from '~/helpers/time/dateDiff';
import dateFormat from '~/helpers/time/dateFormat';
import buildStringFromValues from '~/helpers/time/buildTimeString';
import { useServerStore } from '~/store/server';
export interface Props {
time: string;
state: string;
}
const serverStore = useServerStore();
const { uptime, expireTime, state } = storeToRefs(serverStore);
const props = defineProps<Props>();
const uptimeOrExpiredTime = computed(() => {
return (state.value === 'TRIAL' || state.value === 'EEXPIRED') && expireTime.value && expireTime.value > 0
? expireTime.value
: uptime.value;
});
const parsedTime = ref<string>('');
const formattedTime = computed<string>(() => {
return dateFormat(props.time);
return dateFormat((uptimeOrExpiredTime.value).toString());
});
const countUp = computed<boolean>(() => {
return props.state !== 'TRIAL' && props.state === 'EEXPIRED';
return state.value !== 'TRIAL' && state.value === 'EEXPIRED';
})
const output = computed(() => {
if (!countUp.value) {
return {
title: props.state === 'EEXPIRED'
title: state.value === 'EEXPIRED'
? `Trial Key Expired at ${formattedTime.value}`
: `Trial Key Expires at ${formattedTime.value}`,
text: props.state === 'EEXPIRED'
text: state.value === 'EEXPIRED'
? `Trial Key Expired ${parsedTime.value}`
: `Trial Key Expires in ${parsedTime.value}`,
};
@@ -36,7 +40,7 @@ const output = computed(() => {
};
});
const runDiff = () => parsedTime.value = buildStringFromValues(dateDiff(props.time, countUp.value));
const runDiff = () => parsedTime.value = buildStringFromValues(dateDiff((uptimeOrExpiredTime.value).toString(), countUp.value));
let interval: string | number | NodeJS.Timeout | undefined = undefined;
onBeforeMount(() => {

View File

@@ -49,6 +49,10 @@ export default defineNuxtConfig({
name: 'ConnectPluginPromo',
path: '@/components/PluginPromo.ce',
},
{
name: 'ConnectUserProfile',
path: '@/components/UserProfile.ce',
},
{
name: 'ConnectWanIpCheck',
path: '@/components/WanIpCheck.ce',

26
store/promo.ts Normal file
View File

@@ -0,0 +1,26 @@
import { useToggle } from '@vueuse/core';
import { defineStore, createPinia, setActivePinia } from "pinia";
/**
* @see https://stackoverflow.com/questions/73476371/using-pinia-with-vue-js-web-components
* @see https://github.com/vuejs/pinia/discussions/1085
*/
setActivePinia(createPinia());
export const usePromoStore = defineStore('promo', () => {
const visible = ref<boolean>(false);
const hide = () => visible.value = false;
const show = () => visible.value = true;
const toggle = useToggle(visible);
watch(visible, () => {
console.debug('[visible]', visible.value);
});
return {
visible,
hide,
show,
toggle,
};
});

View File

@@ -234,6 +234,17 @@ export const useServerStore = defineStore('server', () => {
};
}
});
const authActionsNames = ['signIn', 'signOut'];
// Extract sign in / out from actions so we can display seperately as needed
const authActions = computed((): ServerStateDataAction | undefined => {
if (!stateData.value.actions) return;
return stateData.value.actions.find(action => authActionsNames.includes(action.name));
});
// Remove sign in / out from actions so we can display them separately
const keyActions = computed((): ServerStateDataAction[] | undefined => {
if (!stateData.value.actions) return;
return stateData.value.actions.filter(action => !authActionsNames.includes(action.name));
});
/**
* Actions
@@ -284,7 +295,9 @@ export const useServerStore = defineStore('server', () => {
uptime,
username,
// getters
authActions,
isRemoteAccess,
keyActions,
pluginOutdated,
server,
stateData,

View File

@@ -1,26 +0,0 @@
import { defineStore, createPinia, setActivePinia } from "pinia";
import { useServerStore } from './server';
/**
* @see https://stackoverflow.com/questions/73476371/using-pinia-with-vue-js-web-components
* @see https://github.com/vuejs/pinia/discussions/1085
*/
setActivePinia(createPinia());
export const useWanIpCheckStore = defineStore('wanIpCheck', () => {
const serverStore = useServerStore();
/**
* State
*/
const wanIp = ref<string | null>(sessionStorage.getItem('unraidConnect_wanIp'));
/**
* Getters
*/
/**
* Actions
*/
return {
// state
// getters
// actions
};
});