Show version info in about page

This commit is contained in:
WithoutPants
2019-08-21 14:47:48 +10:00
parent 4983437a34
commit 3cf4b26f1d
10 changed files with 274 additions and 5 deletions

View File

@@ -53,3 +53,10 @@ query Stats {
tag_count tag_count
} }
} }
query Version {
version {
hash,
build_time
}
}

View File

@@ -68,6 +68,9 @@ type Query {
allPerformers: [Performer!]! allPerformers: [Performer!]!
allStudios: [Studio!]! allStudios: [Studio!]!
allTags: [Tag!]! allTags: [Tag!]!
# Version
version: Version!
} }
type Mutation { type Mutation {

View File

@@ -0,0 +1,4 @@
type Version {
hash: String!
build_time: String!
}

View File

@@ -2,10 +2,11 @@ package api
import ( import (
"context" "context"
"github.com/stashapp/stash/pkg/models"
"github.com/stashapp/stash/pkg/scraper"
"sort" "sort"
"strconv" "strconv"
"github.com/stashapp/stash/pkg/models"
"github.com/stashapp/stash/pkg/scraper"
) )
type Resolver struct{} type Resolver struct{}
@@ -104,6 +105,15 @@ func (r *queryResolver) Stats(ctx context.Context) (*models.StatsResultType, err
}, nil }, 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. // Get scene marker tags which show up under the video.
func (r *queryResolver) SceneMarkerTags(ctx context.Context, scene_id string) ([]*models.SceneMarkerTag, error) { func (r *queryResolver) SceneMarkerTags(ctx context.Context, scene_id string) ([]*models.SceneMarkerTag, error) {
sceneID, _ := strconv.Atoi(scene_id) sceneID, _ := strconv.Atoi(scene_id)

View File

@@ -180,6 +180,10 @@ func printVersion() {
fmt.Printf("stash version: %s (%s)\n", githash, buildstamp) fmt.Printf("stash version: %s (%s)\n", githash, buildstamp)
} }
func GetVersion() (string, string) {
return githash, buildstamp
}
func makeTLSConfig() *tls.Config { func makeTLSConfig() *tls.Config {
cert, err := ioutil.ReadFile(paths.GetSSLCert()) cert, err := ioutil.ReadFile(paths.GetSSLCert())
if err != nil { if err != nil {

View File

@@ -175,6 +175,7 @@ type ComplexityRoot struct {
ScrapeFreeonesPerformerList func(childComplexity int, query string) int ScrapeFreeonesPerformerList func(childComplexity int, query string) int
Stats func(childComplexity int) int Stats func(childComplexity int) int
ValidGalleriesForScene func(childComplexity int, sceneID *string) int ValidGalleriesForScene func(childComplexity int, sceneID *string) int
Version func(childComplexity int) int
} }
Scene struct { Scene struct {
@@ -277,6 +278,11 @@ type ComplexityRoot struct {
SceneCount func(childComplexity int) int SceneCount func(childComplexity int) int
SceneMarkerCount func(childComplexity int) int SceneMarkerCount func(childComplexity int) int
} }
Version struct {
BuildTime func(childComplexity int) int
Hash func(childComplexity int) int
}
} }
type GalleryResolver interface { type GalleryResolver interface {
@@ -349,6 +355,7 @@ type QueryResolver interface {
AllPerformers(ctx context.Context) ([]*Performer, error) AllPerformers(ctx context.Context) ([]*Performer, error)
AllStudios(ctx context.Context) ([]*Studio, error) AllStudios(ctx context.Context) ([]*Studio, error)
AllTags(ctx context.Context) ([]*Tag, error) AllTags(ctx context.Context) ([]*Tag, error)
Version(ctx context.Context) (*Version, error)
} }
type SceneResolver interface { type SceneResolver interface {
Title(ctx context.Context, obj *Scene) (*string, error) 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 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": case "Scene.checksum":
if e.complexity.Scene.Checksum == nil { if e.complexity.Scene.Checksum == nil {
break break
@@ -1681,6 +1695,20 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Tag.SceneMarkerCount(childComplexity), true 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 return 0, false
} }
@@ -1857,6 +1885,9 @@ type Query {
allPerformers: [Performer!]! allPerformers: [Performer!]!
allStudios: [Studio!]! allStudios: [Studio!]!
allTags: [Tag!]! allTags: [Tag!]!
# Version
version: Version!
} }
type Mutation { type Mutation {
@@ -2273,6 +2304,10 @@ input TagUpdateInput {
input TagDestroyInput { input TagDestroyInput {
id: ID! 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) 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 { func (ec *executionContext) _Query___type(ctx context.Context, field graphql.CollectedField) graphql.Marshaler {
ctx = ec.Tracer.StartFieldExecution(ctx, field) ctx = ec.Tracer.StartFieldExecution(ctx, field)
defer func() { ec.Tracer.EndFieldExecution(ctx) }() 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) 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 { func (ec *executionContext) ___Directive_name(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) graphql.Marshaler {
ctx = ec.Tracer.StartFieldExecution(ctx, field) ctx = ec.Tracer.StartFieldExecution(ctx, field)
defer func() { ec.Tracer.EndFieldExecution(ctx) }() defer func() { ec.Tracer.EndFieldExecution(ctx) }()
@@ -9890,6 +10006,20 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr
} }
return res 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": case "__type":
out.Values[i] = ec._Query___type(ctx, field) out.Values[i] = ec._Query___type(ctx, field)
case "__schema": case "__schema":
@@ -10566,6 +10696,38 @@ func (ec *executionContext) _Tag(ctx context.Context, sel ast.SelectionSet, obj
return out 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"} var __DirectiveImplementors = []string{"__Directive"}
func (ec *executionContext) ___Directive(ctx context.Context, sel ast.SelectionSet, obj *introspection.Directive) graphql.Marshaler { 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) 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 { 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) return ec.___Directive(ctx, sel, &v)
} }

View File

@@ -283,6 +283,11 @@ type TagUpdateInput struct {
Name string `json:"name"` Name string `json:"name"`
} }
type Version struct {
Hash string `json:"hash"`
BuildTime string `json:"build_time"`
}
type CriterionModifier string type CriterionModifier string
const ( const (

View File

@@ -2,18 +2,45 @@ import {
H1, H1,
H4, H4,
H6, H6,
HTMLTable,
Spinner,
Tag, Tag,
} from "@blueprintjs/core"; } from "@blueprintjs/core";
import React, { FunctionComponent } from "react"; import React, { FunctionComponent } from "react";
import * as GQL from "../../core/generated-graphql"; import * as GQL from "../../core/generated-graphql";
import { TextUtils } from "../../utils/text"; import { TextUtils } from "../../utils/text";
import { StashService } from "../../core/StashService";
interface IProps {} interface IProps {}
export const SettingsAboutPanel: FunctionComponent<IProps> = (props: IProps) => { export const SettingsAboutPanel: FunctionComponent<IProps> = (props: IProps) => {
const { data, error, loading } = StashService.useVersion();
function renderVersion() {
if (!data || !data.version) { return; }
return (
<>
<HTMLTable>
<tbody>
<tr>
<td>Build hash:</td>
<td>{data.version.hash}</td>
</tr>
<tr>
<td>Build time:</td>
<td>{data.version.build_time}</td>
</tr>
</tbody>
</HTMLTable>
</>
);
}
return ( return (
<> <>
About <H4>About</H4>
{!data || loading ? <Spinner size={Spinner.SIZE_LARGE} /> : undefined}
{!!error ? <span>error.message</span> : undefined}
{renderVersion()}
</> </>
); );
}; };

View File

@@ -123,6 +123,7 @@ export class StashService {
return GQL.useValidGalleriesForScene({variables: {scene_id: sceneId}}); return GQL.useValidGalleriesForScene({variables: {scene_id: sceneId}});
} }
public static useStats() { return GQL.useStats(); } public static useStats() { return GQL.useStats(); }
public static useVersion() { return GQL.useVersion(); }
public static useConfiguration() { return GQL.useConfiguration(); } public static useConfiguration() { return GQL.useConfiguration(); }
public static useDirectories(path?: string) { return GQL.useDirectories({ variables: { path }}); } public static useDirectories(path?: string) { return GQL.useDirectories({ variables: { path }}); }

View File

@@ -1,6 +1,6 @@
/* tslint:disable */ /* tslint:disable */
/* eslint-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> = T | undefined; export type Maybe<T> = T | undefined;
export interface SceneFilterType { export interface SceneFilterType {
@@ -657,6 +657,22 @@ export type StatsStats = {
tag_count: number; 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 = { export type FindPerformersVariables = {
filter?: Maybe<FindFilterType>; filter?: Maybe<FindFilterType>;
performer_filter?: Maybe<PerformerFilterType>; performer_filter?: Maybe<PerformerFilterType>;
@@ -2141,6 +2157,22 @@ export function useStats(
baseOptions baseOptions
); );
} }
export const VersionDocument = gql`
query Version {
version {
hash
build_time
}
}
`;
export function useVersion(
baseOptions?: ReactApolloHooks.QueryHookOptions<VersionVariables>
) {
return ReactApolloHooks.useQuery<VersionQuery, VersionVariables>(
VersionDocument,
baseOptions
);
}
export const FindPerformersDocument = gql` export const FindPerformersDocument = gql`
query FindPerformers( query FindPerformers(
$filter: FindFilterType $filter: FindFilterType