mirror of
https://github.com/unraid/api.git
synced 2026-01-04 07:29:48 -06:00
refactor: apollo client creation + WIP subscriptions
This commit is contained in:
@@ -37,7 +37,7 @@ if (state === 'TRIAL') expireTime = Date.now() + 60 * 60 * 1000; // in 1 hour
|
||||
if (state === 'EEXPIRED') expireTime = uptime; // 1 hour ago
|
||||
|
||||
const serverState = {
|
||||
"apiKey": "XXXunupc_12312313123",
|
||||
"apiKey": "unupc_fab6ff6ffe51040595c6d9ffb63a353ba16cc2ad7d93f813a2e80a5810",
|
||||
"avatar": "https://source.unsplash.com/300x300/?portrait",
|
||||
"config": {
|
||||
// error: 'INVALID',
|
||||
|
||||
@@ -66,12 +66,8 @@ onBeforeMount(() => {
|
||||
if (typeof props.server === 'object') { // Handles the testing dev Vue component
|
||||
serverStore.setServer(props.server);
|
||||
} else if (typeof props.server === 'string') { // Handle web component
|
||||
try {
|
||||
const parsedServerProp = JSON.parse(props.server);
|
||||
serverStore.setServer(parsedServerProp);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
const parsedServerProp = JSON.parse(props.server);
|
||||
serverStore.setServer(parsedServerProp);
|
||||
}
|
||||
/**
|
||||
* Listen for callbacks, if we receive one that needs to be acted upon the store will display
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import { ExclamationTriangleIcon, CheckCircleIcon } from '@heroicons/vue/24/solid';
|
||||
|
||||
type ApiOnlineStatus = 'online'|'offline';
|
||||
const onlineStatus = ref<ApiOnlineStatus>('online');
|
||||
const apiLoading = ref(false);
|
||||
|
||||
import { useQuery } from '@vue/apollo-composable';
|
||||
|
||||
import {
|
||||
@@ -16,10 +21,6 @@ const result = computed(() => useFragment(TEST_FRAGMENT, newResult.value?.cloud)
|
||||
watch(result, (newVal, oldVal) => {
|
||||
console.log('result', newVal, oldVal);
|
||||
});
|
||||
|
||||
type ApiOnlineStatus = 'online'|'offline';
|
||||
const onlineStatus = ref<ApiOnlineStatus>('online');
|
||||
const apiLoading = ref(false);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ArrowTopRightOnSquareIcon } from '@heroicons/vue/24/solid';
|
||||
import type { ServerStateDataAction } from '~/types/server';
|
||||
@@ -5,7 +6,7 @@ import type { UserProfileLink } from '~/types/userProfile';
|
||||
|
||||
export interface Props {
|
||||
item: ServerStateDataAction | UserProfileLink;
|
||||
rounded: boolean;
|
||||
rounded?: boolean;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
|
||||
@@ -15,6 +15,15 @@ import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-
|
||||
const documents = {
|
||||
"\n fragment TestFragment on Cloud {\n error\n }\n": types.TestFragmentFragmentDoc,
|
||||
"\n query cloudError {\n cloud {\n ...TestFragment\n }\n }\n": types.cloudErrorDocument,
|
||||
"\n fragment FragmentConfig on Config {\n error\n valid\n }\n": types.FragmentConfigFragmentDoc,
|
||||
"\n fragment FragmentOwner on Owner {\n avatar\n username\n }\n": types.FragmentOwnerFragmentDoc,
|
||||
"\n fragment FragmentRegistration on Registration {\n state\n expiration\n keyFile {\n contents\n }\n }\n": types.FragmentRegistrationFragmentDoc,
|
||||
"\n fragment FragmentVars on Vars {\n regGen\n regState\n configError\n configValid\n }\n": types.FragmentVarsFragmentDoc,
|
||||
"\n query serverState {\n owner {\n ...FragmentOwner\n }\n info {\n os {\n hostname\n }\n }\n registration {\n ...FragmentRegistration\n }\n crashReportingEnabled\n vars {\n ...FragmentVars\n }\n config {\n ...FragmentConfig\n }\n cloud {\n error\n apiKey {\n valid\n error\n }\n relay {\n status\n error\n }\n cloud {\n status\n error\n }\n }\n }\n": types.serverStateDocument,
|
||||
"\n subscription Config {\n config {\n ...FragmentConfig\n }\n }\n": types.ConfigDocument,
|
||||
"\n subscription Owner {\n owner {\n ...FragmentOwner\n }\n }\n": types.OwnerDocument,
|
||||
"\n subscription Registration {\n registration {\n ...FragmentRegistration\n }\n }\n": types.RegistrationDocument,
|
||||
"\n subscription Vars {\n vars {\n ...FragmentVars\n }\n }\n": types.VarsDocument,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -39,6 +48,42 @@ export function graphql(source: "\n fragment TestFragment on Cloud {\n error
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n query cloudError {\n cloud {\n ...TestFragment\n }\n }\n"): (typeof documents)["\n query cloudError {\n cloud {\n ...TestFragment\n }\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n fragment FragmentConfig on Config {\n error\n valid\n }\n"): (typeof documents)["\n fragment FragmentConfig on Config {\n error\n valid\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n fragment FragmentOwner on Owner {\n avatar\n username\n }\n"): (typeof documents)["\n fragment FragmentOwner on Owner {\n avatar\n username\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n fragment FragmentRegistration on Registration {\n state\n expiration\n keyFile {\n contents\n }\n }\n"): (typeof documents)["\n fragment FragmentRegistration on Registration {\n state\n expiration\n keyFile {\n contents\n }\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n fragment FragmentVars on Vars {\n regGen\n regState\n configError\n configValid\n }\n"): (typeof documents)["\n fragment FragmentVars on Vars {\n regGen\n regState\n configError\n configValid\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n query serverState {\n owner {\n ...FragmentOwner\n }\n info {\n os {\n hostname\n }\n }\n registration {\n ...FragmentRegistration\n }\n crashReportingEnabled\n vars {\n ...FragmentVars\n }\n config {\n ...FragmentConfig\n }\n cloud {\n error\n apiKey {\n valid\n error\n }\n relay {\n status\n error\n }\n cloud {\n status\n error\n }\n }\n }\n"): (typeof documents)["\n query serverState {\n owner {\n ...FragmentOwner\n }\n info {\n os {\n hostname\n }\n }\n registration {\n ...FragmentRegistration\n }\n crashReportingEnabled\n vars {\n ...FragmentVars\n }\n config {\n ...FragmentConfig\n }\n cloud {\n error\n apiKey {\n valid\n error\n }\n relay {\n status\n error\n }\n cloud {\n status\n error\n }\n }\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n subscription Config {\n config {\n ...FragmentConfig\n }\n }\n"): (typeof documents)["\n subscription Config {\n config {\n ...FragmentConfig\n }\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n subscription Owner {\n owner {\n ...FragmentOwner\n }\n }\n"): (typeof documents)["\n subscription Owner {\n owner {\n ...FragmentOwner\n }\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n subscription Registration {\n registration {\n ...FragmentRegistration\n }\n }\n"): (typeof documents)["\n subscription Registration {\n registration {\n ...FragmentRegistration\n }\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n subscription Vars {\n vars {\n ...FragmentVars\n }\n }\n"): (typeof documents)["\n subscription Vars {\n vars {\n ...FragmentVars\n }\n }\n"];
|
||||
|
||||
export function graphql(source: string) {
|
||||
return (documents as any)[source] ?? {};
|
||||
|
||||
@@ -1596,5 +1596,71 @@ export type cloudErrorQuery = { __typename?: 'Query', cloud?: (
|
||||
& { ' $fragmentRefs'?: { 'TestFragmentFragment': TestFragmentFragment } }
|
||||
) | null };
|
||||
|
||||
export type FragmentConfigFragment = { __typename?: 'Config', error?: ConfigErrorState | null, valid?: boolean | null } & { ' $fragmentName'?: 'FragmentConfigFragment' };
|
||||
|
||||
export type FragmentOwnerFragment = { __typename?: 'Owner', avatar?: string | null, username?: string | null } & { ' $fragmentName'?: 'FragmentOwnerFragment' };
|
||||
|
||||
export type FragmentRegistrationFragment = { __typename?: 'Registration', state?: RegistrationState | null, expiration?: string | null, keyFile?: { __typename?: 'KeyFile', contents?: string | null } | null } & { ' $fragmentName'?: 'FragmentRegistrationFragment' };
|
||||
|
||||
export type FragmentVarsFragment = { __typename?: 'Vars', regGen?: string | null, regState?: RegistrationState | null, configError?: ConfigErrorState | null, configValid?: boolean | null } & { ' $fragmentName'?: 'FragmentVarsFragment' };
|
||||
|
||||
export type serverStateQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type serverStateQuery = { __typename?: 'Query', crashReportingEnabled?: boolean | null, owner?: (
|
||||
{ __typename?: 'Owner' }
|
||||
& { ' $fragmentRefs'?: { 'FragmentOwnerFragment': FragmentOwnerFragment } }
|
||||
) | null, info?: { __typename?: 'Info', os?: { __typename?: 'Os', hostname?: string | null } | null } | null, registration?: (
|
||||
{ __typename?: 'Registration' }
|
||||
& { ' $fragmentRefs'?: { 'FragmentRegistrationFragment': FragmentRegistrationFragment } }
|
||||
) | null, vars?: (
|
||||
{ __typename?: 'Vars' }
|
||||
& { ' $fragmentRefs'?: { 'FragmentVarsFragment': FragmentVarsFragment } }
|
||||
) | null, config: (
|
||||
{ __typename?: 'Config' }
|
||||
& { ' $fragmentRefs'?: { 'FragmentConfigFragment': FragmentConfigFragment } }
|
||||
), cloud?: { __typename?: 'Cloud', error?: string | null, apiKey: { __typename?: 'ApiKeyResponse', valid: boolean, error?: string | null }, relay?: { __typename?: 'RelayResponse', status: string, error?: string | null } | null, cloud: { __typename?: 'CloudResponse', status: string, error?: string | null } } | null };
|
||||
|
||||
export type ConfigSubscriptionVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type ConfigSubscription = { __typename?: 'Subscription', config: (
|
||||
{ __typename?: 'Config' }
|
||||
& { ' $fragmentRefs'?: { 'FragmentConfigFragment': FragmentConfigFragment } }
|
||||
) };
|
||||
|
||||
export type OwnerSubscriptionVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type OwnerSubscription = { __typename?: 'Subscription', owner: (
|
||||
{ __typename?: 'Owner' }
|
||||
& { ' $fragmentRefs'?: { 'FragmentOwnerFragment': FragmentOwnerFragment } }
|
||||
) };
|
||||
|
||||
export type RegistrationSubscriptionVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type RegistrationSubscription = { __typename?: 'Subscription', registration: (
|
||||
{ __typename?: 'Registration' }
|
||||
& { ' $fragmentRefs'?: { 'FragmentRegistrationFragment': FragmentRegistrationFragment } }
|
||||
) };
|
||||
|
||||
export type VarsSubscriptionVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type VarsSubscription = { __typename?: 'Subscription', vars: (
|
||||
{ __typename?: 'Vars' }
|
||||
& { ' $fragmentRefs'?: { 'FragmentVarsFragment': FragmentVarsFragment } }
|
||||
) };
|
||||
|
||||
export const TestFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TestFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Cloud"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"error"}}]}}]} as unknown as DocumentNode<TestFragmentFragment, unknown>;
|
||||
export const cloudErrorDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"cloudError"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"cloud"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TestFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TestFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Cloud"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"error"}}]}}]} as unknown as DocumentNode<cloudErrorQuery, cloudErrorQueryVariables>;
|
||||
export const FragmentConfigFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FragmentConfig"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Config"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"error"}},{"kind":"Field","name":{"kind":"Name","value":"valid"}}]}}]} as unknown as DocumentNode<FragmentConfigFragment, unknown>;
|
||||
export const FragmentOwnerFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FragmentOwner"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Owner"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"avatar"}},{"kind":"Field","name":{"kind":"Name","value":"username"}}]}}]} as unknown as DocumentNode<FragmentOwnerFragment, unknown>;
|
||||
export const FragmentRegistrationFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FragmentRegistration"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Registration"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"state"}},{"kind":"Field","name":{"kind":"Name","value":"expiration"}},{"kind":"Field","name":{"kind":"Name","value":"keyFile"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"contents"}}]}}]}}]} as unknown as DocumentNode<FragmentRegistrationFragment, unknown>;
|
||||
export const FragmentVarsFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FragmentVars"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Vars"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"regGen"}},{"kind":"Field","name":{"kind":"Name","value":"regState"}},{"kind":"Field","name":{"kind":"Name","value":"configError"}},{"kind":"Field","name":{"kind":"Name","value":"configValid"}}]}}]} as unknown as DocumentNode<FragmentVarsFragment, unknown>;
|
||||
export const cloudErrorDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"cloudError"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"cloud"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TestFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TestFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Cloud"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"error"}}]}}]} as unknown as DocumentNode<cloudErrorQuery, cloudErrorQueryVariables>;
|
||||
export const serverStateDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"serverState"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"owner"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FragmentOwner"}}]}},{"kind":"Field","name":{"kind":"Name","value":"info"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"os"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hostname"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"registration"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FragmentRegistration"}}]}},{"kind":"Field","name":{"kind":"Name","value":"crashReportingEnabled"}},{"kind":"Field","name":{"kind":"Name","value":"vars"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FragmentVars"}}]}},{"kind":"Field","name":{"kind":"Name","value":"config"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FragmentConfig"}}]}},{"kind":"Field","name":{"kind":"Name","value":"cloud"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"error"}},{"kind":"Field","name":{"kind":"Name","value":"apiKey"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"valid"}},{"kind":"Field","name":{"kind":"Name","value":"error"}}]}},{"kind":"Field","name":{"kind":"Name","value":"relay"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"error"}}]}},{"kind":"Field","name":{"kind":"Name","value":"cloud"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"error"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FragmentOwner"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Owner"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"avatar"}},{"kind":"Field","name":{"kind":"Name","value":"username"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FragmentRegistration"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Registration"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"state"}},{"kind":"Field","name":{"kind":"Name","value":"expiration"}},{"kind":"Field","name":{"kind":"Name","value":"keyFile"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"contents"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FragmentVars"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Vars"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"regGen"}},{"kind":"Field","name":{"kind":"Name","value":"regState"}},{"kind":"Field","name":{"kind":"Name","value":"configError"}},{"kind":"Field","name":{"kind":"Name","value":"configValid"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FragmentConfig"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Config"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"error"}},{"kind":"Field","name":{"kind":"Name","value":"valid"}}]}}]} as unknown as DocumentNode<serverStateQuery, serverStateQueryVariables>;
|
||||
export const ConfigDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"subscription","name":{"kind":"Name","value":"Config"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"config"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FragmentConfig"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FragmentConfig"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Config"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"error"}},{"kind":"Field","name":{"kind":"Name","value":"valid"}}]}}]} as unknown as DocumentNode<ConfigSubscription, ConfigSubscriptionVariables>;
|
||||
export const OwnerDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"subscription","name":{"kind":"Name","value":"Owner"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"owner"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FragmentOwner"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FragmentOwner"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Owner"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"avatar"}},{"kind":"Field","name":{"kind":"Name","value":"username"}}]}}]} as unknown as DocumentNode<OwnerSubscription, OwnerSubscriptionVariables>;
|
||||
export const RegistrationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"subscription","name":{"kind":"Name","value":"Registration"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"registration"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FragmentRegistration"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FragmentRegistration"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Registration"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"state"}},{"kind":"Field","name":{"kind":"Name","value":"expiration"}},{"kind":"Field","name":{"kind":"Name","value":"keyFile"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"contents"}}]}}]}}]} as unknown as DocumentNode<RegistrationSubscription, RegistrationSubscriptionVariables>;
|
||||
export const VarsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"subscription","name":{"kind":"Name","value":"Vars"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"vars"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FragmentVars"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FragmentVars"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Vars"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"regGen"}},{"kind":"Field","name":{"kind":"Name","value":"regState"}},{"kind":"Field","name":{"kind":"Name","value":"configError"}},{"kind":"Field","name":{"kind":"Name","value":"configValid"}}]}}]} as unknown as DocumentNode<VarsSubscription, VarsSubscriptionVariables>;
|
||||
@@ -1,64 +0,0 @@
|
||||
import { DefaultApolloClient } from '@vue/apollo-composable';
|
||||
import { ApolloClient, HttpLink, InMemoryCache, split } from '@apollo/client/core/core.cjs';
|
||||
import { GraphQLWsLink } from '@apollo/client/link/subscriptions';
|
||||
import { getMainDefinition } from '@apollo/client/utilities';
|
||||
import { createClient } from 'graphql-ws';
|
||||
|
||||
export interface ApolloClientPayload {
|
||||
apiKey: string;
|
||||
httpEndpoint: string;
|
||||
wsEndpoint: string;
|
||||
}
|
||||
|
||||
export const useApollo = (payload: ApolloClientPayload) => {
|
||||
console.debug('[useApollo.create]', payload);
|
||||
|
||||
const unraidApiClient = ref<ApolloClient<any>>();
|
||||
|
||||
// Create an http link:
|
||||
const httpLink = new HttpLink({
|
||||
uri: payload.httpEndpoint,
|
||||
headers: {
|
||||
'x-api-key': payload.apiKey,
|
||||
},
|
||||
});
|
||||
|
||||
// Create a GraphQLWsLink link:
|
||||
const wsLink = new GraphQLWsLink(
|
||||
createClient({
|
||||
url: payload.wsEndpoint,
|
||||
connectionParams: () => ({
|
||||
headers: {
|
||||
'x-api-key': payload.apiKey,
|
||||
},
|
||||
}),
|
||||
}),
|
||||
);
|
||||
|
||||
// using the ability to split links, you can send data to each link
|
||||
// depending on what kind of operation is being sent
|
||||
const link = split(
|
||||
// split based on operation type
|
||||
({ query }) => {
|
||||
const definition = getMainDefinition(query);
|
||||
return (
|
||||
definition.kind === "OperationDefinition" &&
|
||||
definition.operation === "subscription"
|
||||
);
|
||||
},
|
||||
wsLink,
|
||||
httpLink,
|
||||
);
|
||||
|
||||
console.debug('[useApollo.create] link', link);
|
||||
|
||||
// Create the apollo client with cache implementation.
|
||||
unraidApiClient.value = new ApolloClient({
|
||||
link,
|
||||
cache: new InMemoryCache(),
|
||||
});
|
||||
|
||||
return {
|
||||
unraidApiClient,
|
||||
};
|
||||
};
|
||||
7
package-lock.json
generated
7
package-lock.json
generated
@@ -30,6 +30,7 @@
|
||||
"@nuxtjs/tailwindcss": "^6.7.0",
|
||||
"@types/crypto-js": "^4.1.1",
|
||||
"@types/node": "^18",
|
||||
"@vue/apollo-util": "^4.0.0-beta.6",
|
||||
"@vueuse/core": "^10.1.2",
|
||||
"@vueuse/nuxt": "^10.1.2",
|
||||
"amazon-cognito-identity-js": "^6.2.0",
|
||||
@@ -5601,6 +5602,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/apollo-util": {
|
||||
"version": "4.0.0-beta.6",
|
||||
"resolved": "https://registry.npmjs.org/@vue/apollo-util/-/apollo-util-4.0.0-beta.6.tgz",
|
||||
"integrity": "sha512-2QsiJ77eLInd7Wu3I2eGD4OLJrqImXBoVMlgxjLPgRHru1h5Uf+sGow23/99lGy/5Ao+TNqAZp6RGnLdJqo5tw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@vue/babel-helper-vue-transform-on": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.1.5.tgz",
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
"@nuxtjs/tailwindcss": "^6.7.0",
|
||||
"@types/crypto-js": "^4.1.1",
|
||||
"@types/node": "^18",
|
||||
"@vue/apollo-util": "^4.0.0-beta.6",
|
||||
"@vueuse/core": "^10.1.2",
|
||||
"@vueuse/nuxt": "^10.1.2",
|
||||
"amazon-cognito-identity-js": "^6.2.0",
|
||||
|
||||
104
store/server.fragment.ts
Normal file
104
store/server.fragment.ts
Normal file
@@ -0,0 +1,104 @@
|
||||
import { graphql } from "~/composables/gql/gql";
|
||||
|
||||
export const SERVER_CONFIG_FRAGMENT = graphql(/* GraphQL */`
|
||||
fragment FragmentConfig on Config {
|
||||
error
|
||||
valid
|
||||
}
|
||||
`);
|
||||
|
||||
export const SERVER_OWNER_FRAGMENT = graphql(/* GraphQL */`
|
||||
fragment FragmentOwner on Owner {
|
||||
avatar
|
||||
username
|
||||
}
|
||||
`);
|
||||
|
||||
export const SERVER_REGISTRATION_FRAGMENT = graphql(/* GraphQL */`
|
||||
fragment FragmentRegistration on Registration {
|
||||
state
|
||||
expiration
|
||||
keyFile {
|
||||
contents
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
export const SERVER_VARS_FRAGMENT = graphql(/* GraphQL */`
|
||||
fragment FragmentVars on Vars {
|
||||
regGen
|
||||
regState
|
||||
configError
|
||||
configValid
|
||||
}
|
||||
`);
|
||||
|
||||
export const SERVER_STATE_QUERY = graphql(/* GraphQL */`
|
||||
query serverState {
|
||||
owner {
|
||||
...FragmentOwner
|
||||
}
|
||||
info {
|
||||
os {
|
||||
hostname
|
||||
}
|
||||
}
|
||||
registration {
|
||||
...FragmentRegistration
|
||||
}
|
||||
crashReportingEnabled
|
||||
vars {
|
||||
...FragmentVars
|
||||
}
|
||||
config {
|
||||
...FragmentConfig
|
||||
}
|
||||
cloud {
|
||||
error
|
||||
apiKey {
|
||||
valid
|
||||
error
|
||||
}
|
||||
relay {
|
||||
status
|
||||
error
|
||||
}
|
||||
cloud {
|
||||
status
|
||||
error
|
||||
}
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
export const SERVER_CONFIG_SUBSCRIPTION = graphql(/* GraphQL */`
|
||||
subscription Config {
|
||||
config {
|
||||
...FragmentConfig
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
export const SERVER_OWNER_SUBSCRIPTION = graphql(/* GraphQL */`
|
||||
subscription Owner {
|
||||
owner {
|
||||
...FragmentOwner
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
export const SERVER_REGISTRATION_SUBSCRIPTION = graphql(/* GraphQL */`
|
||||
subscription Registration {
|
||||
registration {
|
||||
...FragmentRegistration
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
export const SERVER_VARS_SUBSCRIPTION = graphql(/* GraphQL */`
|
||||
subscription Vars {
|
||||
vars {
|
||||
...FragmentVars
|
||||
}
|
||||
}
|
||||
`);
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @todo Check OS and Connect Plugin versions against latest via API every se
|
||||
* @todo Check OS and Connect Plugin versions against latest via API every session
|
||||
*/
|
||||
import { defineStore, createPinia, setActivePinia } from 'pinia';
|
||||
import {
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
KeyIcon,
|
||||
QuestionMarkCircleIcon
|
||||
} from '@heroicons/vue/24/solid';
|
||||
import { useQuery, useSubscription } from '@vue/apollo-composable';
|
||||
|
||||
import { SETTINGS_MANAGMENT_ACCESS } from '~/helpers/urls';
|
||||
import { useAccountStore } from '~/store/account';
|
||||
@@ -29,6 +30,19 @@ import type {
|
||||
ServerStateDataAction,
|
||||
ServerconnectPluginInstalled,
|
||||
} from '~/types/server';
|
||||
|
||||
import {
|
||||
SERVER_STATE_QUERY,
|
||||
SERVER_VARS_FRAGMENT,
|
||||
SERVER_VARS_SUBSCRIPTION,
|
||||
SERVER_OWNER_FRAGMENT,
|
||||
SERVER_OWNER_SUBSCRIPTION,
|
||||
SERVER_CONFIG_FRAGMENT,
|
||||
SERVER_CONFIG_SUBSCRIPTION,
|
||||
SERVER_REGISTRATION_FRAGMENT,
|
||||
SERVER_REGISTRATION_SUBSCRIPTION,
|
||||
} from './server.fragment';
|
||||
import { useFragment } from '~/composables/gql/fragment-masking';
|
||||
/**
|
||||
* @see https://stackoverflow.com/questions/73476371/using-pinia-with-vue-js-web-components
|
||||
* @see https://github.com/vuejs/pinia/discussions/1085
|
||||
@@ -649,21 +663,93 @@ export const useServerStore = defineStore('server', () => {
|
||||
if (typeof data?.uptime !== 'undefined') uptime.value = data.uptime;
|
||||
if (typeof data?.username !== 'undefined') username.value = data.username;
|
||||
if (typeof data?.wanFQDN !== 'undefined') wanFQDN.value = data.wanFQDN;
|
||||
console.debug('[setServer] server.value', server.value);
|
||||
console.debug('[setServer] server', server.value);
|
||||
};
|
||||
|
||||
const mutateServerStateFromApi = (data) => {
|
||||
const mutatedData = {
|
||||
// if we get an owners obj back and the username is root we don't want to overwrite the values
|
||||
...(data.owner && data.owner.username !== 'root' && {
|
||||
avatar: data.owner.avatar,
|
||||
username: data.owner.username,
|
||||
registered: true,
|
||||
}),
|
||||
// if owners obj is empty we need to sign user out
|
||||
// ...(context.state.signOutTriggered && { username: '', avatar: '', registered: false }),
|
||||
name: (data.info && data.info.os) ? data.info.os.hostname : null,
|
||||
keyfile: (data.registration && data.registration.keyFile) ? data.registration.keyFile.contents : null,
|
||||
// sendCrashInfo: data.crashReportingEnabled,
|
||||
regGen: data.vars ? data.vars.regGen : null,
|
||||
state: data.vars ? data.vars.regState : null,
|
||||
config: data.config ? data.config : {
|
||||
error: data.vars ? data.vars.configError : null,
|
||||
valid: data.vars ? data.vars.configValid : true,
|
||||
},
|
||||
expireTime: (data.registration && data.registration.expiration) ? data.registration.expiration : 0,
|
||||
...(data.cloud && { cloud: data.cloud }),
|
||||
}
|
||||
console.debug('[mutateServerStateFromApi] mutatedData', mutatedData);
|
||||
return mutatedData;
|
||||
};
|
||||
|
||||
const fetchServerFromApi = () => {
|
||||
const { result: resultServerState } = useQuery(SERVER_STATE_QUERY);
|
||||
const serverState = computed(() => resultServerState.value ?? null);
|
||||
watch(serverState, value => {
|
||||
console.debug('[watch.serverState]', value);
|
||||
if (value) {
|
||||
const mutatedServerStateResult = mutateServerStateFromApi(value);
|
||||
setServer(mutatedServerStateResult);
|
||||
}
|
||||
});
|
||||
|
||||
const { result: resultServerVars } = useSubscription(SERVER_VARS_SUBSCRIPTION);
|
||||
const serverVars = computed(() => useFragment(SERVER_VARS_FRAGMENT, resultServerVars.value));
|
||||
watch(serverVars, value => {
|
||||
console.debug('[watch.serverVars]', value);
|
||||
// if (value) {
|
||||
// }
|
||||
});
|
||||
|
||||
// const { result: resultServerOwner } = useSubscription(SERVER_OWNER_SUBSCRIPTION);
|
||||
// const serverOwner = computed(() => resultServerOwner.value ?? null);
|
||||
// watch(serverOwner, value => {
|
||||
// console.debug('[watch.resultServerOwner]', value);
|
||||
// // if (value) {
|
||||
// // }
|
||||
// });
|
||||
|
||||
// const { result: resultServerConfig } = useSubscription(SERVER_CONFIG_SUBSCRIPTION);
|
||||
// const serverConfig = computed(() => resultServerConfig.value ?? null);
|
||||
// watch(serverConfig, value => {
|
||||
// console.debug('[watch.resultServerConfig]', value);
|
||||
// // if (value) {
|
||||
// // }
|
||||
// });
|
||||
|
||||
// const { result: resultServerRegistration } = useSubscription(SERVER_REGISTRATION_SUBSCRIPTION);
|
||||
// const serverRegistration = computed(() => resultServerRegistration.value ?? null);
|
||||
// watch(serverRegistration, value => {
|
||||
// console.debug('[watch.resultServerRegistration]', value);
|
||||
// // if (value) {
|
||||
// // }
|
||||
// });
|
||||
};
|
||||
|
||||
watch(apiKey, (newVal, oldVal) => {
|
||||
console.debug('[useUnraidApiStore] apiKey', newVal, oldVal);
|
||||
console.debug('[watch.apiKey]', newVal, oldVal);
|
||||
if (oldVal) {
|
||||
// stop old client
|
||||
console.debug('[useUnraidApiStore] no apiKey – stop old client');
|
||||
console.debug('[watch.apiKey] no apiKey, stop old client');
|
||||
}
|
||||
if (newVal) {
|
||||
/** @todo abstract validation checks */
|
||||
if (newVal && newVal.length === 64 && newVal.startsWith('unupc_')) {
|
||||
// start new client
|
||||
console.debug('[useUnraidApiStore] apiKey – start new client');
|
||||
console.debug('[watch.apiKey] start new client');
|
||||
unraidApiStore.createApolloClient(newVal);
|
||||
}
|
||||
});
|
||||
|
||||
watch(theme, (newVal) => {
|
||||
if (newVal) themeStore.setTheme(newVal);
|
||||
});
|
||||
@@ -733,5 +819,6 @@ export const useServerStore = defineStore('server', () => {
|
||||
tooManyDevices,
|
||||
// actions
|
||||
setServer,
|
||||
fetchServerFromApi,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1,34 +1,117 @@
|
||||
import { from, ApolloClient, createHttpLink, InMemoryCache, split } from '@apollo/client/core/core.cjs';
|
||||
import { onError } from '@apollo/client/link/error'
|
||||
import { GraphQLWsLink } from '@apollo/client/link/subscriptions';
|
||||
import { getMainDefinition } from '@apollo/client/utilities';
|
||||
import { provideApolloClient } from '@vue/apollo-composable';
|
||||
import { logErrorMessages } from '@vue/apollo-util'
|
||||
import { createClient } from 'graphql-ws';
|
||||
import { defineStore, createPinia, setActivePinia } from 'pinia';
|
||||
import { useApollo } from '~/composables/services/apollo';
|
||||
|
||||
import { useErrorsStore } from '~/store/errors';
|
||||
import { useServerStore } from '~/store/server';
|
||||
/**
|
||||
* @see https://stackoverflow.com/questions/73476371/using-pinia-with-vue-js-web-components
|
||||
* @see https://github.com/vuejs/pinia/discussions/1085
|
||||
*/
|
||||
setActivePinia(createPinia());
|
||||
let baseUrl = window.location.origin
|
||||
const localDevUrl = baseUrl.includes(':4321'); /** @todo use ENV */
|
||||
if (localDevUrl) {
|
||||
/** @temp local dev mode */
|
||||
baseUrl = baseUrl.replace(':4321', ':3001');
|
||||
}
|
||||
const httpEndpoint = new URL('/graphql', baseUrl);
|
||||
const wsEndpoint = new URL('/graphql', baseUrl.replace('http', 'ws'));
|
||||
|
||||
// @todo build URLs correctly
|
||||
const WINDOW_URL = new URL(window.location.origin);
|
||||
const httpEndpoint = `${WINDOW_URL.protocol}//${WINDOW_URL.host}/graphql`;
|
||||
const wsProtocol = WINDOW_URL.protocol.includes('https') ? 'wss://' : 'ws://';
|
||||
const wsEndpoint = `${wsProtocol}${WINDOW_URL.host}/graphql`;
|
||||
console.debug('[useUnraidApiStore] httpEndpoint', httpEndpoint.toString());
|
||||
console.debug('[useUnraidApiStore] wsEndpoint', wsEndpoint.toString());
|
||||
|
||||
export const useUnraidApiStore = defineStore('unraidApi', () => {
|
||||
console.debug('[useUnraidApiStore]');
|
||||
const errorsStore = useErrorsStore();
|
||||
const serverStore = useServerStore();
|
||||
|
||||
const unraidApiClient = ref<ApolloClient<any>>();
|
||||
|
||||
/**
|
||||
* Automatically called when an apiKey is set in the serverStore
|
||||
*/
|
||||
const createApolloClient = (apiKey: string) => {
|
||||
console.debug('[useUnraidApiStore] createClient');
|
||||
const { unraidApiClient } = useApollo({
|
||||
apiKey,
|
||||
httpEndpoint,
|
||||
wsEndpoint,
|
||||
console.debug('[useUnraidApiStore.createApolloClient]');
|
||||
|
||||
const headers = { 'x-api-key': apiKey };
|
||||
|
||||
const httpLink = new createHttpLink({
|
||||
uri: httpEndpoint.toString(),
|
||||
headers,
|
||||
});
|
||||
console.debug('[useUnraidApiStore] provideApolloClient', unraidApiClient.value);
|
||||
|
||||
const wsLink = new GraphQLWsLink(
|
||||
createClient({
|
||||
url: wsEndpoint.toString(),
|
||||
connectionParams: () => ({
|
||||
headers,
|
||||
}),
|
||||
}),
|
||||
);
|
||||
|
||||
/**
|
||||
* @todo integrate errorsStore errorsStore.setError(error);
|
||||
*/
|
||||
const errorLink = onError((errors) => {
|
||||
logErrorMessages(errors);
|
||||
// // { graphQLErrors, networkError }
|
||||
// if (graphQLErrors) {
|
||||
// logErrorMessages(graphQLErrors);
|
||||
// // graphQLErrors.map(({ message, locations, path }) => {
|
||||
// // // console.error(`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`);
|
||||
// // })
|
||||
// }
|
||||
|
||||
// if (networkError) {
|
||||
// logErrorMessages(networkError);
|
||||
// }
|
||||
});
|
||||
|
||||
const splitLinks = split(
|
||||
({ query }) => {
|
||||
const definition = getMainDefinition(query);
|
||||
return (
|
||||
definition.kind === "OperationDefinition" &&
|
||||
definition.operation === "subscription"
|
||||
);
|
||||
},
|
||||
wsLink,
|
||||
httpLink,
|
||||
);
|
||||
/**
|
||||
* @todo as we add retries, determine which we'll need
|
||||
* https://www.apollographql.com/docs/react/api/link/introduction/#additive-composition
|
||||
* https://www.apollographql.com/docs/react/api/link/introduction/#directional-composition
|
||||
*/
|
||||
const additiveLink = from([
|
||||
errorLink,
|
||||
splitLinks,
|
||||
]);
|
||||
|
||||
unraidApiClient.value = new ApolloClient({
|
||||
link: additiveLink,
|
||||
cache: new InMemoryCache(),
|
||||
});
|
||||
|
||||
provideApolloClient(unraidApiClient.value);
|
||||
console.debug('[useUnraidApiStore.createApolloClient] 🏁 CREATED');
|
||||
};
|
||||
|
||||
watch(unraidApiClient, (newVal, oldVal) => {
|
||||
console.debug('[watch.unraidApiStore.unraidApiClient]', { newVal, oldVal });
|
||||
if (newVal && !oldVal) { // first time
|
||||
serverStore.fetchServerFromApi();
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
unraidApiClient,
|
||||
createApolloClient,
|
||||
};
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user