mirror of
https://github.com/unraid/api.git
synced 2026-04-30 04:01:10 -05:00
feat: working unraid-api gql
This commit is contained in:
+54
@@ -0,0 +1,54 @@
|
||||
import type { CodegenConfig } from '@graphql-codegen/cli';
|
||||
|
||||
const getApiCodegenUrl = () => {
|
||||
if (process.env.USE_LOCAL_CODEGEN === 'true') {
|
||||
return 'http://localhost:3001/graphql';
|
||||
}
|
||||
return '';
|
||||
};
|
||||
|
||||
const config: CodegenConfig = {
|
||||
overwrite: true,
|
||||
documents: ['./**/**/*.ts'],
|
||||
ignoreNoDocuments: false,
|
||||
config: {
|
||||
namingConvention: {
|
||||
typeNames: './fix-array-type.ts',
|
||||
},
|
||||
scalars: {
|
||||
DateTime: 'string',
|
||||
Long: 'number',
|
||||
JSON: 'string',
|
||||
URL: 'URL',
|
||||
Port: 'number',
|
||||
UUID: 'string',
|
||||
},
|
||||
},
|
||||
generates: {
|
||||
'composables/gql/': {
|
||||
preset: 'client',
|
||||
config: {
|
||||
useTypeImports: true,
|
||||
},
|
||||
schema: [
|
||||
{
|
||||
'http://localhost:3001/graphql': {
|
||||
headers: {
|
||||
origin: `/var/run/unraid-php.sock`,
|
||||
'x-api-key': 'unupc_fab6ff6ffe51040595c6d9ffb63a353ba16cc2ad7d93f813a2e80a5810',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
plugins: [
|
||||
{
|
||||
add: {
|
||||
content: '/* eslint-disable */',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
@@ -0,0 +1,15 @@
|
||||
import { graphql } from "~/composables/gql/gql";
|
||||
|
||||
export const TEST_FRAGMENT = graphql(/* GraphQL */`
|
||||
fragment TestFragment on Cloud {
|
||||
error
|
||||
}
|
||||
`);
|
||||
|
||||
export const TEST_QUERY = graphql(/* GraphQL */`
|
||||
query cloudError {
|
||||
cloud {
|
||||
...TestFragment
|
||||
}
|
||||
}
|
||||
`);
|
||||
@@ -1,8 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import { ExclamationTriangleIcon, CheckCircleIcon } from '@heroicons/vue/24/solid';
|
||||
// import { storeToRefs } from 'pinia';
|
||||
// import { useServerStore } from '~/store/server';
|
||||
// const { stateData } = storeToRefs(useServerStore());
|
||||
import { useQuery } from '@vue/apollo-composable';
|
||||
|
||||
import {
|
||||
TEST_FRAGMENT,
|
||||
TEST_QUERY,
|
||||
} from './DropdownConnectStatus.fragment';
|
||||
import { useFragment } from '@/composables/gql/fragment-masking';
|
||||
|
||||
const { result: newResult } = useQuery(
|
||||
TEST_QUERY,
|
||||
);
|
||||
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');
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
import type { ResultOf, DocumentTypeDecoration, TypedDocumentNode } from '@graphql-typed-document-node/core';
|
||||
import type { FragmentDefinitionNode } from 'graphql';
|
||||
import type { Incremental } from './graphql';
|
||||
|
||||
|
||||
export type FragmentType<TDocumentType extends DocumentTypeDecoration<any, any>> = TDocumentType extends DocumentTypeDecoration<
|
||||
infer TType,
|
||||
any
|
||||
>
|
||||
? [TType] extends [{ ' $fragmentName'?: infer TKey }]
|
||||
? TKey extends string
|
||||
? { ' $fragmentRefs'?: { [key in TKey]: TType } }
|
||||
: never
|
||||
: never
|
||||
: never;
|
||||
|
||||
// return non-nullable if `fragmentType` is non-nullable
|
||||
export function useFragment<TType>(
|
||||
_documentNode: DocumentTypeDecoration<TType, any>,
|
||||
fragmentType: FragmentType<DocumentTypeDecoration<TType, any>>
|
||||
): TType;
|
||||
// return nullable if `fragmentType` is nullable
|
||||
export function useFragment<TType>(
|
||||
_documentNode: DocumentTypeDecoration<TType, any>,
|
||||
fragmentType: FragmentType<DocumentTypeDecoration<TType, any>> | null | undefined
|
||||
): TType | null | undefined;
|
||||
// return array of non-nullable if `fragmentType` is array of non-nullable
|
||||
export function useFragment<TType>(
|
||||
_documentNode: DocumentTypeDecoration<TType, any>,
|
||||
fragmentType: ReadonlyArray<FragmentType<DocumentTypeDecoration<TType, any>>>
|
||||
): ReadonlyArray<TType>;
|
||||
// return array of nullable if `fragmentType` is array of nullable
|
||||
export function useFragment<TType>(
|
||||
_documentNode: DocumentTypeDecoration<TType, any>,
|
||||
fragmentType: ReadonlyArray<FragmentType<DocumentTypeDecoration<TType, any>>> | null | undefined
|
||||
): ReadonlyArray<TType> | null | undefined;
|
||||
export function useFragment<TType>(
|
||||
_documentNode: DocumentTypeDecoration<TType, any>,
|
||||
fragmentType: FragmentType<DocumentTypeDecoration<TType, any>> | ReadonlyArray<FragmentType<DocumentTypeDecoration<TType, any>>> | null | undefined
|
||||
): TType | ReadonlyArray<TType> | null | undefined {
|
||||
return fragmentType as any;
|
||||
}
|
||||
|
||||
|
||||
export function makeFragmentData<
|
||||
F extends DocumentTypeDecoration<any, any>,
|
||||
FT extends ResultOf<F>
|
||||
>(data: FT, _fragment: F): FragmentType<F> {
|
||||
return data as FragmentType<F>;
|
||||
}
|
||||
export function isFragmentReady<TQuery, TFrag>(
|
||||
queryNode: DocumentTypeDecoration<TQuery, any>,
|
||||
fragmentNode: TypedDocumentNode<TFrag>,
|
||||
data: FragmentType<TypedDocumentNode<Incremental<TFrag>, any>> | null | undefined
|
||||
): data is FragmentType<typeof fragmentNode> {
|
||||
const deferredFields = (queryNode as { __meta__?: { deferredFields: Record<string, (keyof TFrag)[]> } }).__meta__
|
||||
?.deferredFields;
|
||||
|
||||
if (!deferredFields) return true;
|
||||
|
||||
const fragDef = fragmentNode.definitions[0] as FragmentDefinitionNode | undefined;
|
||||
const fragName = fragDef?.name?.value;
|
||||
|
||||
const fields = (fragName && deferredFields[fragName]) || [];
|
||||
return fields.length > 0 && fields.every(field => data && field in data);
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/* eslint-disable */
|
||||
import * as types from './graphql';
|
||||
import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';
|
||||
|
||||
/**
|
||||
* Map of all GraphQL operations in the project.
|
||||
*
|
||||
* This map has several performance disadvantages:
|
||||
* 1. It is not tree-shakeable, so it will include all operations in the project.
|
||||
* 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle.
|
||||
* 3. It does not support dead code elimination, so it will add unused operations.
|
||||
*
|
||||
* Therefore it is highly recommended to use the babel or swc plugin for production.
|
||||
*/
|
||||
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,
|
||||
};
|
||||
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const query = graphql(`query GetUser($id: ID!) { user(id: $id) { name } }`);
|
||||
* ```
|
||||
*
|
||||
* The query argument is unknown!
|
||||
* Please regenerate the types.
|
||||
*/
|
||||
export function graphql(source: string): unknown;
|
||||
|
||||
/**
|
||||
* 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 TestFragment on Cloud {\n error\n }\n"): (typeof documents)["\n fragment TestFragment on Cloud {\n error\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 cloudError {\n cloud {\n ...TestFragment\n }\n }\n"): (typeof documents)["\n query cloudError {\n cloud {\n ...TestFragment\n }\n }\n"];
|
||||
|
||||
export function graphql(source: string) {
|
||||
return (documents as any)[source] ?? {};
|
||||
}
|
||||
|
||||
export type DocumentType<TDocumentNode extends DocumentNode<any, any>> = TDocumentNode extends DocumentNode< infer TType, any> ? TType : never;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
export * from "./fragment-masking";
|
||||
export * from "./gql";
|
||||
@@ -1,5 +1,5 @@
|
||||
import { DefaultApolloClient } from '@vue/apollo-composable';
|
||||
import { ApolloClient, HttpLink, InMemoryCache, split } from '@apollo/client/core';
|
||||
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';
|
||||
@@ -10,7 +10,7 @@ export interface ApolloClientPayload {
|
||||
wsEndpoint: string;
|
||||
}
|
||||
|
||||
const useApollo = (payload: ApolloClientPayload) => {
|
||||
export const useApollo = (payload: ApolloClientPayload) => {
|
||||
console.debug('[useApollo.create]', payload);
|
||||
|
||||
const unraidApiClient = ref<ApolloClient<any>>();
|
||||
@@ -54,7 +54,7 @@ const useApollo = (payload: ApolloClientPayload) => {
|
||||
|
||||
// Create the apollo client with cache implementation.
|
||||
unraidApiClient.value = new ApolloClient({
|
||||
// link,
|
||||
link,
|
||||
cache: new InMemoryCache(),
|
||||
});
|
||||
|
||||
@@ -62,5 +62,3 @@ const useApollo = (payload: ApolloClientPayload) => {
|
||||
unraidApiClient,
|
||||
};
|
||||
};
|
||||
|
||||
export default useApollo;
|
||||
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* This function wraps constant case, that turns any string into CONSTANT_CASE
|
||||
* However, this function has a bug that, if you pass _ to it it will return an empty
|
||||
* string. This small module fixes that
|
||||
*
|
||||
* @param {string*} str
|
||||
* @return {string}
|
||||
*/
|
||||
function FixArrayType(str) {
|
||||
if (str === 'Array') {
|
||||
return 'ArrayType';
|
||||
}
|
||||
// If result is an empty string, just return the original string
|
||||
return str;
|
||||
}
|
||||
|
||||
module.exports = FixArrayType;
|
||||
Generated
+4488
-506
File diff suppressed because it is too large
Load Diff
+6
-1
@@ -9,9 +9,14 @@
|
||||
"postinstall": "nuxt prepare",
|
||||
"serve": "serve dist/nuxt-custom-elements/connect-components",
|
||||
"deploy:dev": "./scripts/deploy-dev.sh",
|
||||
"build:dev": "nuxt build && npm run deploy:dev"
|
||||
"build:dev": "nuxt build && npm run deploy:dev",
|
||||
"codegen": "graphql-codegen --config codegen.ts -r dotenv/config",
|
||||
"codegen:watch": "graphql-codegen --config codegen.ts --watch -r dotenv/config"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@graphql-codegen/cli": "^4.0.1",
|
||||
"@graphql-codegen/client-preset": "^4.0.1",
|
||||
"@graphql-codegen/introspection": "^4.0.0",
|
||||
"@nuxt/devtools": "^0.6.1",
|
||||
"@nuxtjs/tailwindcss": "^6.7.0",
|
||||
"@types/crypto-js": "^4.1.1",
|
||||
|
||||
+1
-1
@@ -661,7 +661,7 @@ export const useServerStore = defineStore('server', () => {
|
||||
if (newVal) {
|
||||
// start new client
|
||||
console.debug('[useUnraidApiStore] apiKey – start new client');
|
||||
unraidApiStore.createApolloClient();
|
||||
unraidApiStore.createApolloClient(newVal);
|
||||
}
|
||||
});
|
||||
watch(theme, (newVal) => {
|
||||
|
||||
+6
-12
@@ -1,7 +1,6 @@
|
||||
import { provideApolloClient } from '@vue/apollo-composable';
|
||||
import { defineStore, createPinia, setActivePinia } from 'pinia';
|
||||
|
||||
import useApollo from '~/composables/services/apollo';
|
||||
import { useApollo } from '~/composables/services/apollo';
|
||||
|
||||
/**
|
||||
* @see https://stackoverflow.com/questions/73476371/using-pinia-with-vue-js-web-components
|
||||
@@ -9,6 +8,7 @@ import useApollo from '~/composables/services/apollo';
|
||||
*/
|
||||
setActivePinia(createPinia());
|
||||
|
||||
// @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://';
|
||||
@@ -17,24 +17,18 @@ const wsEndpoint = `${wsProtocol}${WINDOW_URL.host}/graphql`;
|
||||
export const useUnraidApiStore = defineStore('unraidApi', () => {
|
||||
console.debug('[useUnraidApiStore]');
|
||||
|
||||
const apiKey = ref<string>('');
|
||||
|
||||
const setApiKey = (newApiKey: string) => apiKey.value = newApiKey;
|
||||
|
||||
const createApolloClient = () => {
|
||||
const createApolloClient = (apiKey: string) => {
|
||||
console.debug('[useUnraidApiStore] createClient');
|
||||
const { unraidApiClient} = useApollo({
|
||||
apiKey: apiKey.value,
|
||||
const { unraidApiClient } = useApollo({
|
||||
apiKey,
|
||||
httpEndpoint,
|
||||
wsEndpoint,
|
||||
});
|
||||
console.debug('[useUnraidApiStore] provideApolloClient', unraidApiClient.value);
|
||||
// provideApolloClient(unraidApiClient);
|
||||
provideApolloClient(unraidApiClient.value);
|
||||
};
|
||||
|
||||
return {
|
||||
apiKey,
|
||||
setApiKey,
|
||||
createApolloClient,
|
||||
};
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user