From 03cc6a60a7e15d5efd134e7b7892e1e371ff5c09 Mon Sep 17 00:00:00 2001 From: Kevin Kandlbinder Date: Wed, 7 Sep 2022 16:12:09 +0200 Subject: [PATCH] webui: Add basis for Hashing Controls --- graph/generated/generated.go | 107 ++++++++- graph/model/room.go | 15 +- graph/schema.graphqls | 2 +- graph/schema.resolvers.go | 83 +++++++ webui/data/schema.graphql | 2 +- webui/src/App.tsx | 38 ++- .../panel/hashing/entries/Entries.module.scss | 77 ++++++ .../panel/hashing/entries/Entries.tsx | 61 +++++ .../hashing/entries/EntriesTable.module.scss | 5 + .../panel/hashing/entries/EntriesTable.tsx | 50 ++++ .../hashing/entries/EntryDetail.module.scss | 47 ++++ .../panel/hashing/entries/EntryDetail.tsx | 171 ++++++++++++++ .../__generated__/EntriesQuery.graphql.ts | 186 +++++++++++++++ .../EntriesTableFragment.graphql.ts | 163 +++++++++++++ .../__generated__/EntryDetailQuery.graphql.ts | 97 ++++++++ .../hashing/lists/ListDetail.module.scss | 47 ++++ .../panel/hashing/lists/ListDetail.tsx | 186 +++++++++++++++ .../panel/hashing/lists/Lists.module.scss | 77 ++++++ .../components/panel/hashing/lists/Lists.tsx | 61 +++++ .../hashing/lists/ListsTable.module.scss | 5 + .../panel/hashing/lists/ListsTable.tsx | 60 +++++ .../__generated__/ListDetailQuery.graphql.ts | 185 +++++++++++++++ .../lists/__generated__/ListsQuery.graphql.ts | 220 ++++++++++++++++++ .../ListsTableFragment.graphql.ts | 203 ++++++++++++++++ .../src/components/panel/rooms/RoomDetail.tsx | 30 +-- .../__generated__/RoomDetailQuery.graphql.ts | 93 ++++++-- webui/src/index.tsx | 8 +- .../src/mutations/ReconfigureRoomMutation.ts | 10 +- .../ReconfigureRoomMutation.graphql.ts | 101 ++++++-- 29 files changed, 2292 insertions(+), 98 deletions(-) create mode 100644 webui/src/components/panel/hashing/entries/Entries.module.scss create mode 100644 webui/src/components/panel/hashing/entries/Entries.tsx create mode 100644 webui/src/components/panel/hashing/entries/EntriesTable.module.scss create mode 100644 webui/src/components/panel/hashing/entries/EntriesTable.tsx create mode 100644 webui/src/components/panel/hashing/entries/EntryDetail.module.scss create mode 100644 webui/src/components/panel/hashing/entries/EntryDetail.tsx create mode 100644 webui/src/components/panel/hashing/entries/__generated__/EntriesQuery.graphql.ts create mode 100644 webui/src/components/panel/hashing/entries/__generated__/EntriesTableFragment.graphql.ts create mode 100644 webui/src/components/panel/hashing/entries/__generated__/EntryDetailQuery.graphql.ts create mode 100644 webui/src/components/panel/hashing/lists/ListDetail.module.scss create mode 100644 webui/src/components/panel/hashing/lists/ListDetail.tsx create mode 100644 webui/src/components/panel/hashing/lists/Lists.module.scss create mode 100644 webui/src/components/panel/hashing/lists/Lists.tsx create mode 100644 webui/src/components/panel/hashing/lists/ListsTable.module.scss create mode 100644 webui/src/components/panel/hashing/lists/ListsTable.tsx create mode 100644 webui/src/components/panel/hashing/lists/__generated__/ListDetailQuery.graphql.ts create mode 100644 webui/src/components/panel/hashing/lists/__generated__/ListsQuery.graphql.ts create mode 100644 webui/src/components/panel/hashing/lists/__generated__/ListsTableFragment.graphql.ts diff --git a/graph/generated/generated.go b/graph/generated/generated.go index 1a50636..c0d20b4 100644 --- a/graph/generated/generated.go +++ b/graph/generated/generated.go @@ -39,6 +39,7 @@ type Config struct { type ResolverRoot interface { Comment() CommentResolver Entry() EntryResolver + HashCheckerConfig() HashCheckerConfigResolver List() ListResolver Mutation() MutationResolver Query() QueryResolver @@ -90,7 +91,7 @@ type ComplexityRoot struct { HashCheckerConfig struct { ChatNotice func(childComplexity int) int HashCheckMode func(childComplexity int) int - SubscribedLists func(childComplexity int) int + SubscribedLists func(childComplexity int, first *int, after *string) int } List struct { @@ -198,6 +199,9 @@ type EntryResolver interface { AddedBy(ctx context.Context, obj *model.Entry) (*model.User, error) Comments(ctx context.Context, obj *model.Entry, first *int, after *string) (*model.CommentConnection, error) } +type HashCheckerConfigResolver interface { + SubscribedLists(ctx context.Context, obj *model.HashCheckerConfig, first *int, after *string) (*model.ListConnection, error) +} type ListResolver interface { Creator(ctx context.Context, obj *model.List) (*model.User, error) Comments(ctx context.Context, obj *model.List, first *int, after *string) (*model.CommentConnection, error) @@ -402,7 +406,12 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in break } - return e.complexity.HashCheckerConfig.SubscribedLists(childComplexity), true + args, err := ec.field_HashCheckerConfig_subscribedLists_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.HashCheckerConfig.SubscribedLists(childComplexity, args["first"].(*int), args["after"].(*string)), true case "List.comments": if e.complexity.List.Comments == nil { @@ -1081,7 +1090,7 @@ enum HashCheckerMode { type HashCheckerConfig { chatNotice: Boolean! hashCheckMode: HashCheckerMode! - subscribedLists: [ID!] + subscribedLists(first: Int, after: String): ListConnection! } type Room { @@ -1457,6 +1466,30 @@ func (ec *executionContext) field_Entry_partOf_args(ctx context.Context, rawArgs return args, nil } +func (ec *executionContext) field_HashCheckerConfig_subscribedLists_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 *int + if tmp, ok := rawArgs["first"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("first")) + arg0, err = ec.unmarshalOInt2ᚖint(ctx, tmp) + if err != nil { + return nil, err + } + } + args["first"] = arg0 + var arg1 *string + if tmp, ok := rawArgs["after"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("after")) + arg1, err = ec.unmarshalOString2ᚖstring(ctx, tmp) + if err != nil { + return nil, err + } + } + args["after"] = arg1 + return args, nil +} + func (ec *executionContext) field_List_comments_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -3037,30 +3070,50 @@ func (ec *executionContext) _HashCheckerConfig_subscribedLists(ctx context.Conte }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.SubscribedLists, nil + return ec.resolvers.HashCheckerConfig().SubscribedLists(rctx, obj, fc.Args["first"].(*int), fc.Args["after"].(*string)) }) if err != nil { ec.Error(ctx, err) return graphql.Null } if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } return graphql.Null } - res := resTmp.([]string) + res := resTmp.(*model.ListConnection) fc.Result = res - return ec.marshalOID2ᚕstringᚄ(ctx, field.Selections, res) + return ec.marshalNListConnection2ᚖgithubᚗcomᚋUnkn0wnCatᚋmatrixᚑvelesᚋgraphᚋmodelᚐListConnection(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_HashCheckerConfig_subscribedLists(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "HashCheckerConfig", Field: field, - IsMethod: false, - IsResolver: false, + IsMethod: true, + IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type ID does not have child fields") + switch field.Name { + case "pageInfo": + return ec.fieldContext_ListConnection_pageInfo(ctx, field) + case "edges": + return ec.fieldContext_ListConnection_edges(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type ListConnection", field.Name) }, } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_HashCheckerConfig_subscribedLists_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return + } return fc, nil } @@ -10224,19 +10277,35 @@ func (ec *executionContext) _HashCheckerConfig(ctx context.Context, sel ast.Sele out.Values[i] = ec._HashCheckerConfig_chatNotice(ctx, field, obj) if out.Values[i] == graphql.Null { - invalids++ + atomic.AddUint32(&invalids, 1) } case "hashCheckMode": out.Values[i] = ec._HashCheckerConfig_hashCheckMode(ctx, field, obj) if out.Values[i] == graphql.Null { - invalids++ + atomic.AddUint32(&invalids, 1) } case "subscribedLists": + field := field - out.Values[i] = ec._HashCheckerConfig_subscribedLists(ctx, field, obj) + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._HashCheckerConfig_subscribedLists(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + out.Concurrently(i, func() graphql.Marshaler { + return innerFunc(ctx) + + }) default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -11713,6 +11782,20 @@ func (ec *executionContext) marshalNList2ᚖgithubᚗcomᚋUnkn0wnCatᚋmatrix return ec._List(ctx, sel, v) } +func (ec *executionContext) marshalNListConnection2githubᚗcomᚋUnkn0wnCatᚋmatrixᚑvelesᚋgraphᚋmodelᚐListConnection(ctx context.Context, sel ast.SelectionSet, v model.ListConnection) graphql.Marshaler { + return ec._ListConnection(ctx, sel, &v) +} + +func (ec *executionContext) marshalNListConnection2ᚖgithubᚗcomᚋUnkn0wnCatᚋmatrixᚑvelesᚋgraphᚋmodelᚐListConnection(ctx context.Context, sel ast.SelectionSet, v *model.ListConnection) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._ListConnection(ctx, sel, v) +} + func (ec *executionContext) marshalNListEdge2ᚕᚖgithubᚗcomᚋUnkn0wnCatᚋmatrixᚑvelesᚋgraphᚋmodelᚐListEdgeᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.ListEdge) graphql.Marshaler { ret := make(graphql.Array, len(v)) var wg sync.WaitGroup diff --git a/graph/model/room.go b/graph/model/room.go index 94e3e82..8faf3ac 100644 --- a/graph/model/room.go +++ b/graph/model/room.go @@ -1,6 +1,9 @@ package model -import "github.com/Unkn0wnCat/matrix-veles/internal/config" +import ( + "github.com/Unkn0wnCat/matrix-veles/internal/config" + "go.mongodb.org/mongo-driver/bson/primitive" +) type Room struct { ID string `json:"id"` @@ -16,16 +19,10 @@ type Room struct { type HashCheckerConfig struct { ChatNotice bool `json:"chatNotice"` HashCheckMode HashCheckerMode `json:"hashCheckMode"` - SubscribedLists []string `json:"subscribedLists"` + SubscribedLists []*primitive.ObjectID } func MakeRoom(room *config.RoomConfig) *Room { - var subscribed []string - - for _, subId := range room.HashChecker.SubscribedLists { - subscribed = append(subscribed, subId.Hex()) - } - return &Room{ ID: room.ID.Hex(), Name: room.Name, @@ -37,7 +34,7 @@ func MakeRoom(room *config.RoomConfig) *Room { HashCheckerConfig: &HashCheckerConfig{ ChatNotice: room.HashChecker.NoticeToChat, HashCheckMode: AllHashCheckerMode[room.HashChecker.HashCheckMode], - SubscribedLists: subscribed, + SubscribedLists: room.HashChecker.SubscribedLists, }, } } diff --git a/graph/schema.graphqls b/graph/schema.graphqls index a8d81e7..a551fca 100644 --- a/graph/schema.graphqls +++ b/graph/schema.graphqls @@ -40,7 +40,7 @@ enum HashCheckerMode { type HashCheckerConfig { chatNotice: Boolean! hashCheckMode: HashCheckerMode! - subscribedLists: [ID!] + subscribedLists(first: Int, after: String): ListConnection! } type Room { diff --git a/graph/schema.resolvers.go b/graph/schema.resolvers.go index ccb3e73..88497dc 100644 --- a/graph/schema.resolvers.go +++ b/graph/schema.resolvers.go @@ -136,6 +136,83 @@ func (r *entryResolver) Comments(ctx context.Context, obj *model.Entry, first *i return ResolveComments(comments, first, after) } +// SubscribedLists is the resolver for the subscribedLists field. +func (r *hashCheckerConfigResolver) SubscribedLists(ctx context.Context, obj *model.HashCheckerConfig, first *int, after *string) (*model.ListConnection, error) { + ids := obj.SubscribedLists + + if len(ids) == 0 { + return nil, nil + } + + startIndex := 0 + + if after != nil { + afterInt := new(big.Int) + afterInt.SetString(*after, 16) + + idInt := new(big.Int) + + set := false + + for i, id := range obj.SubscribedLists { + idInt.SetString(id.Hex(), 16) + + if idInt.Cmp(afterInt) > 0 { + startIndex = i + set = true + break + } + } + + if !set { + return nil, nil + } + } + + if startIndex >= len(ids) { + return nil, nil + } + + ids = ids[startIndex:] + + length := 25 + + if first != nil { + length = *first + } + + cut := false + + if len(ids) > length { + cut = true + ids = ids[:length] + } + + var edges []*model.ListEdge + + for _, id := range ids { + dbList, err := db.GetListByID(*id) + if err != nil { + return nil, err + } + + edges = append(edges, &model.ListEdge{ + Node: model.MakeList(dbList), + Cursor: dbList.ID.Hex(), + }) + } + + return &model.ListConnection{ + PageInfo: &model.PageInfo{ + HasPreviousPage: startIndex > 0, + HasNextPage: cut, + StartCursor: edges[0].Cursor, + EndCursor: edges[len(edges)-1].Cursor, + }, + Edges: edges, + }, nil +} + // Creator is the resolver for the creator field. func (r *listResolver) Creator(ctx context.Context, obj *model.List) (*model.User, error) { user, err := db.GetUserByID(obj.CreatorID) @@ -1359,6 +1436,11 @@ func (r *Resolver) Comment() generated.CommentResolver { return &commentResolver // Entry returns generated.EntryResolver implementation. func (r *Resolver) Entry() generated.EntryResolver { return &entryResolver{r} } +// HashCheckerConfig returns generated.HashCheckerConfigResolver implementation. +func (r *Resolver) HashCheckerConfig() generated.HashCheckerConfigResolver { + return &hashCheckerConfigResolver{r} +} + // List returns generated.ListResolver implementation. func (r *Resolver) List() generated.ListResolver { return &listResolver{r} } @@ -1370,6 +1452,7 @@ func (r *Resolver) Query() generated.QueryResolver { return &queryResolver{r} } type commentResolver struct{ *Resolver } type entryResolver struct{ *Resolver } +type hashCheckerConfigResolver struct{ *Resolver } type listResolver struct{ *Resolver } type mutationResolver struct{ *Resolver } type queryResolver struct{ *Resolver } diff --git a/webui/data/schema.graphql b/webui/data/schema.graphql index a8d81e7..a551fca 100644 --- a/webui/data/schema.graphql +++ b/webui/data/schema.graphql @@ -40,7 +40,7 @@ enum HashCheckerMode { type HashCheckerConfig { chatNotice: Boolean! hashCheckMode: HashCheckerMode! - subscribedLists: [ID!] + subscribedLists(first: Int, after: String): ListConnection! } type Room { diff --git a/webui/src/App.tsx b/webui/src/App.tsx index 5408386..ef555d5 100644 --- a/webui/src/App.tsx +++ b/webui/src/App.tsx @@ -18,6 +18,14 @@ import Rooms from "./components/panel/rooms/Rooms"; import RoomsQueryGraphql, {RoomsQuery} from "./components/panel/rooms/__generated__/RoomsQuery.graphql"; import RoomDetailQueryGraphql, {RoomDetailQuery} from "./components/panel/rooms/__generated__/RoomDetailQuery.graphql"; import RoomDetail from "./components/panel/rooms/RoomDetail"; +import ListsQueryGraphql, {ListsQuery} from "./components/panel/hashing/lists/__generated__/ListsQuery.graphql"; +import ListDetailQueryGraphql, {ListDetailQuery} from "./components/panel/hashing/lists/__generated__/ListDetailQuery.graphql"; +import Lists from "./components/panel/hashing/lists/Lists"; +import ListDetail from "./components/panel/hashing/lists/ListDetail"; +import EntriesQueryGraphql, {EntriesQuery} from "./components/panel/hashing/entries/__generated__/EntriesQuery.graphql"; +import EntryDetailQueryGraphql, {EntryDetailQuery} from "./components/panel/hashing/entries/__generated__/EntryDetailQuery.graphql"; +import Entries from "./components/panel/hashing/entries/Entries"; +import EntryDetail from "./components/panel/hashing/entries/EntryDetail"; function App() { const dispatch = useAppDispatch() @@ -37,6 +45,22 @@ function App() { RoomDetailQueryGraphql ) + const [listsInitialState, loadListsQuery, disposeListsQuery] = useQueryLoader( + ListsQueryGraphql + ) + + const [listDetailInitialState, loadListDetailQuery, disposeListDetailQuery] = useQueryLoader( + ListDetailQueryGraphql + ) + + const [entriesInitialState, loadEntriesQuery, disposeEntriesQuery] = useQueryLoader( + EntriesQueryGraphql + ) + + const [entryDetailInitialState, loadEntryDetailQuery, disposeEntryDetailQuery] = useQueryLoader( + EntryDetailQueryGraphql + ) + // This needs to be here to prevent a weird bug useTranslation() @@ -50,13 +74,17 @@ function App() { if(auth.jwt !== null) { loadQuery({}) loadRoomsQuery({}) + loadListsQuery({}) + loadEntriesQuery({}) return } disposeQuery() disposeRoomsQuery() + disposeListsQuery() + disposeEntriesQuery() environment.getStore().notify(undefined, true) - }, [auth, disposeQuery, disposeRoomsQuery, environment, loadQuery, loadRoomsQuery]) + }, [auth, disposeQuery, disposeRoomsQuery, environment, loadQuery, loadRoomsQuery, loadListsQuery, disposeListsQuery, loadEntriesQuery, disposeEntriesQuery]) return ( @@ -70,11 +98,11 @@ function App() { {roomsInitialState && }}> } /> -

lists

}> - list detail} /> + {listsInitialState && }}> + } /> -

entries

}> - entry detail} /> + {entriesInitialState && }}> + } /> diff --git a/webui/src/components/panel/hashing/entries/Entries.module.scss b/webui/src/components/panel/hashing/entries/Entries.module.scss new file mode 100644 index 0000000..d245ef5 --- /dev/null +++ b/webui/src/components/panel/hashing/entries/Entries.module.scss @@ -0,0 +1,77 @@ +@import "../../../../globals"; + +$slideOverBreakpoint: 1000px; + +.roomsContainer { + display: flex; + height: calc(100% + 2*var(--veles-layout-padding)); + margin: var(--veles-layout-padding-inverse); + width: calc(100% + 2*var(--veles-layout-padding)); + overflow: hidden; + + .roomsOverview { + flex-grow: 1; + flex-shrink: 1; + width: 100px; + padding: var(--veles-layout-padding); + transition: margin-right .25s; + + &.leaveSpace { + margin-right: 400px; + + @media(max-width: $slideOverBreakpoint) { + margin-right: 0; + } + } + } + + .slideOver { + position: absolute; + top: 0; + right: -400px; + height: 100%; + width: 400px; + border-left: thin solid var(--veles-color-border); + transition: right .25s, border-left .25s, width .25s; + + @media(max-width: $slideOverBreakpoint) { + width: 100%; + border-left: 0 solid var(--veles-color-border); + margin-right: 0; + right: -100%; + } + + background-color: var(--veles-color-background); + + &.active { + right: 0; + } + + .slideOverContent { + padding: var(--veles-layout-padding); + } + + .slideOverHeader { + display: flex; + border-bottom: thin solid var(--veles-color-border); + align-items: center; + + >* { + padding: var(--veles-layout-padding-slim) var(--veles-layout-padding); + } + + > span { + flex-grow: 1; + } + + > button { + margin: 0; + background: transparent; + font: inherit; + color: inherit; + border: none; + cursor: pointer; + } + } + } +} \ No newline at end of file diff --git a/webui/src/components/panel/hashing/entries/Entries.tsx b/webui/src/components/panel/hashing/entries/Entries.tsx new file mode 100644 index 0000000..d2f3028 --- /dev/null +++ b/webui/src/components/panel/hashing/entries/Entries.tsx @@ -0,0 +1,61 @@ +import React, {useState} from "react"; +import {useNavigate, useOutlet} from "react-router-dom"; + +import styles from "./Entries.module.scss"; +import {Trans, useTranslation} from "react-i18next"; +import EntriesTable from "./EntriesTable"; +import {PreloadedQuery, usePreloadedQuery} from "react-relay/hooks"; +import {graphql} from "babel-plugin-relay/macro"; +import {EntriesQuery} from "./__generated__/EntriesQuery.graphql"; +import {X} from "lucide-react"; +import {LoaderSuspense} from "../../../common/Loader"; + +type Props = { + initialQueryRef: PreloadedQuery, +} + +const Entries = ({initialQueryRef}: Props) => { + const outlet = useOutlet() + const navigate = useNavigate() + const {t} = useTranslation() + + const data = usePreloadedQuery( + graphql` + query EntriesQuery($first: String, $count: Int) { + ...EntriesTableFragment + } + `, + initialQueryRef + ) + + const defaultTitle = t("entries.details", "Details") + + const [title, setTitle] = useState(defaultTitle) + + + return
+
+

Entry Management

+ + +
+ +
+ +
+ {title} + +
+
+ + {outlet} + +
+
+
+
+} + +export const EntriesSlideOverTitleContext = React.createContext>|null>(null) + +export default Entries \ No newline at end of file diff --git a/webui/src/components/panel/hashing/entries/EntriesTable.module.scss b/webui/src/components/panel/hashing/entries/EntriesTable.module.scss new file mode 100644 index 0000000..1b8c6c6 --- /dev/null +++ b/webui/src/components/panel/hashing/entries/EntriesTable.module.scss @@ -0,0 +1,5 @@ +@import "../../../../globals"; + +.roomsTableWrapper { + @include tableWrapper; +} diff --git a/webui/src/components/panel/hashing/entries/EntriesTable.tsx b/webui/src/components/panel/hashing/entries/EntriesTable.tsx new file mode 100644 index 0000000..8045d8b --- /dev/null +++ b/webui/src/components/panel/hashing/entries/EntriesTable.tsx @@ -0,0 +1,50 @@ +import React from "react"; +import {usePaginationFragment} from "react-relay/hooks"; +import {graphql} from "babel-plugin-relay/macro"; +import {EntriesTableFragment$key} from "./__generated__/EntriesTableFragment.graphql"; +import styles from "./EntriesTable.module.scss"; +import {useNavigate} from "react-router-dom"; +import {Trans} from "react-i18next"; + +type Props = { + initialQueryRef: EntriesTableFragment$key, +} + +const EntriesTable = ({initialQueryRef}: Props) => { + const {data} = usePaginationFragment(graphql` + fragment EntriesTableFragment on Query @refetchable(queryName: "EntriesTableFragment") { + entries(after: $first, first: $count) @connection(key: "EntriesTableFragment_entries") { + edges { + node { + id + tags + } + } + } + } + `, initialQueryRef) + + const navigate = useNavigate() + + return
+ + + + + + + + { + data.entries?.edges.map((edge) => { + return {navigate("/hashing/entries/"+edge.node.id)}} key={edge.node.id}> + + ; + }) + } + + +
Entry ID
{edge.node.id}
+
+} + +export default EntriesTable \ No newline at end of file diff --git a/webui/src/components/panel/hashing/entries/EntryDetail.module.scss b/webui/src/components/panel/hashing/entries/EntryDetail.module.scss new file mode 100644 index 0000000..0b58e8a --- /dev/null +++ b/webui/src/components/panel/hashing/entries/EntryDetail.module.scss @@ -0,0 +1,47 @@ +@import "../../../../globals"; + +.title { + display: flex; + gap: var(--veles-layout-padding) +} + +.label { + display: block; + padding: var(--veles-layout-padding-slim); +} + +.powerLevelInput { + @include inputGroup; + + input { + flex-grow: 1; + } +} + +.hashCheckModeChooser { + @include input; + width: 100%; +} + +.listTable { + @include tableWrapper; + padding: var(--veles-layout-padding); +} + +.settingsGroup { + display: block; + margin: var(--veles-layout-padding) var(--veles-layout-padding-inverse); + + border-top: thin solid var(--veles-color-border); + border-bottom: thin solid var(--veles-color-border); + + .settingsGroupTitle { + display: block; + border-bottom: thin solid var(--veles-color-border); + padding: var(--veles-layout-padding-slim) var(--veles-layout-padding); + } + + .settingsGroupContent { + padding: var(--veles-layout-padding); + } +} \ No newline at end of file diff --git a/webui/src/components/panel/hashing/entries/EntryDetail.tsx b/webui/src/components/panel/hashing/entries/EntryDetail.tsx new file mode 100644 index 0000000..3b47b0f --- /dev/null +++ b/webui/src/components/panel/hashing/entries/EntryDetail.tsx @@ -0,0 +1,171 @@ +import React, {useContext, useEffect} from "react"; +import {PreloadedQuery, usePreloadedQuery} from "react-relay/hooks"; +import {graphql} from "babel-plugin-relay/macro"; +import {EntryDetailQuery, EntryDetailQuery$variables} from "./__generated__/EntryDetailQuery.graphql"; +import {DisposeFn} from "relay-runtime"; +import {useParams} from "react-router-dom"; +import {EntriesSlideOverTitleContext} from "./Entries"; + +//import styles from "./EntryDetail.module.scss"; + +type Props = { + initialQueryRef: PreloadedQuery | null | undefined, + fetch: (variables: EntryDetailQuery$variables) => void + dispose: DisposeFn +} + +type PropsFinal = { + initialQueryRef: PreloadedQuery, +} + +const RoomDetailInner = ({initialQueryRef}: PropsFinal) => { + /*const {t} = useTranslation() + const navigate = useNavigate()*/ + + + const data = usePreloadedQuery( + graphql` + query EntryDetailQuery($id: ID) { + entry(id:$id) { + id + tags + } + } + `, + initialQueryRef + ) + + const titleSetContext = useContext(EntriesSlideOverTitleContext) + + titleSetContext && data.entry?.id && titleSetContext(data.entry.id); + + return <> +
{JSON.stringify(data, null, 2)}
+ + + /*return <> + { + reconfigureRoom({ + variables: { + reconfigureInput: { + id: data.room?.id!, + deactivate: !ev.currentTarget.checked + } + } + }) + }} disabled={reconfiguringRoom || ((data.room || false) && !data.room.active && !data.room.deactivated)} checked={data.room?.active}/> + + { + reconfigureRoom({ + variables: { + reconfigureInput: { + id: data.room?.id!, + debug: ev.currentTarget.checked + } + } + }) + }} disabled={reconfiguringRoom || (!data.room)} checked={data.room?.debug}/> + + +
+ { + if(Number.parseInt(ev.currentTarget.value) === data.room?.adminPowerLevel) { + setNewAdminPowerLevel(null) + return + } + + setNewAdminPowerLevel(Number.parseInt(ev.currentTarget.value)) + }} id={"adminPowerLevelInput"} /> + +
+ +
+ Hash-Checker +
+ { + reconfigureRoom({ + variables: { + reconfigureInput: { + id: data.room?.id!, + hashChecker: { + chatNotice: ev.currentTarget.checked + } + } + } + }) + }} disabled={reconfiguringRoom || (!data.room)} checked={data.room?.hashCheckerConfig.chatNotice}/> + + + +
+ +
+ + + + + + + + + { + data.room?.hashCheckerConfig.subscribedLists.edges.map((edge) => { + return {navigate("/hashing/lists/"+edge.node.id)}} key={edge.node.id}> + + + ; + }) + } + +
NameList ID
{edge.node.name}{edge.node.id}
+
+
+ */ +} + +const EntryDetail = ({initialQueryRef, fetch, dispose}: Props) => { + const {id} = useParams() + + useEffect(() => { + fetch({id}) + + return () => { + dispose(); + } + }, [id, dispose, fetch]) + + return initialQueryRef ? : null +} + +export default EntryDetail; \ No newline at end of file diff --git a/webui/src/components/panel/hashing/entries/__generated__/EntriesQuery.graphql.ts b/webui/src/components/panel/hashing/entries/__generated__/EntriesQuery.graphql.ts new file mode 100644 index 0000000..9be1221 --- /dev/null +++ b/webui/src/components/panel/hashing/entries/__generated__/EntriesQuery.graphql.ts @@ -0,0 +1,186 @@ +/** + * @generated SignedSource<<0d6e62e3c8c5ff07cb1c9f683624d372>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ConcreteRequest, Query } from 'relay-runtime'; +import { FragmentRefs } from "relay-runtime"; +export type EntriesQuery$variables = { + first?: string | null; + count?: number | null; +}; +export type EntriesQuery$data = { + readonly " $fragmentSpreads": FragmentRefs<"EntriesTableFragment">; +}; +export type EntriesQuery = { + variables: EntriesQuery$variables; + response: EntriesQuery$data; +}; + +const node: ConcreteRequest = (function(){ +var v0 = { + "defaultValue": null, + "kind": "LocalArgument", + "name": "count" +}, +v1 = { + "defaultValue": null, + "kind": "LocalArgument", + "name": "first" +}, +v2 = [ + { + "kind": "Variable", + "name": "after", + "variableName": "first" + }, + { + "kind": "Variable", + "name": "first", + "variableName": "count" + } +]; +return { + "fragment": { + "argumentDefinitions": [ + (v0/*: any*/), + (v1/*: any*/) + ], + "kind": "Fragment", + "metadata": null, + "name": "EntriesQuery", + "selections": [ + { + "args": null, + "kind": "FragmentSpread", + "name": "EntriesTableFragment" + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [ + (v1/*: any*/), + (v0/*: any*/) + ], + "kind": "Operation", + "name": "EntriesQuery", + "selections": [ + { + "alias": null, + "args": (v2/*: any*/), + "concreteType": "EntryConnection", + "kind": "LinkedField", + "name": "entries", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "EntryEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "Entry", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "tags", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null + } + ], + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "cursor", + "storageKey": null + } + ], + "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "PageInfo", + "kind": "LinkedField", + "name": "pageInfo", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "endCursor", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "hasNextPage", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + }, + { + "alias": null, + "args": (v2/*: any*/), + "filters": null, + "handle": "connection", + "key": "EntriesTableFragment_entries", + "kind": "LinkedHandle", + "name": "entries" + } + ] + }, + "params": { + "cacheID": "cb7fcbe76a323cc0ce2ae532aa6fa861", + "id": null, + "metadata": {}, + "name": "EntriesQuery", + "operationKind": "query", + "text": "query EntriesQuery(\n $first: String\n $count: Int\n) {\n ...EntriesTableFragment\n}\n\nfragment EntriesTableFragment on Query {\n entries(after: $first, first: $count) {\n edges {\n node {\n id\n tags\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n" + } +}; +})(); + +(node as any).hash = "06398f7547759ada0c2066a0d13cf04c"; + +export default node; diff --git a/webui/src/components/panel/hashing/entries/__generated__/EntriesTableFragment.graphql.ts b/webui/src/components/panel/hashing/entries/__generated__/EntriesTableFragment.graphql.ts new file mode 100644 index 0000000..a4cb212 --- /dev/null +++ b/webui/src/components/panel/hashing/entries/__generated__/EntriesTableFragment.graphql.ts @@ -0,0 +1,163 @@ +/** + * @generated SignedSource<<38a8e1d2b568b81072536ddacd114e6f>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ReaderFragment, RefetchableFragment } from 'relay-runtime'; +import { FragmentRefs } from "relay-runtime"; +export type EntriesTableFragment$data = { + readonly entries: { + readonly edges: ReadonlyArray<{ + readonly node: { + readonly id: string; + readonly tags: ReadonlyArray | null; + }; + }>; + } | null; + readonly " $fragmentType": "EntriesTableFragment"; +}; +export type EntriesTableFragment$key = { + readonly " $data"?: EntriesTableFragment$data; + readonly " $fragmentSpreads": FragmentRefs<"EntriesTableFragment">; +}; + +const node: ReaderFragment = (function(){ +var v0 = [ + "entries" +]; +return { + "argumentDefinitions": [ + { + "kind": "RootArgument", + "name": "count" + }, + { + "kind": "RootArgument", + "name": "first" + } + ], + "kind": "Fragment", + "metadata": { + "connection": [ + { + "count": "count", + "cursor": "first", + "direction": "forward", + "path": (v0/*: any*/) + } + ], + "refetch": { + "connection": { + "forward": { + "count": "count", + "cursor": "first" + }, + "backward": null, + "path": (v0/*: any*/) + }, + "fragmentPathInResult": [], + "operation": require('./EntriesTableFragment.graphql') + } + }, + "name": "EntriesTableFragment", + "selections": [ + { + "alias": "entries", + "args": null, + "concreteType": "EntryConnection", + "kind": "LinkedField", + "name": "__EntriesTableFragment_entries_connection", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "EntryEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "Entry", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "tags", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null + } + ], + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "cursor", + "storageKey": null + } + ], + "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "PageInfo", + "kind": "LinkedField", + "name": "pageInfo", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "endCursor", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "hasNextPage", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "type": "Query", + "abstractKey": null +}; +})(); + +(node as any).hash = "999faf383df2d42007f73da008f4c910"; + +export default node; diff --git a/webui/src/components/panel/hashing/entries/__generated__/EntryDetailQuery.graphql.ts b/webui/src/components/panel/hashing/entries/__generated__/EntryDetailQuery.graphql.ts new file mode 100644 index 0000000..695cac8 --- /dev/null +++ b/webui/src/components/panel/hashing/entries/__generated__/EntryDetailQuery.graphql.ts @@ -0,0 +1,97 @@ +/** + * @generated SignedSource<<5a8663de6323dd94e27c8d5b53db80eb>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ConcreteRequest, Query } from 'relay-runtime'; +export type EntryDetailQuery$variables = { + id?: string | null; +}; +export type EntryDetailQuery$data = { + readonly entry: { + readonly id: string; + readonly tags: ReadonlyArray | null; + } | null; +}; +export type EntryDetailQuery = { + variables: EntryDetailQuery$variables; + response: EntryDetailQuery$data; +}; + +const node: ConcreteRequest = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "id" + } +], +v1 = [ + { + "alias": null, + "args": [ + { + "kind": "Variable", + "name": "id", + "variableName": "id" + } + ], + "concreteType": "Entry", + "kind": "LinkedField", + "name": "entry", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "tags", + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "EntryDetailQuery", + "selections": (v1/*: any*/), + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "EntryDetailQuery", + "selections": (v1/*: any*/) + }, + "params": { + "cacheID": "1f01a8cbc9fbd149cc3511fbfb5a0929", + "id": null, + "metadata": {}, + "name": "EntryDetailQuery", + "operationKind": "query", + "text": "query EntryDetailQuery(\n $id: ID\n) {\n entry(id: $id) {\n id\n tags\n }\n}\n" + } +}; +})(); + +(node as any).hash = "2121d3309f0f6813613afae4a045e275"; + +export default node; diff --git a/webui/src/components/panel/hashing/lists/ListDetail.module.scss b/webui/src/components/panel/hashing/lists/ListDetail.module.scss new file mode 100644 index 0000000..0b58e8a --- /dev/null +++ b/webui/src/components/panel/hashing/lists/ListDetail.module.scss @@ -0,0 +1,47 @@ +@import "../../../../globals"; + +.title { + display: flex; + gap: var(--veles-layout-padding) +} + +.label { + display: block; + padding: var(--veles-layout-padding-slim); +} + +.powerLevelInput { + @include inputGroup; + + input { + flex-grow: 1; + } +} + +.hashCheckModeChooser { + @include input; + width: 100%; +} + +.listTable { + @include tableWrapper; + padding: var(--veles-layout-padding); +} + +.settingsGroup { + display: block; + margin: var(--veles-layout-padding) var(--veles-layout-padding-inverse); + + border-top: thin solid var(--veles-color-border); + border-bottom: thin solid var(--veles-color-border); + + .settingsGroupTitle { + display: block; + border-bottom: thin solid var(--veles-color-border); + padding: var(--veles-layout-padding-slim) var(--veles-layout-padding); + } + + .settingsGroupContent { + padding: var(--veles-layout-padding); + } +} \ No newline at end of file diff --git a/webui/src/components/panel/hashing/lists/ListDetail.tsx b/webui/src/components/panel/hashing/lists/ListDetail.tsx new file mode 100644 index 0000000..6eab001 --- /dev/null +++ b/webui/src/components/panel/hashing/lists/ListDetail.tsx @@ -0,0 +1,186 @@ +import React, {useContext, useEffect} from "react"; +import {PreloadedQuery, usePreloadedQuery} from "react-relay/hooks"; +import {graphql} from "babel-plugin-relay/macro"; +import {ListDetailQuery, ListDetailQuery$variables} from "./__generated__/ListDetailQuery.graphql"; +import {DisposeFn} from "relay-runtime"; +import {useParams} from "react-router-dom"; +import {ListsSlideOverTitleContext} from "./Lists"; + +//import styles from "./ListDetail.module.scss"; + +type Props = { + initialQueryRef: PreloadedQuery | null | undefined, + fetch: (variables: ListDetailQuery$variables) => void + dispose: DisposeFn +} + +type PropsFinal = { + initialQueryRef: PreloadedQuery, +} + +const RoomDetailInner = ({initialQueryRef}: PropsFinal) => { + /*const {t} = useTranslation() + const navigate = useNavigate()*/ + + + const data = usePreloadedQuery( + graphql` + query ListDetailQuery($id: ID) { + list(id:$id) { + id + name + tags + creator { + id + username + matrixLinks + } + maintainers(first: 100) { + edges { + node { + id + username + matrixLinks + } + } + } + } + } + `, + initialQueryRef + ) + + const titleSetContext = useContext(ListsSlideOverTitleContext) + + titleSetContext && data.list?.name && titleSetContext(data.list.name); + + return <> +
{JSON.stringify(data, null, 2)}
+ + + /*return <> + { + reconfigureRoom({ + variables: { + reconfigureInput: { + id: data.room?.id!, + deactivate: !ev.currentTarget.checked + } + } + }) + }} disabled={reconfiguringRoom || ((data.room || false) && !data.room.active && !data.room.deactivated)} checked={data.room?.active}/> + + { + reconfigureRoom({ + variables: { + reconfigureInput: { + id: data.room?.id!, + debug: ev.currentTarget.checked + } + } + }) + }} disabled={reconfiguringRoom || (!data.room)} checked={data.room?.debug}/> + + +
+ { + if(Number.parseInt(ev.currentTarget.value) === data.room?.adminPowerLevel) { + setNewAdminPowerLevel(null) + return + } + + setNewAdminPowerLevel(Number.parseInt(ev.currentTarget.value)) + }} id={"adminPowerLevelInput"} /> + +
+ +
+ Hash-Checker +
+ { + reconfigureRoom({ + variables: { + reconfigureInput: { + id: data.room?.id!, + hashChecker: { + chatNotice: ev.currentTarget.checked + } + } + } + }) + }} disabled={reconfiguringRoom || (!data.room)} checked={data.room?.hashCheckerConfig.chatNotice}/> + + + +
+ +
+ + + + + + + + + { + data.room?.hashCheckerConfig.subscribedLists.edges.map((edge) => { + return {navigate("/hashing/lists/"+edge.node.id)}} key={edge.node.id}> + + + ; + }) + } + +
NameList ID
{edge.node.name}{edge.node.id}
+
+
+ */ +} + +const ListDetail = ({initialQueryRef, fetch, dispose}: Props) => { + const {id} = useParams() + + useEffect(() => { + fetch({id}) + + return () => { + dispose(); + } + }, [id, dispose, fetch]) + + return initialQueryRef ? : null +} + +export default ListDetail; \ No newline at end of file diff --git a/webui/src/components/panel/hashing/lists/Lists.module.scss b/webui/src/components/panel/hashing/lists/Lists.module.scss new file mode 100644 index 0000000..d245ef5 --- /dev/null +++ b/webui/src/components/panel/hashing/lists/Lists.module.scss @@ -0,0 +1,77 @@ +@import "../../../../globals"; + +$slideOverBreakpoint: 1000px; + +.roomsContainer { + display: flex; + height: calc(100% + 2*var(--veles-layout-padding)); + margin: var(--veles-layout-padding-inverse); + width: calc(100% + 2*var(--veles-layout-padding)); + overflow: hidden; + + .roomsOverview { + flex-grow: 1; + flex-shrink: 1; + width: 100px; + padding: var(--veles-layout-padding); + transition: margin-right .25s; + + &.leaveSpace { + margin-right: 400px; + + @media(max-width: $slideOverBreakpoint) { + margin-right: 0; + } + } + } + + .slideOver { + position: absolute; + top: 0; + right: -400px; + height: 100%; + width: 400px; + border-left: thin solid var(--veles-color-border); + transition: right .25s, border-left .25s, width .25s; + + @media(max-width: $slideOverBreakpoint) { + width: 100%; + border-left: 0 solid var(--veles-color-border); + margin-right: 0; + right: -100%; + } + + background-color: var(--veles-color-background); + + &.active { + right: 0; + } + + .slideOverContent { + padding: var(--veles-layout-padding); + } + + .slideOverHeader { + display: flex; + border-bottom: thin solid var(--veles-color-border); + align-items: center; + + >* { + padding: var(--veles-layout-padding-slim) var(--veles-layout-padding); + } + + > span { + flex-grow: 1; + } + + > button { + margin: 0; + background: transparent; + font: inherit; + color: inherit; + border: none; + cursor: pointer; + } + } + } +} \ No newline at end of file diff --git a/webui/src/components/panel/hashing/lists/Lists.tsx b/webui/src/components/panel/hashing/lists/Lists.tsx new file mode 100644 index 0000000..13a5c2d --- /dev/null +++ b/webui/src/components/panel/hashing/lists/Lists.tsx @@ -0,0 +1,61 @@ +import React, {useState} from "react"; +import {useNavigate, useOutlet} from "react-router-dom"; + +import styles from "./Lists.module.scss"; +import {Trans, useTranslation} from "react-i18next"; +import ListsTable from "./ListsTable"; +import {PreloadedQuery, usePreloadedQuery} from "react-relay/hooks"; +import {graphql} from "babel-plugin-relay/macro"; +import {ListsQuery} from "./__generated__/ListsQuery.graphql"; +import {X} from "lucide-react"; +import {LoaderSuspense} from "../../../common/Loader"; + +type Props = { + initialQueryRef: PreloadedQuery, +} + +const Lists = ({initialQueryRef}: Props) => { + const outlet = useOutlet() + const navigate = useNavigate() + const {t} = useTranslation() + + const data = usePreloadedQuery( + graphql` + query ListsQuery($first: String, $count: Int) { + ...ListsTableFragment + } + `, + initialQueryRef + ) + + const defaultTitle = t("lists.details", "Details") + + const [title, setTitle] = useState(defaultTitle) + + + return
+
+

Available Lists

+ + +
+ +
+ +
+ {title} + +
+
+ + {outlet} + +
+
+
+
+} + +export const ListsSlideOverTitleContext = React.createContext>|null>(null) + +export default Lists \ No newline at end of file diff --git a/webui/src/components/panel/hashing/lists/ListsTable.module.scss b/webui/src/components/panel/hashing/lists/ListsTable.module.scss new file mode 100644 index 0000000..1b8c6c6 --- /dev/null +++ b/webui/src/components/panel/hashing/lists/ListsTable.module.scss @@ -0,0 +1,5 @@ +@import "../../../../globals"; + +.roomsTableWrapper { + @include tableWrapper; +} diff --git a/webui/src/components/panel/hashing/lists/ListsTable.tsx b/webui/src/components/panel/hashing/lists/ListsTable.tsx new file mode 100644 index 0000000..d9c0ffd --- /dev/null +++ b/webui/src/components/panel/hashing/lists/ListsTable.tsx @@ -0,0 +1,60 @@ +import React from "react"; +import {usePaginationFragment} from "react-relay/hooks"; +import {graphql} from "babel-plugin-relay/macro"; +import {ListsTableFragment$key} from "./__generated__/ListsTableFragment.graphql"; +import styles from "./ListsTable.module.scss"; +import {useNavigate} from "react-router-dom"; +import {Trans} from "react-i18next"; + +type Props = { + initialQueryRef: ListsTableFragment$key, +} + +const ListsTable = ({initialQueryRef}: Props) => { + const {data} = usePaginationFragment(graphql` + fragment ListsTableFragment on Query @refetchable(queryName: "ListsTableFragment") { + lists(after: $first, first: $count) @connection(key: "ListsTableFragment_lists") { + edges { + node { + id + name + tags + creator { + id + username + matrixLinks + } + } + } + } + } + `, initialQueryRef) + + const navigate = useNavigate() + + return
+ + + + + + + + + + { + data.lists?.edges.map((edge) => { + return {navigate("/hashing/lists/"+edge.node.id)}} key={edge.node.id}> + + + + ; + }) + } + + +
NameList IDList Creator
{edge.node.name}{edge.node.id}{edge.node.creator.username}
+
+} + +export default ListsTable \ No newline at end of file diff --git a/webui/src/components/panel/hashing/lists/__generated__/ListDetailQuery.graphql.ts b/webui/src/components/panel/hashing/lists/__generated__/ListDetailQuery.graphql.ts new file mode 100644 index 0000000..56c92f6 --- /dev/null +++ b/webui/src/components/panel/hashing/lists/__generated__/ListDetailQuery.graphql.ts @@ -0,0 +1,185 @@ +/** + * @generated SignedSource<<387ef79509f6e2371f71fa3d72d073fd>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ConcreteRequest, Query } from 'relay-runtime'; +export type ListDetailQuery$variables = { + id?: string | null; +}; +export type ListDetailQuery$data = { + readonly list: { + readonly id: string; + readonly name: string; + readonly tags: ReadonlyArray | null; + readonly creator: { + readonly id: string; + readonly username: string; + readonly matrixLinks: ReadonlyArray | null; + }; + readonly maintainers: { + readonly edges: ReadonlyArray<{ + readonly node: { + readonly id: string; + readonly username: string; + readonly matrixLinks: ReadonlyArray | null; + }; + }>; + }; + } | null; +}; +export type ListDetailQuery = { + variables: ListDetailQuery$variables; + response: ListDetailQuery$data; +}; + +const node: ConcreteRequest = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "id" + } +], +v1 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null +}, +v2 = [ + (v1/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "username", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "matrixLinks", + "storageKey": null + } +], +v3 = [ + { + "alias": null, + "args": [ + { + "kind": "Variable", + "name": "id", + "variableName": "id" + } + ], + "concreteType": "List", + "kind": "LinkedField", + "name": "list", + "plural": false, + "selections": [ + (v1/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "tags", + "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "User", + "kind": "LinkedField", + "name": "creator", + "plural": false, + "selections": (v2/*: any*/), + "storageKey": null + }, + { + "alias": null, + "args": [ + { + "kind": "Literal", + "name": "first", + "value": 100 + } + ], + "concreteType": "UserConnection", + "kind": "LinkedField", + "name": "maintainers", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "UserEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "User", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": (v2/*: any*/), + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": "maintainers(first:100)" + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "ListDetailQuery", + "selections": (v3/*: any*/), + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "ListDetailQuery", + "selections": (v3/*: any*/) + }, + "params": { + "cacheID": "25b9482991b61f15c2856c99875b239e", + "id": null, + "metadata": {}, + "name": "ListDetailQuery", + "operationKind": "query", + "text": "query ListDetailQuery(\n $id: ID\n) {\n list(id: $id) {\n id\n name\n tags\n creator {\n id\n username\n matrixLinks\n }\n maintainers(first: 100) {\n edges {\n node {\n id\n username\n matrixLinks\n }\n }\n }\n }\n}\n" + } +}; +})(); + +(node as any).hash = "7cef889868efd30077c76c270e95474e"; + +export default node; diff --git a/webui/src/components/panel/hashing/lists/__generated__/ListsQuery.graphql.ts b/webui/src/components/panel/hashing/lists/__generated__/ListsQuery.graphql.ts new file mode 100644 index 0000000..87a78c8 --- /dev/null +++ b/webui/src/components/panel/hashing/lists/__generated__/ListsQuery.graphql.ts @@ -0,0 +1,220 @@ +/** + * @generated SignedSource<<5aab59ac780b7eaef3dee3a8745fbc28>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ConcreteRequest, Query } from 'relay-runtime'; +import { FragmentRefs } from "relay-runtime"; +export type ListsQuery$variables = { + first?: string | null; + count?: number | null; +}; +export type ListsQuery$data = { + readonly " $fragmentSpreads": FragmentRefs<"ListsTableFragment">; +}; +export type ListsQuery = { + variables: ListsQuery$variables; + response: ListsQuery$data; +}; + +const node: ConcreteRequest = (function(){ +var v0 = { + "defaultValue": null, + "kind": "LocalArgument", + "name": "count" +}, +v1 = { + "defaultValue": null, + "kind": "LocalArgument", + "name": "first" +}, +v2 = [ + { + "kind": "Variable", + "name": "after", + "variableName": "first" + }, + { + "kind": "Variable", + "name": "first", + "variableName": "count" + } +], +v3 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null +}; +return { + "fragment": { + "argumentDefinitions": [ + (v0/*: any*/), + (v1/*: any*/) + ], + "kind": "Fragment", + "metadata": null, + "name": "ListsQuery", + "selections": [ + { + "args": null, + "kind": "FragmentSpread", + "name": "ListsTableFragment" + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [ + (v1/*: any*/), + (v0/*: any*/) + ], + "kind": "Operation", + "name": "ListsQuery", + "selections": [ + { + "alias": null, + "args": (v2/*: any*/), + "concreteType": "ListConnection", + "kind": "LinkedField", + "name": "lists", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "ListEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "List", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v3/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "tags", + "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "User", + "kind": "LinkedField", + "name": "creator", + "plural": false, + "selections": [ + (v3/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "username", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "matrixLinks", + "storageKey": null + } + ], + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null + } + ], + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "cursor", + "storageKey": null + } + ], + "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "PageInfo", + "kind": "LinkedField", + "name": "pageInfo", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "endCursor", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "hasNextPage", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + }, + { + "alias": null, + "args": (v2/*: any*/), + "filters": null, + "handle": "connection", + "key": "ListsTableFragment_lists", + "kind": "LinkedHandle", + "name": "lists" + } + ] + }, + "params": { + "cacheID": "97b29f2758a0594dc8e7260db058e120", + "id": null, + "metadata": {}, + "name": "ListsQuery", + "operationKind": "query", + "text": "query ListsQuery(\n $first: String\n $count: Int\n) {\n ...ListsTableFragment\n}\n\nfragment ListsTableFragment on Query {\n lists(after: $first, first: $count) {\n edges {\n node {\n id\n name\n tags\n creator {\n id\n username\n matrixLinks\n }\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n" + } +}; +})(); + +(node as any).hash = "af7a7db395ee385cea027ca6d8320a42"; + +export default node; diff --git a/webui/src/components/panel/hashing/lists/__generated__/ListsTableFragment.graphql.ts b/webui/src/components/panel/hashing/lists/__generated__/ListsTableFragment.graphql.ts new file mode 100644 index 0000000..805ce5f --- /dev/null +++ b/webui/src/components/panel/hashing/lists/__generated__/ListsTableFragment.graphql.ts @@ -0,0 +1,203 @@ +/** + * @generated SignedSource<<9406112d41db017f2dbc6315c2cd7064>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ReaderFragment, RefetchableFragment } from 'relay-runtime'; +import { FragmentRefs } from "relay-runtime"; +export type ListsTableFragment$data = { + readonly lists: { + readonly edges: ReadonlyArray<{ + readonly node: { + readonly id: string; + readonly name: string; + readonly tags: ReadonlyArray | null; + readonly creator: { + readonly id: string; + readonly username: string; + readonly matrixLinks: ReadonlyArray | null; + }; + }; + }>; + } | null; + readonly " $fragmentType": "ListsTableFragment"; +}; +export type ListsTableFragment$key = { + readonly " $data"?: ListsTableFragment$data; + readonly " $fragmentSpreads": FragmentRefs<"ListsTableFragment">; +}; + +const node: ReaderFragment = (function(){ +var v0 = [ + "lists" +], +v1 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null +}; +return { + "argumentDefinitions": [ + { + "kind": "RootArgument", + "name": "count" + }, + { + "kind": "RootArgument", + "name": "first" + } + ], + "kind": "Fragment", + "metadata": { + "connection": [ + { + "count": "count", + "cursor": "first", + "direction": "forward", + "path": (v0/*: any*/) + } + ], + "refetch": { + "connection": { + "forward": { + "count": "count", + "cursor": "first" + }, + "backward": null, + "path": (v0/*: any*/) + }, + "fragmentPathInResult": [], + "operation": require('./ListsTableFragment.graphql') + } + }, + "name": "ListsTableFragment", + "selections": [ + { + "alias": "lists", + "args": null, + "concreteType": "ListConnection", + "kind": "LinkedField", + "name": "__ListsTableFragment_lists_connection", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "ListEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "List", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v1/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "tags", + "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "User", + "kind": "LinkedField", + "name": "creator", + "plural": false, + "selections": [ + (v1/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "username", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "matrixLinks", + "storageKey": null + } + ], + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null + } + ], + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "cursor", + "storageKey": null + } + ], + "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "PageInfo", + "kind": "LinkedField", + "name": "pageInfo", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "endCursor", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "hasNextPage", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "type": "Query", + "abstractKey": null +}; +})(); + +(node as any).hash = "8b14551a242c87b90d76b77b05535cb2"; + +export default node; diff --git a/webui/src/components/panel/rooms/RoomDetail.tsx b/webui/src/components/panel/rooms/RoomDetail.tsx index 65ff8f8..7777670 100644 --- a/webui/src/components/panel/rooms/RoomDetail.tsx +++ b/webui/src/components/panel/rooms/RoomDetail.tsx @@ -3,7 +3,7 @@ import {PreloadedQuery, usePreloadedQuery} from "react-relay/hooks"; import {graphql} from "babel-plugin-relay/macro"; import {RoomDetailQuery, RoomDetailQuery$variables} from "./__generated__/RoomDetailQuery.graphql"; import {DisposeFn} from "relay-runtime"; -import {useParams} from "react-router-dom"; +import {useNavigate, useParams} from "react-router-dom"; import {RoomsSlideOverTitleContext} from "./Rooms"; import ToggleButton from "../../form_components/ToggleButton"; @@ -26,6 +26,7 @@ const RoomDetailInner = ({initialQueryRef}: PropsFinal) => { const [reconfigureRoom, reconfiguringRoom] = useReconfigureRoomMutation(); const [newAdminPowerLevel, setNewAdminPowerLevel] = useState(null) const {t} = useTranslation() + const navigate = useNavigate() const data = usePreloadedQuery( @@ -42,7 +43,14 @@ const RoomDetailInner = ({initialQueryRef}: PropsFinal) => { hashCheckerConfig { chatNotice hashCheckMode - subscribedLists + subscribedLists(first: 100) { + edges { + node { + id + name + } + } + } } } } @@ -150,26 +158,18 @@ const RoomDetailInner = ({initialQueryRef}: PropsFinal) => { - {/* - data.rooms?.edges.map((edge) => { - return {navigate("/rooms/"+edge.node.id)}} key={edge.node.id}> - - {edge.node.debug && Debug} - {!edge.node.active && Inactive} - {edge.node.active && Active} - + { + data.room?.hashCheckerConfig.subscribedLists.edges.map((edge) => { + return {navigate("/hashing/lists/"+edge.node.id)}} key={edge.node.id}> {edge.node.name} - {edge.node.roomId} + {edge.node.id} ; }) - */} + } - - -
{JSON.stringify(data, null, 2)}
} diff --git a/webui/src/components/panel/rooms/__generated__/RoomDetailQuery.graphql.ts b/webui/src/components/panel/rooms/__generated__/RoomDetailQuery.graphql.ts index b4c4790..e27e675 100644 --- a/webui/src/components/panel/rooms/__generated__/RoomDetailQuery.graphql.ts +++ b/webui/src/components/panel/rooms/__generated__/RoomDetailQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<58fc708823f0e42ade18c16f92c3b0d2>> + * @generated SignedSource<<1663469824a6a66c6959a37976f2a05e>> * @lightSyntaxTransform * @nogrep */ @@ -25,7 +25,14 @@ export type RoomDetailQuery$data = { readonly hashCheckerConfig: { readonly chatNotice: boolean; readonly hashCheckMode: HashCheckerMode; - readonly subscribedLists: ReadonlyArray | null; + readonly subscribedLists: { + readonly edges: ReadonlyArray<{ + readonly node: { + readonly id: string; + readonly name: string; + }; + }>; + }; }; } | null; }; @@ -42,7 +49,21 @@ var v0 = [ "name": "id" } ], -v1 = [ +v1 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null +}, +v2 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null +}, +v3 = [ { "alias": null, "args": [ @@ -57,13 +78,7 @@ v1 = [ "name": "room", "plural": false, "selections": [ - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "id", - "storageKey": null - }, + (v1/*: any*/), { "alias": null, "args": null, @@ -92,13 +107,7 @@ v1 = [ "name": "debug", "storageKey": null }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "name", - "storageKey": null - }, + (v2/*: any*/), { "alias": null, "args": null, @@ -130,10 +139,44 @@ v1 = [ }, { "alias": null, - "args": null, - "kind": "ScalarField", + "args": [ + { + "kind": "Literal", + "name": "first", + "value": 100 + } + ], + "concreteType": "ListConnection", + "kind": "LinkedField", "name": "subscribedLists", - "storageKey": null + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "ListEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "List", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v1/*: any*/), + (v2/*: any*/) + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": "subscribedLists(first:100)" } ], "storageKey": null @@ -148,7 +191,7 @@ return { "kind": "Fragment", "metadata": null, "name": "RoomDetailQuery", - "selections": (v1/*: any*/), + "selections": (v3/*: any*/), "type": "Query", "abstractKey": null }, @@ -157,19 +200,19 @@ return { "argumentDefinitions": (v0/*: any*/), "kind": "Operation", "name": "RoomDetailQuery", - "selections": (v1/*: any*/) + "selections": (v3/*: any*/) }, "params": { - "cacheID": "397376ecc93b3b405d66d01b7fd4de21", + "cacheID": "12bcb055f358f8be4fc522afa4daf9e3", "id": null, "metadata": {}, "name": "RoomDetailQuery", "operationKind": "query", - "text": "query RoomDetailQuery(\n $id: ID\n) {\n room(id: $id) {\n id\n active\n deactivated\n adminPowerLevel\n debug\n name\n roomId\n hashCheckerConfig {\n chatNotice\n hashCheckMode\n subscribedLists\n }\n }\n}\n" + "text": "query RoomDetailQuery(\n $id: ID\n) {\n room(id: $id) {\n id\n active\n deactivated\n adminPowerLevel\n debug\n name\n roomId\n hashCheckerConfig {\n chatNotice\n hashCheckMode\n subscribedLists(first: 100) {\n edges {\n node {\n id\n name\n }\n }\n }\n }\n }\n}\n" } }; })(); -(node as any).hash = "338b222f1e379335edc6847c401f52f5"; +(node as any).hash = "c5785d54de6de8e5986d7119f5dd7527"; export default node; diff --git a/webui/src/index.tsx b/webui/src/index.tsx index 2a5e0b1..c27b91a 100644 --- a/webui/src/index.tsx +++ b/webui/src/index.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import ReactDOM from 'react-dom'; import './index.scss'; import App from './App'; import {store} from './app/store'; @@ -13,9 +12,11 @@ import { import "./i18n"; import RelayEnvironment from "./RelayEnvironment"; import {LoaderSuspense} from "./components/common/Loader"; +import {createRoot} from "react-dom/client"; +const root = createRoot(document.getElementById('root')!); -ReactDOM.render( +root.render( @@ -26,8 +27,7 @@ ReactDOM.render( - , - document.getElementById('root') + ); // If you want your app to work offline and load faster, you can change diff --git a/webui/src/mutations/ReconfigureRoomMutation.ts b/webui/src/mutations/ReconfigureRoomMutation.ts index 477b632..542e892 100644 --- a/webui/src/mutations/ReconfigureRoomMutation.ts +++ b/webui/src/mutations/ReconfigureRoomMutation.ts @@ -23,7 +23,15 @@ const mutation = graphql` hashCheckerConfig { chatNotice hashCheckMode - subscribedLists + subscribedLists(first: 100) { + edges { + node { + id + name + tags + } + } + } } } } diff --git a/webui/src/mutations/__generated__/ReconfigureRoomMutation.graphql.ts b/webui/src/mutations/__generated__/ReconfigureRoomMutation.graphql.ts index 8b863f1..4869424 100644 --- a/webui/src/mutations/__generated__/ReconfigureRoomMutation.graphql.ts +++ b/webui/src/mutations/__generated__/ReconfigureRoomMutation.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -36,7 +36,15 @@ export type ReconfigureRoomMutation$data = { readonly hashCheckerConfig: { readonly chatNotice: boolean; readonly hashCheckMode: HashCheckerMode; - readonly subscribedLists: ReadonlyArray | null; + readonly subscribedLists: { + readonly edges: ReadonlyArray<{ + readonly node: { + readonly id: string; + readonly name: string; + readonly tags: ReadonlyArray | null; + }; + }>; + }; }; }; }; @@ -53,7 +61,21 @@ var v0 = [ "name": "reconfigureInput" } ], -v1 = [ +v1 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null +}, +v2 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null +}, +v3 = [ { "alias": null, "args": [ @@ -68,13 +90,7 @@ v1 = [ "name": "reconfigureRoom", "plural": false, "selections": [ - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "id", - "storageKey": null - }, + (v1/*: any*/), { "alias": null, "args": null, @@ -89,13 +105,7 @@ v1 = [ "name": "deactivated", "storageKey": null }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "name", - "storageKey": null - }, + (v2/*: any*/), { "alias": null, "args": null, @@ -141,10 +151,51 @@ v1 = [ }, { "alias": null, - "args": null, - "kind": "ScalarField", + "args": [ + { + "kind": "Literal", + "name": "first", + "value": 100 + } + ], + "concreteType": "ListConnection", + "kind": "LinkedField", "name": "subscribedLists", - "storageKey": null + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "ListEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "List", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v1/*: any*/), + (v2/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "tags", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": "subscribedLists(first:100)" } ], "storageKey": null @@ -159,7 +210,7 @@ return { "kind": "Fragment", "metadata": null, "name": "ReconfigureRoomMutation", - "selections": (v1/*: any*/), + "selections": (v3/*: any*/), "type": "Mutation", "abstractKey": null }, @@ -168,19 +219,19 @@ return { "argumentDefinitions": (v0/*: any*/), "kind": "Operation", "name": "ReconfigureRoomMutation", - "selections": (v1/*: any*/) + "selections": (v3/*: any*/) }, "params": { - "cacheID": "4186d7d18c6230e79d890ca0043dc104", + "cacheID": "0961d774133f607eb0b0145371e73f32", "id": null, "metadata": {}, "name": "ReconfigureRoomMutation", "operationKind": "mutation", - "text": "mutation ReconfigureRoomMutation(\n $reconfigureInput: RoomConfigUpdate!\n) {\n reconfigureRoom(input: $reconfigureInput) {\n id\n active\n deactivated\n name\n roomId\n debug\n adminPowerLevel\n hashCheckerConfig {\n chatNotice\n hashCheckMode\n subscribedLists\n }\n }\n}\n" + "text": "mutation ReconfigureRoomMutation(\n $reconfigureInput: RoomConfigUpdate!\n) {\n reconfigureRoom(input: $reconfigureInput) {\n id\n active\n deactivated\n name\n roomId\n debug\n adminPowerLevel\n hashCheckerConfig {\n chatNotice\n hashCheckMode\n subscribedLists(first: 100) {\n edges {\n node {\n id\n name\n tags\n }\n }\n }\n }\n }\n}\n" } }; })(); -(node as any).hash = "e4ccf905922a56c92f44336d58c96a53"; +(node as any).hash = "9041b8d9fb6c1da957feb5f33ec8ac1b"; export default node;