Hook up UI to add and remove multiple root paths for each user
This commit is contained in:
parent
6e2773cc65
commit
c198e68daf
|
@ -129,6 +129,8 @@ type ComplexityRoot struct {
|
||||||
ShareAlbum func(childComplexity int, albumID int, expire *time.Time, password *string) int
|
ShareAlbum func(childComplexity int, albumID int, expire *time.Time, password *string) int
|
||||||
ShareMedia func(childComplexity int, mediaID int, expire *time.Time, password *string) int
|
ShareMedia func(childComplexity int, mediaID int, expire *time.Time, password *string) int
|
||||||
UpdateUser func(childComplexity int, id int, username *string, password *string, admin *bool) int
|
UpdateUser func(childComplexity int, id int, username *string, password *string, admin *bool) int
|
||||||
|
UserAddRootPath func(childComplexity int, id int, rootPath string) int
|
||||||
|
UserRemoveRootAlbum func(childComplexity int, userID int, albumID int) int
|
||||||
}
|
}
|
||||||
|
|
||||||
Notification struct {
|
Notification struct {
|
||||||
|
@ -246,6 +248,8 @@ type MutationResolver interface {
|
||||||
UpdateUser(ctx context.Context, id int, username *string, password *string, admin *bool) (*models.User, error)
|
UpdateUser(ctx context.Context, id int, username *string, password *string, admin *bool) (*models.User, error)
|
||||||
CreateUser(ctx context.Context, username string, password *string, admin bool) (*models.User, error)
|
CreateUser(ctx context.Context, username string, password *string, admin bool) (*models.User, error)
|
||||||
DeleteUser(ctx context.Context, id int) (*models.User, error)
|
DeleteUser(ctx context.Context, id int) (*models.User, error)
|
||||||
|
UserAddRootPath(ctx context.Context, id int, rootPath string) (*models.Album, error)
|
||||||
|
UserRemoveRootAlbum(ctx context.Context, userID int, albumID int) (*models.Album, error)
|
||||||
SetPeriodicScanInterval(ctx context.Context, interval int) (int, error)
|
SetPeriodicScanInterval(ctx context.Context, interval int) (int, error)
|
||||||
SetScannerConcurrentWorkers(ctx context.Context, workers int) (int, error)
|
SetScannerConcurrentWorkers(ctx context.Context, workers int) (int, error)
|
||||||
}
|
}
|
||||||
|
@ -771,6 +775,30 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
||||||
|
|
||||||
return e.complexity.Mutation.UpdateUser(childComplexity, args["id"].(int), args["username"].(*string), args["password"].(*string), args["admin"].(*bool)), true
|
return e.complexity.Mutation.UpdateUser(childComplexity, args["id"].(int), args["username"].(*string), args["password"].(*string), args["admin"].(*bool)), true
|
||||||
|
|
||||||
|
case "Mutation.userAddRootPath":
|
||||||
|
if e.complexity.Mutation.UserAddRootPath == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
args, err := ec.field_Mutation_userAddRootPath_args(context.TODO(), rawArgs)
|
||||||
|
if err != nil {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.Mutation.UserAddRootPath(childComplexity, args["id"].(int), args["rootPath"].(string)), true
|
||||||
|
|
||||||
|
case "Mutation.userRemoveRootAlbum":
|
||||||
|
if e.complexity.Mutation.UserRemoveRootAlbum == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
args, err := ec.field_Mutation_userRemoveRootAlbum_args(context.TODO(), rawArgs)
|
||||||
|
if err != nil {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.Mutation.UserRemoveRootAlbum(childComplexity, args["userId"].(int), args["albumId"].(int)), true
|
||||||
|
|
||||||
case "Notification.content":
|
case "Notification.content":
|
||||||
if e.complexity.Notification.Content == nil {
|
if e.complexity.Notification.Content == nil {
|
||||||
break
|
break
|
||||||
|
@ -1372,6 +1400,10 @@ type Mutation {
|
||||||
): User @isAdmin
|
): User @isAdmin
|
||||||
deleteUser(id: ID!): User @isAdmin
|
deleteUser(id: ID!): User @isAdmin
|
||||||
|
|
||||||
|
"Add a root path from where to look for media for the given user"
|
||||||
|
userAddRootPath(id: ID!, rootPath: String!): Album @isAdmin
|
||||||
|
userRemoveRootAlbum(userId: ID!, albumId: ID!): Album @isAdmin
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Set how often, in seconds, the server should automatically scan for new media,
|
Set how often, in seconds, the server should automatically scan for new media,
|
||||||
a value of 0 will disable periodic scans
|
a value of 0 will disable periodic scans
|
||||||
|
@ -1935,6 +1967,54 @@ func (ec *executionContext) field_Mutation_updateUser_args(ctx context.Context,
|
||||||
return args, nil
|
return args, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) field_Mutation_userAddRootPath_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["id"]; ok {
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id"))
|
||||||
|
arg0, err = ec.unmarshalNID2int(ctx, tmp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
args["id"] = arg0
|
||||||
|
var arg1 string
|
||||||
|
if tmp, ok := rawArgs["rootPath"]; ok {
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("rootPath"))
|
||||||
|
arg1, err = ec.unmarshalNString2string(ctx, tmp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
args["rootPath"] = arg1
|
||||||
|
return args, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) field_Mutation_userRemoveRootAlbum_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["userId"]; ok {
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("userId"))
|
||||||
|
arg0, err = ec.unmarshalNID2int(ctx, tmp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
args["userId"] = arg0
|
||||||
|
var arg1 int
|
||||||
|
if tmp, ok := rawArgs["albumId"]; ok {
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("albumId"))
|
||||||
|
arg1, err = ec.unmarshalNID2int(ctx, tmp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
args["albumId"] = arg1
|
||||||
|
return args, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) field_Query___type_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
func (ec *executionContext) field_Query___type_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
||||||
var err error
|
var err error
|
||||||
args := map[string]interface{}{}
|
args := map[string]interface{}{}
|
||||||
|
@ -4236,6 +4316,124 @@ func (ec *executionContext) _Mutation_deleteUser(ctx context.Context, field grap
|
||||||
return ec.marshalOUser2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐUser(ctx, field.Selections, res)
|
return ec.marshalOUser2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐUser(ctx, field.Selections, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _Mutation_userAddRootPath(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
fc := &graphql.FieldContext{
|
||||||
|
Object: "Mutation",
|
||||||
|
Field: field,
|
||||||
|
Args: nil,
|
||||||
|
IsMethod: true,
|
||||||
|
IsResolver: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
rawArgs := field.ArgumentMap(ec.Variables)
|
||||||
|
args, err := ec.field_Mutation_userAddRootPath_args(ctx, rawArgs)
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
fc.Args = args
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
|
directive0 := func(rctx context.Context) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return ec.resolvers.Mutation().UserAddRootPath(rctx, args["id"].(int), args["rootPath"].(string))
|
||||||
|
}
|
||||||
|
directive1 := func(ctx context.Context) (interface{}, error) {
|
||||||
|
if ec.directives.IsAdmin == nil {
|
||||||
|
return nil, errors.New("directive isAdmin is not implemented")
|
||||||
|
}
|
||||||
|
return ec.directives.IsAdmin(ctx, nil, directive0)
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp, err := directive1(rctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, graphql.ErrorOnPath(ctx, err)
|
||||||
|
}
|
||||||
|
if tmp == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if data, ok := tmp.(*models.Album); ok {
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/photoview/photoview/api/graphql/models.Album`, tmp)
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(*models.Album)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalOAlbum2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐAlbum(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _Mutation_userRemoveRootAlbum(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
fc := &graphql.FieldContext{
|
||||||
|
Object: "Mutation",
|
||||||
|
Field: field,
|
||||||
|
Args: nil,
|
||||||
|
IsMethod: true,
|
||||||
|
IsResolver: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
rawArgs := field.ArgumentMap(ec.Variables)
|
||||||
|
args, err := ec.field_Mutation_userRemoveRootAlbum_args(ctx, rawArgs)
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
fc.Args = args
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
|
directive0 := func(rctx context.Context) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return ec.resolvers.Mutation().UserRemoveRootAlbum(rctx, args["userId"].(int), args["albumId"].(int))
|
||||||
|
}
|
||||||
|
directive1 := func(ctx context.Context) (interface{}, error) {
|
||||||
|
if ec.directives.IsAdmin == nil {
|
||||||
|
return nil, errors.New("directive isAdmin is not implemented")
|
||||||
|
}
|
||||||
|
return ec.directives.IsAdmin(ctx, nil, directive0)
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp, err := directive1(rctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, graphql.ErrorOnPath(ctx, err)
|
||||||
|
}
|
||||||
|
if tmp == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if data, ok := tmp.(*models.Album); ok {
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/photoview/photoview/api/graphql/models.Album`, tmp)
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(*models.Album)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalOAlbum2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐAlbum(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _Mutation_setPeriodicScanInterval(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
func (ec *executionContext) _Mutation_setPeriodicScanInterval(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
|
@ -8008,6 +8206,10 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
|
||||||
out.Values[i] = ec._Mutation_createUser(ctx, field)
|
out.Values[i] = ec._Mutation_createUser(ctx, field)
|
||||||
case "deleteUser":
|
case "deleteUser":
|
||||||
out.Values[i] = ec._Mutation_deleteUser(ctx, field)
|
out.Values[i] = ec._Mutation_deleteUser(ctx, field)
|
||||||
|
case "userAddRootPath":
|
||||||
|
out.Values[i] = ec._Mutation_userAddRootPath(ctx, field)
|
||||||
|
case "userRemoveRootAlbum":
|
||||||
|
out.Values[i] = ec._Mutation_userRemoveRootAlbum(ctx, field)
|
||||||
case "setPeriodicScanInterval":
|
case "setPeriodicScanInterval":
|
||||||
out.Values[i] = ec._Mutation_setPeriodicScanInterval(ctx, field)
|
out.Values[i] = ec._Mutation_setPeriodicScanInterval(ctx, field)
|
||||||
if out.Values[i] == graphql.Null {
|
if out.Values[i] == graphql.Null {
|
||||||
|
|
|
@ -217,3 +217,39 @@ func (r *mutationResolver) DeleteUser(ctx context.Context, id int) (*models.User
|
||||||
|
|
||||||
return &user, nil
|
return &user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *mutationResolver) UserAddRootPath(ctx context.Context, id int, rootPath string) (*models.Album, error) {
|
||||||
|
|
||||||
|
var user models.User
|
||||||
|
if err := r.Database.First(&user, id).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Check if path exists and that user does not already own rootPath, directly or indirectly
|
||||||
|
|
||||||
|
newAlbum, err := scanner.NewRootAlbum(r.Database, rootPath, &user)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return newAlbum, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *mutationResolver) UserRemoveRootAlbum(ctx context.Context, userID int, albumID int) (*models.Album, error) {
|
||||||
|
|
||||||
|
var album models.Album
|
||||||
|
if err := r.Database.First(&album, albumID).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
result := r.Database.Exec("DELETE FROM user_albums WHERE album_id = ? AND user_id = ?", albumID, userID)
|
||||||
|
if result.Error != nil {
|
||||||
|
return nil, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.RowsAffected == 0 {
|
||||||
|
return nil, errors.New("No relation deleted")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &album, nil
|
||||||
|
}
|
||||||
|
|
|
@ -95,6 +95,10 @@ type Mutation {
|
||||||
): User @isAdmin
|
): User @isAdmin
|
||||||
deleteUser(id: ID!): User @isAdmin
|
deleteUser(id: ID!): User @isAdmin
|
||||||
|
|
||||||
|
"Add a root path from where to look for media for the given user"
|
||||||
|
userAddRootPath(id: ID!, rootPath: String!): Album @isAdmin
|
||||||
|
userRemoveRootAlbum(userId: ID!, albumId: ID!): Album @isAdmin
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Set how often, in seconds, the server should automatically scan for new media,
|
Set how often, in seconds, the server should automatically scan for new media,
|
||||||
a value of 0 will disable periodic scans
|
a value of 0 will disable periodic scans
|
||||||
|
|
|
@ -1,84 +1,8 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import { Button, Checkbox, Input, Table } from 'semantic-ui-react'
|
||||||
import styled from 'styled-components'
|
import { EditRootPaths } from './EditUserRowRootPaths'
|
||||||
import { Button, Checkbox, Icon, Input, Table } from 'semantic-ui-react'
|
|
||||||
import { UserRowProps } from './UserRow'
|
import { UserRowProps } from './UserRow'
|
||||||
|
|
||||||
const RootPathListItem = styled.li`
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
`
|
|
||||||
|
|
||||||
const EditRootPath = ({ filePath, removePath }) => (
|
|
||||||
<RootPathListItem>
|
|
||||||
<span>{filePath}</span>
|
|
||||||
<Button negative onClick={() => removePath()}>
|
|
||||||
<Icon name="remove" />
|
|
||||||
Remove
|
|
||||||
</Button>
|
|
||||||
</RootPathListItem>
|
|
||||||
)
|
|
||||||
|
|
||||||
EditRootPath.propTypes = {
|
|
||||||
filePath: PropTypes.string.isRequired,
|
|
||||||
removePath: PropTypes.func.isRequired,
|
|
||||||
}
|
|
||||||
|
|
||||||
const NewRootPathInput = styled(Input)`
|
|
||||||
width: 100%;
|
|
||||||
margin-top: 24px;
|
|
||||||
`
|
|
||||||
|
|
||||||
const EditNewRootPath = ({ state, updateInput }) => (
|
|
||||||
<li>
|
|
||||||
<NewRootPathInput
|
|
||||||
style={{ width: '100%' }}
|
|
||||||
value={state.rootPath}
|
|
||||||
onChange={e => updateInput(e, 'rootPath')}
|
|
||||||
action={{
|
|
||||||
positive: true,
|
|
||||||
icon: 'add',
|
|
||||||
content: 'Add',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</li>
|
|
||||||
)
|
|
||||||
|
|
||||||
EditNewRootPath.propTypes = {
|
|
||||||
state: PropTypes.object.isRequired,
|
|
||||||
updateInput: PropTypes.func.isRequired,
|
|
||||||
}
|
|
||||||
|
|
||||||
const RootPathList = styled.ul`
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
list-style: none;
|
|
||||||
`
|
|
||||||
|
|
||||||
const EditRootPaths = ({ user, state, updateInput }) => {
|
|
||||||
const editRows = user.rootAlbums.map(album => (
|
|
||||||
<EditRootPath
|
|
||||||
key={album.id}
|
|
||||||
filePath={album.filePath}
|
|
||||||
removePath={() => {}}
|
|
||||||
/>
|
|
||||||
))
|
|
||||||
|
|
||||||
return (
|
|
||||||
<RootPathList>
|
|
||||||
{editRows}
|
|
||||||
<EditNewRootPath state={state} updateInput={updateInput} />
|
|
||||||
</RootPathList>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
EditRootPaths.propTypes = {
|
|
||||||
updateInput: PropTypes.func.isRequired,
|
|
||||||
user: PropTypes.object.isRequired,
|
|
||||||
state: PropTypes.object.isRequired,
|
|
||||||
}
|
|
||||||
|
|
||||||
const EditUserRow = ({
|
const EditUserRow = ({
|
||||||
user,
|
user,
|
||||||
state,
|
state,
|
||||||
|
@ -104,17 +28,17 @@ const EditUserRow = ({
|
||||||
/>
|
/>
|
||||||
</Table.Cell>
|
</Table.Cell>
|
||||||
<Table.Cell>
|
<Table.Cell>
|
||||||
<EditRootPaths user={user} state={state} updateInput={updateInput} />
|
<EditRootPaths user={user} />
|
||||||
</Table.Cell>
|
</Table.Cell>
|
||||||
<Table.Cell>
|
<Table.Cell>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
toggle
|
toggle
|
||||||
checked={state.admin}
|
checked={state.admin}
|
||||||
onChange={(_, data) => {
|
onChange={(_, data) => {
|
||||||
setState({
|
setState(state => ({
|
||||||
...state,
|
...state,
|
||||||
admin: data.checked,
|
admin: data.checked,
|
||||||
})
|
}))
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Table.Cell>
|
</Table.Cell>
|
||||||
|
@ -123,9 +47,9 @@ const EditUserRow = ({
|
||||||
<Button
|
<Button
|
||||||
negative
|
negative
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
setState({
|
setState(state => ({
|
||||||
...state.oldState,
|
...state.oldState,
|
||||||
})
|
}))
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
|
|
|
@ -0,0 +1,134 @@
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import React, { useState } from 'react'
|
||||||
|
import { gql, useMutation } from '@apollo/client'
|
||||||
|
import { Button, Icon, Input } from 'semantic-ui-react'
|
||||||
|
import styled from 'styled-components'
|
||||||
|
import { USERS_QUERY } from './UsersTable'
|
||||||
|
|
||||||
|
const userAddRootPathMutation = gql`
|
||||||
|
mutation userAddRootPath($id: ID!, $rootPath: String!) {
|
||||||
|
userAddRootPath(id: $id, rootPath: $rootPath) {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const userRemoveAlbumPathMutation = gql`
|
||||||
|
mutation userRemoveAlbumPathMutation($userId: ID!, $albumId: ID!) {
|
||||||
|
userRemoveRootAlbum(userId: $userId, albumId: $albumId) {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const RootPathListItem = styled.li`
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
`
|
||||||
|
|
||||||
|
const EditRootPath = ({ album, user }) => {
|
||||||
|
const [removeAlbumPath, { loading }] = useMutation(
|
||||||
|
userRemoveAlbumPathMutation,
|
||||||
|
{
|
||||||
|
refetchQueries: [
|
||||||
|
{
|
||||||
|
query: USERS_QUERY,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<RootPathListItem>
|
||||||
|
<span>{album.filePath}</span>
|
||||||
|
<Button
|
||||||
|
negative
|
||||||
|
disabled={loading}
|
||||||
|
onClick={() =>
|
||||||
|
removeAlbumPath({
|
||||||
|
variables: {
|
||||||
|
userId: user.id,
|
||||||
|
albumId: album.id,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Icon name="remove" />
|
||||||
|
Remove
|
||||||
|
</Button>
|
||||||
|
</RootPathListItem>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
EditRootPath.propTypes = {
|
||||||
|
album: PropTypes.object.isRequired,
|
||||||
|
user: PropTypes.object.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
const NewRootPathInput = styled(Input)`
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 24px;
|
||||||
|
`
|
||||||
|
|
||||||
|
const EditNewRootPath = ({ userID }) => {
|
||||||
|
const [value, setValue] = useState('')
|
||||||
|
const [addRootPath, { loading }] = useMutation(userAddRootPathMutation, {
|
||||||
|
refetchQueries: [
|
||||||
|
{
|
||||||
|
query: USERS_QUERY,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<li>
|
||||||
|
<NewRootPathInput
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
value={value}
|
||||||
|
onChange={e => setValue(e.target.value)}
|
||||||
|
disabled={loading}
|
||||||
|
action={{
|
||||||
|
positive: true,
|
||||||
|
icon: 'add',
|
||||||
|
content: 'Add',
|
||||||
|
onClick: () => {
|
||||||
|
addRootPath({
|
||||||
|
variables: {
|
||||||
|
id: userID,
|
||||||
|
rootPath: value,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
EditNewRootPath.propTypes = {
|
||||||
|
userID: PropTypes.string.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
const RootPathList = styled.ul`
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
list-style: none;
|
||||||
|
`
|
||||||
|
|
||||||
|
export const EditRootPaths = ({ user }) => {
|
||||||
|
const editRows = user.rootAlbums.map(album => (
|
||||||
|
<EditRootPath key={album.id} album={album} user={user} />
|
||||||
|
))
|
||||||
|
|
||||||
|
return (
|
||||||
|
<RootPathList>
|
||||||
|
{editRows}
|
||||||
|
<EditNewRootPath userID={user.id} />
|
||||||
|
</RootPathList>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
EditRootPaths.propTypes = {
|
||||||
|
user: PropTypes.object.isRequired,
|
||||||
|
}
|
|
@ -46,6 +46,7 @@ const UserRow = ({ user, refetchUsers }) => {
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
...user,
|
...user,
|
||||||
editing: false,
|
editing: false,
|
||||||
|
newRootPath: '',
|
||||||
})
|
})
|
||||||
|
|
||||||
const [showConfirmDelete, setConfirmDelete] = useState(false)
|
const [showConfirmDelete, setConfirmDelete] = useState(false)
|
||||||
|
|
|
@ -6,7 +6,7 @@ import UserRow from './UserRow'
|
||||||
import AddUserRow from './AddUserRow'
|
import AddUserRow from './AddUserRow'
|
||||||
import { SectionTitle } from '../SettingsPage'
|
import { SectionTitle } from '../SettingsPage'
|
||||||
|
|
||||||
const USERS_QUERY = gql`
|
export const USERS_QUERY = gql`
|
||||||
query settingsUsersQuery {
|
query settingsUsersQuery {
|
||||||
user {
|
user {
|
||||||
id
|
id
|
||||||
|
|
|
@ -12,7 +12,7 @@ const PathList = styled.ul`
|
||||||
|
|
||||||
const ViewUserRow = ({
|
const ViewUserRow = ({
|
||||||
user,
|
user,
|
||||||
state,
|
// state,
|
||||||
setState,
|
setState,
|
||||||
scanUser,
|
scanUser,
|
||||||
deleteUser,
|
deleteUser,
|
||||||
|
@ -41,7 +41,7 @@ const ViewUserRow = ({
|
||||||
<Button.Group>
|
<Button.Group>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setState({ ...state, editing: true, oldState: state })
|
setState(state => ({ ...state, editing: true, oldState: state }))
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Icon name="edit" />
|
<Icon name="edit" />
|
||||||
|
|
Loading…
Reference in New Issue