1
Fork 0

Rewrite sidebar share to Typescript

This commit is contained in:
viktorstrate 2021-04-17 22:14:17 +02:00
parent f6f7377096
commit e43a344902
No known key found for this signature in database
GPG Key ID: 3F855605109C1E8A
7 changed files with 287 additions and 171 deletions

View File

@ -1882,7 +1882,7 @@ type Album {
thumbnail: Media
path: [Album!]!
shares: [ShareToken]
shares: [ShareToken!]!
}
type MediaURL {
@ -3232,11 +3232,14 @@ func (ec *executionContext) _Album_shares(ctx context.Context, field graphql.Col
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.([]*models.ShareToken)
fc.Result = res
return ec.marshalOShareToken2ᚕᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐShareToken(ctx, field.Selections, res)
return ec.marshalNShareToken2ᚕᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐShareToken(ctx, field.Selections, res)
}
func (ec *executionContext) _AuthorizeResult_success(ctx context.Context, field graphql.CollectedField, obj *models.AuthorizeResult) (ret graphql.Marshaler) {
@ -10044,6 +10047,9 @@ func (ec *executionContext) _Album(ctx context.Context, sel ast.SelectionSet, ob
}
}()
res = ec._Album_shares(ctx, field, obj)
if res == graphql.Null {
atomic.AddUint32(&invalids, 1)
}
return res
})
default:
@ -12642,53 +12648,6 @@ func (ec *executionContext) unmarshalOPagination2ᚖgithubᚗcomᚋphotoviewᚋp
return &res, graphql.ErrorOnPath(ctx, err)
}
func (ec *executionContext) marshalOShareToken2ᚕᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐShareToken(ctx context.Context, sel ast.SelectionSet, v []*models.ShareToken) graphql.Marshaler {
if v == nil {
return graphql.Null
}
ret := make(graphql.Array, len(v))
var wg sync.WaitGroup
isLen1 := len(v) == 1
if !isLen1 {
wg.Add(len(v))
}
for i := range v {
i := i
fc := &graphql.FieldContext{
Index: &i,
Result: &v[i],
}
ctx := graphql.WithFieldContext(ctx, fc)
f := func(i int) {
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = nil
}
}()
if !isLen1 {
defer wg.Done()
}
ret[i] = ec.marshalOShareToken2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐShareToken(ctx, sel, v[i])
}
if isLen1 {
f(i)
} else {
go f(i)
}
}
wg.Wait()
return ret
}
func (ec *executionContext) marshalOShareToken2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐShareToken(ctx context.Context, sel ast.SelectionSet, v *models.ShareToken) graphql.Marshaler {
if v == nil {
return graphql.Null
}
return ec._ShareToken(ctx, sel, v)
}
func (ec *executionContext) unmarshalOShareTokenCredentials2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐShareTokenCredentials(ctx context.Context, v interface{}) (*models.ShareTokenCredentials, error) {
if v == nil {
return nil, nil

View File

@ -262,7 +262,7 @@ type Album {
thumbnail: Media
path: [Album!]!
shares: [ShareToken]
shares: [ShareToken!]!
}
type MediaURL {

View File

@ -1,7 +1,6 @@
import React from 'react'
import PropTypes from 'prop-types'
import { useQuery, gql } from '@apollo/client'
import SidebarShare from './Sharing'
import { SidebarAlbumShare } from './Sharing'
import { useTranslation } from 'react-i18next'
const albumQuery = gql`
@ -13,7 +12,11 @@ const albumQuery = gql`
}
`
const AlbumSidebar = ({ albumId }) => {
type AlbumSidebarProps = {
albumId: string
}
const AlbumSidebar = ({ albumId }: AlbumSidebarProps) => {
const { t } = useTranslation()
const { loading, error, data } = useQuery(albumQuery, {
variables: { id: albumId },
@ -27,14 +30,10 @@ const AlbumSidebar = ({ albumId }) => {
<p>{t('sidebar.album.title', 'Album options')}</p>
<div>
<h1>{data.album.title}</h1>
<SidebarShare album={data.album} />
<SidebarAlbumShare id={data.album.id} />
</div>
</div>
)
}
AlbumSidebar.propTypes = {
albumId: PropTypes.string.isRequired,
}
export default AlbumSidebar

View File

@ -7,7 +7,7 @@ import {
ProtectedVideo,
ProtectedVideoProps_Media,
} from '../photoGallery/ProtectedMedia'
import SidebarShare from './Sharing'
import { SidebarPhotoShare } from './Sharing'
import SidebarDownload from './SidebarDownload'
import SidebarItem from './SidebarItem'
import { SidebarFacesOverlay } from '../facesOverlay/FacesOverlay'
@ -377,7 +377,7 @@ const SidebarContent = ({ media, hidePreview }: SidebarContentProps) => {
<Name>{media.title}</Name>
<MetadataInfo media={media} />
<SidebarDownload photo={media} />
<SidebarShare photo={media} />
<SidebarPhotoShare id={media.id} />
</div>
)
}

View File

@ -1,5 +1,4 @@
import React, { useState } from 'react'
import PropTypes from 'prop-types'
import { useMutation, useQuery, gql } from '@apollo/client'
import {
Table,
@ -10,12 +9,37 @@ import {
Icon,
} from 'semantic-ui-react'
import copy from 'copy-to-clipboard'
import { authToken } from '../../helpers/authentication'
import styled from 'styled-components'
import { useTranslation } from 'react-i18next'
import { sidbarGetAlbumShares_album_shares } from './__generated__/sidbarGetAlbumShares'
import {
sidebareDeleteShare,
sidebareDeleteShareVariables,
} from './__generated__/sidebareDeleteShare'
import {
sidebarProtectShare,
sidebarProtectShareVariables,
} from './__generated__/sidebarProtectShare'
import { sidbarGetPhotoShares_media_shares } from './__generated__/sidbarGetPhotoShares'
import {
sidebarPhotoAddShare,
sidebarPhotoAddShareVariables,
} from './__generated__/sidebarPhotoAddShare'
import {
sidebarAlbumAddShare,
sidebarAlbumAddShareVariables,
} from './__generated__/sidebarAlbumAddShare'
import {
sidebarGetPhotoShares,
sidebarGetPhotoSharesVariables,
} from './__generated__/sidebarGetPhotoShares'
import {
sidebarGetAlbumShares,
sidebarGetAlbumSharesVariables,
} from './__generated__/sidebarGetAlbumShares'
const sharePhotoQuery = gql`
query sidbarGetPhotoShares($id: ID!) {
const SHARE_PHOTO_QUERY = gql`
query sidebarGetPhotoShares($id: ID!) {
media(id: $id) {
id
shares {
@ -27,8 +51,8 @@ const sharePhotoQuery = gql`
}
`
const shareAlbumQuery = gql`
query sidbarGetAlbumShares($id: ID!) {
const SHARE_ALBUM_QUERY = gql`
query sidebarGetAlbumShares($id: ID!) {
album(id: $id) {
id
shares {
@ -40,7 +64,7 @@ const shareAlbumQuery = gql`
}
`
const addPhotoShareMutation = gql`
const ADD_MEDIA_SHARE_MUTATION = gql`
mutation sidebarPhotoAddShare($id: ID!, $password: String, $expire: Time) {
shareMedia(mediaId: $id, password: $password, expire: $expire) {
token
@ -48,7 +72,7 @@ const addPhotoShareMutation = gql`
}
`
const addAlbumShareMutation = gql`
const ADD_ALBUM_SHARE_MUTATION = gql`
mutation sidebarAlbumAddShare($id: ID!, $password: String, $expire: Time) {
shareAlbum(albumId: $id, password: $password, expire: $expire) {
token
@ -56,7 +80,7 @@ const addAlbumShareMutation = gql`
}
`
const protectShareMutation = gql`
const PROTECT_SHARE_MUTATION = gql`
mutation sidebarProtectShare($token: String!, $password: String) {
protectShareToken(token: $token, password: $password) {
token
@ -65,7 +89,7 @@ const protectShareMutation = gql`
}
`
const deleteShareMutation = gql`
const DELETE_SHARE_MUTATION = gql`
mutation sidebareDeleteShare($token: String!) {
deleteShareToken(token: $token) {
token
@ -73,16 +97,26 @@ const deleteShareMutation = gql`
}
`
const ShareItemMoreDropdown = ({ id, share, isPhoto }) => {
const { t } = useTranslation()
const query = isPhoto ? sharePhotoQuery : shareAlbumQuery
type ShareItemMoreDropdownProps = {
id: string
isPhoto: boolean
share: sidbarGetAlbumShares_album_shares
}
const [deleteShare, { loading: deleteShareLoading }] = useMutation(
deleteShareMutation,
{
refetchQueries: [{ query: query, variables: { id } }],
}
)
const ShareItemMoreDropdown = ({
id,
share,
isPhoto,
}: ShareItemMoreDropdownProps) => {
const { t } = useTranslation()
const query = isPhoto ? SHARE_PHOTO_QUERY : SHARE_ALBUM_QUERY
const [deleteShare, { loading: deleteShareLoading }] = useMutation<
sidebareDeleteShare,
sidebareDeleteShareVariables
>(DELETE_SHARE_MUTATION, {
refetchQueries: [{ query: query, variables: { id } }],
})
const [addingPassword, setAddingPassword] = useState(false)
const showPasswordInput = addingPassword || share.hasPassword
@ -92,36 +126,36 @@ const ShareItemMoreDropdown = ({ id, share, isPhoto }) => {
)
const [passwordHidden, setPasswordHidden] = useState(share.hasPassword)
const hidePassword = hide => {
const hidePassword = (hide: boolean) => {
setPasswordHidden(hide)
if (hide) {
setPasswordInputValue('**********')
}
}
const [setPassword, { loading: setPasswordLoading }] = useMutation(
protectShareMutation,
{
refetchQueries: [{ query: query, variables: { id } }],
onCompleted: data => {
hidePassword(data.protectShareToken.hasPassword)
},
// refetchQueries: [{ query: query, variables: { id } }],
variables: {
token: share.token,
},
}
)
const [setPassword, { loading: setPasswordLoading }] = useMutation<
sidebarProtectShare,
sidebarProtectShareVariables
>(PROTECT_SHARE_MUTATION, {
refetchQueries: [{ query: query, variables: { id } }],
onCompleted: data => {
hidePassword(data.protectShareToken.hasPassword)
},
// refetchQueries: [{ query: query, variables: { id } }],
variables: {
token: share.token,
},
})
let addPasswordInput = null
if (showPasswordInput) {
const setPasswordEvent = event => {
const setPasswordEvent = (event: React.KeyboardEvent<HTMLInputElement>) => {
if (!passwordHidden && passwordInputValue != '' && event.key == 'Enter') {
event.preventDefault()
setPassword({
variables: {
token: share.token,
password: event.target.value,
password: (event.target as HTMLInputElement).value,
},
})
}
@ -132,7 +166,7 @@ const ShareItemMoreDropdown = ({ id, share, isPhoto }) => {
disabled={setPasswordLoading}
loading={setPasswordLoading}
style={{ marginTop: 8, marginRight: 0, display: 'block' }}
onClick={e => e.stopPropagation()}
onClick={(e: MouseEvent) => e.stopPropagation()}
value={passwordInputValue}
type={passwordHidden ? 'password' : 'text'}
onKeyUp={setPasswordEvent}
@ -158,6 +192,7 @@ const ShareItemMoreDropdown = ({ id, share, isPhoto }) => {
if (!enable) {
setPassword({
variables: {
token: share.token,
password: null,
},
})
@ -182,7 +217,7 @@ const ShareItemMoreDropdown = ({ id, share, isPhoto }) => {
>
<Dropdown.Menu>
<Dropdown.Item
onKeyDown={e => e.stopPropagation()}
onKeyDown={(e: KeyboardEvent) => e.stopPropagation()}
onClick={e => {
e.stopPropagation()
checkboxClick()
@ -215,88 +250,153 @@ const ShareItemMoreDropdown = ({ id, share, isPhoto }) => {
)
}
ShareItemMoreDropdown.propTypes = {
id: PropTypes.string.isRequired,
isPhoto: PropTypes.bool.isRequired,
share: PropTypes.object.isRequired,
}
const ShareButtonGroup = styled(Button.Group)`
flex-wrap: wrap;
`
const SidebarShare = ({ photo, album }) => {
type SidebarShareAlbumProps = {
id: string
}
export const SidebarAlbumShare = ({ id }: SidebarShareAlbumProps) => {
const { t } = useTranslation()
if ((!photo || !photo.id) && (!album || !album.id)) return null
if (!authToken()) return null
const isPhoto = !!photo
const id = isPhoto ? photo.id : album.id
const query = isPhoto ? sharePhotoQuery : shareAlbumQuery
const addShareMutation = isPhoto
? addPhotoShareMutation
: addAlbumShareMutation
const {
loading: sharesLoading,
loading: queryLoading,
error: sharesError,
data: sharesData,
} = useQuery(query, {
variables: { id },
} = useQuery<sidebarGetAlbumShares, sidebarGetAlbumSharesVariables>(
SHARE_ALBUM_QUERY,
{ variables: { id } }
)
const [shareAlbum, { loading: mutationLoading }] = useMutation<
sidebarAlbumAddShare,
sidebarAlbumAddShareVariables
>(ADD_ALBUM_SHARE_MUTATION, {
refetchQueries: [{ query: SHARE_ALBUM_QUERY, variables: { id } }],
})
const [sharePhoto, { loading: sharePhotoLoading }] = useMutation(
addShareMutation,
const loading = queryLoading || mutationLoading
if (sharesError) {
return <div>Error: {sharesError.message}</div>
}
if (loading) {
return <div>{t('general.loading.shares', 'Loading shares...')}</div>
}
return (
<SidebarShare
id={id}
isPhoto={false}
loading={loading}
shares={sharesData?.album.shares}
shareItem={shareAlbum}
/>
)
}
type SidebarSharePhotoProps = {
id: string
}
export const SidebarPhotoShare = ({ id }: SidebarSharePhotoProps) => {
const { t } = useTranslation()
const {
loading: queryLoading,
error: sharesError,
data: sharesData,
} = useQuery<sidebarGetPhotoShares, sidebarGetPhotoSharesVariables>(
SHARE_PHOTO_QUERY,
{
refetchQueries: [{ query: query, variables: { id } }],
variables: { id },
}
)
let content = null
const [sharePhoto, { loading: mutationLoading }] = useMutation<
sidebarPhotoAddShare,
sidebarPhotoAddShareVariables
>(ADD_MEDIA_SHARE_MUTATION, {
refetchQueries: [{ query: SHARE_PHOTO_QUERY, variables: { id } }],
})
const loading = queryLoading || mutationLoading
if (sharesError) {
content = <div>Error: {sharesError.message}</div>
return <div>Error: {sharesError.message}</div>
}
if (!content && sharesLoading) {
content = <div>{t('general.loading.shares', 'Loading shares...')}</div>
if (loading) {
return <div>{t('general.loading.shares', 'Loading shares...')}</div>
}
if (!content) {
const shares = isPhoto ? sharesData.media.shares : sharesData.album.shares
return (
<SidebarShare
id={id}
isPhoto={true}
loading={loading}
shares={sharesData?.media.shares}
shareItem={sharePhoto}
/>
)
}
const optionsRows = shares.map(share => (
<Table.Row key={share.token}>
<Table.Cell>
<b>{t('sidebar.sharing.public_link', 'Public Link')}</b> {share.token}
</Table.Cell>
<Table.Cell>
<ShareButtonGroup>
<Button
icon="chain"
content={t('sidebar.sharing.copy_link', 'Copy Link')}
onClick={() => {
copy(`${location.origin}/share/${share.token}`)
}}
/>
<ShareItemMoreDropdown share={share} id={id} isPhoto={isPhoto} />
</ShareButtonGroup>
type SidebarShareProps = {
id: string
isPhoto: boolean
loading: boolean
shares?: sidbarGetPhotoShares_media_shares[]
shareItem(item: { variables: { id: string } }): void
}
const SidebarShare = ({
loading,
shares,
isPhoto,
id,
shareItem,
}: SidebarShareProps) => {
const { t } = useTranslation()
if (shares === undefined) {
return null
}
const optionsRows = shares.map(share => (
<Table.Row key={share.token}>
<Table.Cell>
<b>{t('sidebar.sharing.public_link', 'Public Link')}</b> {share.token}
</Table.Cell>
<Table.Cell>
<ShareButtonGroup>
<Button
icon="chain"
content={t('sidebar.sharing.copy_link', 'Copy Link')}
onClick={() => {
copy(`${location.origin}/share/${share.token}`)
}}
/>
<ShareItemMoreDropdown share={share} id={id} isPhoto={isPhoto} />
</ShareButtonGroup>
</Table.Cell>
</Table.Row>
))
if (optionsRows.length == 0) {
optionsRows.push(
<Table.Row key="no-shares">
<Table.Cell colSpan="2">
{t('sidebar.sharing.no_shares_found', 'No shares found')}
</Table.Cell>
</Table.Row>
))
)
}
if (optionsRows.length == 0) {
optionsRows.push(
<Table.Row key="no-shares">
<Table.Cell colSpan="2">
{t('sidebar.sharing.no_shares_found', 'No shares found')}
</Table.Cell>
</Table.Row>
)
}
content = (
return (
<div>
<h2>{t('sidebar.sharing.title', 'Sharing options')}</h2>
<div>
<Table>
<Table.Header>
@ -315,10 +415,10 @@ const SidebarShare = ({ photo, album }) => {
icon="add"
floated="right"
positive
loading={sharePhotoLoading}
disabled={sharePhotoLoading}
loading={loading}
disabled={loading}
onClick={() => {
sharePhoto({
shareItem({
variables: {
id,
},
@ -330,20 +430,6 @@ const SidebarShare = ({ photo, album }) => {
</Table.Footer>
</Table>
</div>
)
}
return (
<div>
<h2>{t('sidebar.sharing.title', 'Sharing options')}</h2>
{content}
</div>
)
}
SidebarShare.propTypes = {
photo: PropTypes.object,
album: PropTypes.object,
}
export default SidebarShare

View File

@ -0,0 +1,36 @@
/* tslint:disable */
/* eslint-disable */
// @generated
// This file was automatically generated and should not be edited.
// ====================================================
// GraphQL query operation: sidebarGetAlbumShares
// ====================================================
export interface sidebarGetAlbumShares_album_shares {
__typename: 'ShareToken'
id: string
token: string
/**
* Whether or not a password is needed to access the share
*/
hasPassword: boolean
}
export interface sidebarGetAlbumShares_album {
__typename: 'Album'
id: string
shares: sidebarGetAlbumShares_album_shares[]
}
export interface sidebarGetAlbumShares {
/**
* Get album by id, user must own the album or be admin
* If valid tokenCredentials are provided, the album may be retrived without further authentication
*/
album: sidebarGetAlbumShares_album
}
export interface sidebarGetAlbumSharesVariables {
id: string
}

View File

@ -0,0 +1,36 @@
/* tslint:disable */
/* eslint-disable */
// @generated
// This file was automatically generated and should not be edited.
// ====================================================
// GraphQL query operation: sidebarGetPhotoShares
// ====================================================
export interface sidebarGetPhotoShares_media_shares {
__typename: 'ShareToken'
id: string
token: string
/**
* Whether or not a password is needed to access the share
*/
hasPassword: boolean
}
export interface sidebarGetPhotoShares_media {
__typename: 'Media'
id: string
shares: sidebarGetPhotoShares_media_shares[]
}
export interface sidebarGetPhotoShares {
/**
* Get media by id, user must own the media or be admin.
* If valid tokenCredentials are provided, the media may be retrived without further authentication
*/
media: sidebarGetPhotoShares_media
}
export interface sidebarGetPhotoSharesVariables {
id: string
}