From 3cf4b26f1d4419b40245b79d29c1008803769a48 Mon Sep 17 00:00:00 2001 From: WithoutPants <53250216+WithoutPants@users.noreply.github.com> Date: Wed, 21 Aug 2019 14:47:48 +1000 Subject: [PATCH] Show version info in about page --- graphql/documents/queries/misc.graphql | 9 +- graphql/schema/schema.graphql | 3 + graphql/schema/types/version.graphql | 4 + pkg/api/resolver.go | 14 +- pkg/api/server.go | 4 + pkg/models/generated_exec.go | 176 ++++++++++++++++++ pkg/models/generated_models.go | 5 + .../Settings/SettingsAboutPanel.tsx | 29 ++- ui/v2/src/core/StashService.ts | 1 + ui/v2/src/core/generated-graphql.tsx | 34 +++- 10 files changed, 274 insertions(+), 5 deletions(-) create mode 100644 graphql/schema/types/version.graphql diff --git a/graphql/documents/queries/misc.graphql b/graphql/documents/queries/misc.graphql index d7990159a..3c1de2639 100644 --- a/graphql/documents/queries/misc.graphql +++ b/graphql/documents/queries/misc.graphql @@ -52,4 +52,11 @@ query Stats { studio_count, tag_count } -} \ No newline at end of file +} + +query Version { + version { + hash, + build_time + } +} diff --git a/graphql/schema/schema.graphql b/graphql/schema/schema.graphql index e756cd285..84ea46f91 100644 --- a/graphql/schema/schema.graphql +++ b/graphql/schema/schema.graphql @@ -68,6 +68,9 @@ type Query { allPerformers: [Performer!]! allStudios: [Studio!]! allTags: [Tag!]! + + # Version + version: Version! } type Mutation { diff --git a/graphql/schema/types/version.graphql b/graphql/schema/types/version.graphql new file mode 100644 index 000000000..79f9e4dab --- /dev/null +++ b/graphql/schema/types/version.graphql @@ -0,0 +1,4 @@ +type Version { + hash: String! + build_time: String! +} \ No newline at end of file diff --git a/pkg/api/resolver.go b/pkg/api/resolver.go index 451df1eef..2744cb322 100644 --- a/pkg/api/resolver.go +++ b/pkg/api/resolver.go @@ -2,10 +2,11 @@ package api import ( "context" - "github.com/stashapp/stash/pkg/models" - "github.com/stashapp/stash/pkg/scraper" "sort" "strconv" + + "github.com/stashapp/stash/pkg/models" + "github.com/stashapp/stash/pkg/scraper" ) type Resolver struct{} @@ -104,6 +105,15 @@ func (r *queryResolver) Stats(ctx context.Context) (*models.StatsResultType, err }, nil } +func (r *queryResolver) Version(ctx context.Context) (*models.Version, error) { + hash, buildtime := GetVersion() + + return &models.Version{ + Hash: hash, + BuildTime: buildtime, + }, nil +} + // Get scene marker tags which show up under the video. func (r *queryResolver) SceneMarkerTags(ctx context.Context, scene_id string) ([]*models.SceneMarkerTag, error) { sceneID, _ := strconv.Atoi(scene_id) diff --git a/pkg/api/server.go b/pkg/api/server.go index fd1112a29..4cee5a2e9 100644 --- a/pkg/api/server.go +++ b/pkg/api/server.go @@ -180,6 +180,10 @@ func printVersion() { fmt.Printf("stash version: %s (%s)\n", githash, buildstamp) } +func GetVersion() (string, string) { + return githash, buildstamp +} + func makeTLSConfig() *tls.Config { cert, err := ioutil.ReadFile(paths.GetSSLCert()) if err != nil { diff --git a/pkg/models/generated_exec.go b/pkg/models/generated_exec.go index 48627edc4..e2e9e83d8 100644 --- a/pkg/models/generated_exec.go +++ b/pkg/models/generated_exec.go @@ -175,6 +175,7 @@ type ComplexityRoot struct { ScrapeFreeonesPerformerList func(childComplexity int, query string) int Stats func(childComplexity int) int ValidGalleriesForScene func(childComplexity int, sceneID *string) int + Version func(childComplexity int) int } Scene struct { @@ -277,6 +278,11 @@ type ComplexityRoot struct { SceneCount func(childComplexity int) int SceneMarkerCount func(childComplexity int) int } + + Version struct { + BuildTime func(childComplexity int) int + Hash func(childComplexity int) int + } } type GalleryResolver interface { @@ -349,6 +355,7 @@ type QueryResolver interface { AllPerformers(ctx context.Context) ([]*Performer, error) AllStudios(ctx context.Context) ([]*Studio, error) AllTags(ctx context.Context) ([]*Tag, error) + Version(ctx context.Context) (*Version, error) } type SceneResolver interface { Title(ctx context.Context, obj *Scene) (*string, error) @@ -1184,6 +1191,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Query.ValidGalleriesForScene(childComplexity, args["scene_id"].(*string)), true + case "Query.version": + if e.complexity.Query.Version == nil { + break + } + + return e.complexity.Query.Version(childComplexity), true + case "Scene.checksum": if e.complexity.Scene.Checksum == nil { break @@ -1681,6 +1695,20 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Tag.SceneMarkerCount(childComplexity), true + case "Version.build_time": + if e.complexity.Version.BuildTime == nil { + break + } + + return e.complexity.Version.BuildTime(childComplexity), true + + case "Version.hash": + if e.complexity.Version.Hash == nil { + break + } + + return e.complexity.Version.Hash(childComplexity), true + } return 0, false } @@ -1857,6 +1885,9 @@ type Query { allPerformers: [Performer!]! allStudios: [Studio!]! allTags: [Tag!]! + + # Version + version: Version! } type Mutation { @@ -2273,6 +2304,10 @@ input TagUpdateInput { input TagDestroyInput { id: ID! +}`}, + &ast.Source{Name: "graphql/schema/types/version.graphql", Input: `type Version { + hash: String! + build_time: String! }`}, ) @@ -5338,6 +5373,33 @@ func (ec *executionContext) _Query_allTags(ctx context.Context, field graphql.Co return ec.marshalNTag2ᚕᚖgithubᚗcomᚋstashappᚋstashᚋpkgᚋmodelsᚐTag(ctx, field.Selections, res) } +func (ec *executionContext) _Query_version(ctx context.Context, field graphql.CollectedField) graphql.Marshaler { + ctx = ec.Tracer.StartFieldExecution(ctx, field) + defer func() { ec.Tracer.EndFieldExecution(ctx) }() + rctx := &graphql.ResolverContext{ + Object: "Query", + Field: field, + Args: nil, + IsMethod: true, + } + ctx = graphql.WithResolverContext(ctx, rctx) + ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx) + resTmp := ec.FieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().Version(rctx) + }) + if resTmp == nil { + if !ec.HasError(rctx) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*Version) + rctx.Result = res + ctx = ec.Tracer.StartFieldChildExecution(ctx) + return ec.marshalNVersion2ᚖgithubᚗcomᚋstashappᚋstashᚋpkgᚋmodelsᚐVersion(ctx, field.Selections, res) +} + func (ec *executionContext) _Query___type(ctx context.Context, field graphql.CollectedField) graphql.Marshaler { ctx = ec.Tracer.StartFieldExecution(ctx, field) defer func() { ec.Tracer.EndFieldExecution(ctx) }() @@ -7188,6 +7250,60 @@ func (ec *executionContext) _Tag_scene_marker_count(ctx context.Context, field g return ec.marshalOInt2ᚖint(ctx, field.Selections, res) } +func (ec *executionContext) _Version_hash(ctx context.Context, field graphql.CollectedField, obj *Version) graphql.Marshaler { + ctx = ec.Tracer.StartFieldExecution(ctx, field) + defer func() { ec.Tracer.EndFieldExecution(ctx) }() + rctx := &graphql.ResolverContext{ + Object: "Version", + Field: field, + Args: nil, + IsMethod: false, + } + ctx = graphql.WithResolverContext(ctx, rctx) + ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx) + resTmp := ec.FieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Hash, nil + }) + if resTmp == nil { + if !ec.HasError(rctx) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + rctx.Result = res + ctx = ec.Tracer.StartFieldChildExecution(ctx) + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _Version_build_time(ctx context.Context, field graphql.CollectedField, obj *Version) graphql.Marshaler { + ctx = ec.Tracer.StartFieldExecution(ctx, field) + defer func() { ec.Tracer.EndFieldExecution(ctx) }() + rctx := &graphql.ResolverContext{ + Object: "Version", + Field: field, + Args: nil, + IsMethod: false, + } + ctx = graphql.WithResolverContext(ctx, rctx) + ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx) + resTmp := ec.FieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.BuildTime, nil + }) + if resTmp == nil { + if !ec.HasError(rctx) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + rctx.Result = res + ctx = ec.Tracer.StartFieldChildExecution(ctx) + return ec.marshalNString2string(ctx, field.Selections, res) +} + func (ec *executionContext) ___Directive_name(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) graphql.Marshaler { ctx = ec.Tracer.StartFieldExecution(ctx, field) defer func() { ec.Tracer.EndFieldExecution(ctx) }() @@ -9890,6 +10006,20 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr } return res }) + case "version": + field := field + out.Concurrently(i, func() (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_version(ctx, field) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + }) case "__type": out.Values[i] = ec._Query___type(ctx, field) case "__schema": @@ -10566,6 +10696,38 @@ func (ec *executionContext) _Tag(ctx context.Context, sel ast.SelectionSet, obj return out } +var versionImplementors = []string{"Version"} + +func (ec *executionContext) _Version(ctx context.Context, sel ast.SelectionSet, obj *Version) graphql.Marshaler { + fields := graphql.CollectFields(ec.RequestContext, sel, versionImplementors) + + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("Version") + case "hash": + out.Values[i] = ec._Version_hash(ctx, field, obj) + if out.Values[i] == graphql.Null { + invalids++ + } + case "build_time": + out.Values[i] = ec._Version_build_time(ctx, field, obj) + if out.Values[i] == graphql.Null { + invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + var __DirectiveImplementors = []string{"__Directive"} func (ec *executionContext) ___Directive(ctx context.Context, sel ast.SelectionSet, obj *introspection.Directive) graphql.Marshaler { @@ -11574,6 +11736,20 @@ func (ec *executionContext) unmarshalNTagUpdateInput2githubᚗcomᚋstashappᚋs return ec.unmarshalInputTagUpdateInput(ctx, v) } +func (ec *executionContext) marshalNVersion2githubᚗcomᚋstashappᚋstashᚋpkgᚋmodelsᚐVersion(ctx context.Context, sel ast.SelectionSet, v Version) graphql.Marshaler { + return ec._Version(ctx, sel, &v) +} + +func (ec *executionContext) marshalNVersion2ᚖgithubᚗcomᚋstashappᚋstashᚋpkgᚋmodelsᚐVersion(ctx context.Context, sel ast.SelectionSet, v *Version) graphql.Marshaler { + if v == nil { + if !ec.HasError(graphql.GetResolverContext(ctx)) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + return ec._Version(ctx, sel, v) +} + func (ec *executionContext) marshalN__Directive2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirective(ctx context.Context, sel ast.SelectionSet, v introspection.Directive) graphql.Marshaler { return ec.___Directive(ctx, sel, &v) } diff --git a/pkg/models/generated_models.go b/pkg/models/generated_models.go index 351270d16..70b8094f4 100644 --- a/pkg/models/generated_models.go +++ b/pkg/models/generated_models.go @@ -283,6 +283,11 @@ type TagUpdateInput struct { Name string `json:"name"` } +type Version struct { + Hash string `json:"hash"` + BuildTime string `json:"build_time"` +} + type CriterionModifier string const ( diff --git a/ui/v2/src/components/Settings/SettingsAboutPanel.tsx b/ui/v2/src/components/Settings/SettingsAboutPanel.tsx index d2d93ba60..f943ef345 100644 --- a/ui/v2/src/components/Settings/SettingsAboutPanel.tsx +++ b/ui/v2/src/components/Settings/SettingsAboutPanel.tsx @@ -2,18 +2,45 @@ import { H1, H4, H6, + HTMLTable, + Spinner, Tag, } from "@blueprintjs/core"; import React, { FunctionComponent } from "react"; import * as GQL from "../../core/generated-graphql"; import { TextUtils } from "../../utils/text"; +import { StashService } from "../../core/StashService"; interface IProps {} export const SettingsAboutPanel: FunctionComponent = (props: IProps) => { + const { data, error, loading } = StashService.useVersion(); + + function renderVersion() { + if (!data || !data.version) { return; } + return ( + <> + + + + Build hash: + {data.version.hash} + + + Build time: + {data.version.build_time} + + + + + ); + } return ( <> - About +

About

+ {!data || loading ? : undefined} + {!!error ? error.message : undefined} + {renderVersion()} ); }; diff --git a/ui/v2/src/core/StashService.ts b/ui/v2/src/core/StashService.ts index 13c83c0dd..6f85b27a3 100644 --- a/ui/v2/src/core/StashService.ts +++ b/ui/v2/src/core/StashService.ts @@ -123,6 +123,7 @@ export class StashService { return GQL.useValidGalleriesForScene({variables: {scene_id: sceneId}}); } public static useStats() { return GQL.useStats(); } + public static useVersion() { return GQL.useVersion(); } public static useConfiguration() { return GQL.useConfiguration(); } public static useDirectories(path?: string) { return GQL.useDirectories({ variables: { path }}); } diff --git a/ui/v2/src/core/generated-graphql.tsx b/ui/v2/src/core/generated-graphql.tsx index d0239e0b2..5330314f2 100644 --- a/ui/v2/src/core/generated-graphql.tsx +++ b/ui/v2/src/core/generated-graphql.tsx @@ -1,6 +1,6 @@ /* tslint:disable */ /* eslint-disable */ -// Generated in 2019-08-14T07:29:27+10:00 +// Generated in 2019-08-21T14:16:45+10:00 export type Maybe = T | undefined; export interface SceneFilterType { @@ -657,6 +657,22 @@ export type StatsStats = { tag_count: number; }; +export type VersionVariables = {}; + +export type VersionQuery = { + __typename?: "Query"; + + version: VersionVersion; +}; + +export type VersionVersion = { + __typename?: "Version"; + + hash: string; + + build_time: string; +}; + export type FindPerformersVariables = { filter?: Maybe; performer_filter?: Maybe; @@ -2141,6 +2157,22 @@ export function useStats( baseOptions ); } +export const VersionDocument = gql` + query Version { + version { + hash + build_time + } + } +`; +export function useVersion( + baseOptions?: ReactApolloHooks.QueryHookOptions +) { + return ReactApolloHooks.useQuery( + VersionDocument, + baseOptions + ); +} export const FindPerformersDocument = gql` query FindPerformers( $filter: FindFilterType