Compare commits
4 Commits
050122c665
...
3d3dc52cec
Author | SHA1 | Date | |
---|---|---|---|
|
3d3dc52cec | ||
|
0576716c4a | ||
|
a7bc757514 | ||
|
d2a981ca5d |
@ -1311,6 +1311,9 @@ export const createItem = async (parent, { forward, options, ...item }, { me, mo
|
||||
item.url = removeTracking(item.url)
|
||||
}
|
||||
|
||||
// mark item as created with API key
|
||||
item.apiKey = me?.apiKey
|
||||
|
||||
const uploadIds = uploadIdsFromText(item.text, { models })
|
||||
const { totalFees: imgFees } = await imageFeesInfo(uploadIds, { models, me })
|
||||
|
||||
@ -1433,7 +1436,7 @@ export const SELECT =
|
||||
"Item".ncomments, "Item"."commentMsats", "Item"."lastCommentAt", "Item"."weightedVotes",
|
||||
"Item"."weightedDownVotes", "Item".freebie, "Item".bio, "Item"."otsHash", "Item"."bountyPaidTo",
|
||||
ltree2text("Item"."path") AS "path", "Item"."weightedComments", "Item"."imgproxyUrls", "Item".outlawed,
|
||||
"Item"."pollExpiresAt"`
|
||||
"Item"."pollExpiresAt", "Item"."apiKey"`
|
||||
|
||||
function topOrderByWeightedSats (me, models) {
|
||||
return `ORDER BY ${orderByNumerator(models)} DESC NULLS LAST, "Item".id DESC`
|
||||
|
@ -125,6 +125,7 @@ export default gql`
|
||||
forwards: [ItemForward]
|
||||
imgproxyUrls: JSONObject
|
||||
rel: String
|
||||
apiKey: Boolean
|
||||
}
|
||||
|
||||
input ItemForwardInput {
|
||||
|
@ -104,3 +104,4 @@ benalleng,helpfulness,#1191,#134,medium,,,did most of this before,100k,benalleng
|
||||
cointastical,issue,#1191,#134,medium,,,,22k,cointastical@stacker.news,2024-05-28
|
||||
kravhen,pr,#1198,#1180,good-first-issue,,,required linting,18k,nichro@getalby.com,2024-05-28
|
||||
OneOneSeven117,issue,#1198,#1180,good-first-issue,,,required linting,2k,OneOneSeven@stacker.news,2024-05-28
|
||||
tsmith123,pr,#1207,#837,easy,high,1,,180k,stickymarch60@walletofsatoshi.com,2024-05-31
|
||||
|
|
@ -3,7 +3,9 @@ import AccordionContext from 'react-bootstrap/AccordionContext'
|
||||
import { useAccordionButton } from 'react-bootstrap/AccordionButton'
|
||||
import ArrowRight from '@/svgs/arrow-right-s-fill.svg'
|
||||
import ArrowDown from '@/svgs/arrow-down-s-fill.svg'
|
||||
import { useContext, useEffect } from 'react'
|
||||
import { useContext, useEffect, useState } from 'react'
|
||||
|
||||
const KEY_ID = '0'
|
||||
|
||||
function ContextAwareToggle ({ children, headerColor = 'var(--theme-grey)', eventKey, show }) {
|
||||
const { activeEventKey } = useContext(AccordionContext)
|
||||
@ -29,10 +31,20 @@ function ContextAwareToggle ({ children, headerColor = 'var(--theme-grey)', even
|
||||
}
|
||||
|
||||
export default function AccordianItem ({ header, body, headerColor = 'var(--theme-grey)', show }) {
|
||||
const [activeKey, setActiveKey] = useState()
|
||||
|
||||
useEffect(() => {
|
||||
setActiveKey(show ? KEY_ID : null)
|
||||
}, [show])
|
||||
|
||||
const handleOnSelect = () => {
|
||||
setActiveKey(activeKey === KEY_ID ? null : KEY_ID)
|
||||
}
|
||||
|
||||
return (
|
||||
<Accordion defaultActiveKey={show ? '0' : undefined}>
|
||||
<ContextAwareToggle show={show} eventKey='0'><div style={{ color: headerColor }}>{header}</div></ContextAwareToggle>
|
||||
<Accordion.Collapse eventKey='0' className='mt-2'>
|
||||
<Accordion defaultActiveKey={activeKey} activeKey={activeKey} onSelect={handleOnSelect}>
|
||||
<ContextAwareToggle show={show} eventKey={KEY_ID}><div style={{ color: headerColor }}>{header}</div></ContextAwareToggle>
|
||||
<Accordion.Collapse eventKey={KEY_ID} className='mt-2'>
|
||||
<div>{body}</div>
|
||||
</Accordion.Collapse>
|
||||
</Accordion>
|
||||
|
@ -176,7 +176,14 @@ function TopLevelItem ({ item, noReply, ...props }) {
|
||||
</article>
|
||||
{!noReply &&
|
||||
<>
|
||||
<Reply item={item} replyOpen placeholder={item.ncomments > 3 ? 'fractions of a penny for your thoughts?' : 'early comments get more zaps'} onCancelQuote={cancelQuote} onQuoteReply={quoteReply} quote={quote} />
|
||||
<Reply
|
||||
item={item}
|
||||
replyOpen
|
||||
placeholder={item.ncomments > 3 ? 'fractions of a penny for your thoughts?' : 'early comments get more zaps'}
|
||||
onCancelQuote={cancelQuote}
|
||||
onQuoteReply={quoteReply}
|
||||
quote={quote}
|
||||
/>
|
||||
{
|
||||
// Don't show related items for Saloon items (position is set but no subName)
|
||||
(!item.position && item.subName) &&
|
||||
|
@ -136,6 +136,9 @@ export default function ItemInfo ({
|
||||
{' '}<Badge className={styles.newComment} bg={null}>freebie</Badge>
|
||||
</Link>
|
||||
)}
|
||||
{(item.apiKey &&
|
||||
<>{' '}<Badge className={styles.newComment} bg={null}>bot</Badge></>
|
||||
)}
|
||||
{extraBadges}
|
||||
{canEdit && !item.deletedAt &&
|
||||
<>
|
||||
|
@ -31,7 +31,15 @@ export function ReplyOnAnotherPage ({ item }) {
|
||||
)
|
||||
}
|
||||
|
||||
export default forwardRef(function Reply ({ item, onSuccess, replyOpen, children, placeholder, onQuoteReply, onCancelQuote, quote }, ref) {
|
||||
export default forwardRef(function Reply ({
|
||||
item,
|
||||
replyOpen,
|
||||
children,
|
||||
placeholder,
|
||||
onQuoteReply,
|
||||
onCancelQuote,
|
||||
quote
|
||||
}, ref) {
|
||||
const [reply, setReply] = useState(replyOpen || quote)
|
||||
const me = useMe()
|
||||
const parentId = item.id
|
||||
|
@ -34,6 +34,7 @@ export const COMMENT_FIELDS = gql`
|
||||
ncomments
|
||||
imgproxyUrls
|
||||
rel
|
||||
apiKey
|
||||
}
|
||||
`
|
||||
|
||||
|
@ -59,6 +59,7 @@ export const ITEM_FIELDS = gql`
|
||||
mine
|
||||
imgproxyUrls
|
||||
rel
|
||||
apiKey
|
||||
}`
|
||||
|
||||
export const ITEM_FULL_FIELDS = gql`
|
||||
|
@ -28,7 +28,6 @@ import { useServiceWorkerLogger } from '@/components/logger'
|
||||
import { useMe } from '@/components/me'
|
||||
import { INVOICE_RETENTION_DAYS, ZAP_UNDO_DELAY_MS } from '@/lib/constants'
|
||||
import { OverlayTrigger, Tooltip } from 'react-bootstrap'
|
||||
import DeleteIcon from '@/svgs/delete-bin-line.svg'
|
||||
import { useField } from 'formik'
|
||||
import styles from './settings.module.css'
|
||||
|
||||
@ -859,22 +858,25 @@ I estimate that I will call the GraphQL API this many times (rough estimate is f
|
||||
// link to DM with ek on SimpleX
|
||||
const simplexLink = 'https://simplex.chat/contact#/?v=1-2&smp=smp%3A%2F%2F6iIcWT_dF2zN_w5xzZEY7HI2Prbh3ldP07YTyDexPjE%3D%40smp10.simplex.im%2FxNnPk9DkTbQJ6NckWom9mi5vheo_VPLm%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAnFUiU0M8jS1JY34LxUoPr7mdJlFZwf3pFkjRrhprdQs%253D%26srv%3Drb2pbttocvnbrngnwziclp2f4ckjq65kebafws6g4hy22cdaiv5dwjqd.onion'
|
||||
|
||||
const disabled = !enabled || apiKey
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='form-label mt-3'>api key</div>
|
||||
<div className='mt-2 d-flex align-items-center'>
|
||||
<OverlayTrigger
|
||||
placement='bottom'
|
||||
overlay={disabled ? <Tooltip>{apiKey ? 'you can have only one API key at a time' : 'request access to API keys in ~meta'}</Tooltip> : <></>}
|
||||
overlay={!enabled ? <Tooltip>{apiKey ? 'you can have only one API key at a time' : 'request access to API keys in ~meta'}</Tooltip> : <></>}
|
||||
trigger={['hover', 'focus']}
|
||||
>
|
||||
<div>
|
||||
<Button
|
||||
disabled={disabled}
|
||||
variant='secondary'
|
||||
disabled={!enabled}
|
||||
variant={apiKey ? 'danger' : 'secondary'}
|
||||
onClick={async () => {
|
||||
if (apiKey) {
|
||||
showModal((onClose) => <ApiKeyDeleteObstacle onClose={onClose} />)
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const { data } = await generateApiKey({ variables: { id: me.id } })
|
||||
const { generateApiKey: apiKey } = data
|
||||
@ -884,17 +886,10 @@ I estimate that I will call the GraphQL API this many times (rough estimate is f
|
||||
toaster.danger('error generating api key')
|
||||
}
|
||||
}}
|
||||
>Generate API key
|
||||
>{apiKey ? 'Delete' : 'Generate'} API key
|
||||
</Button>
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
{apiKey &&
|
||||
<DeleteIcon
|
||||
style={{ cursor: 'pointer' }} className='fill-danger mx-1' width={24} height={24}
|
||||
onClick={async () => {
|
||||
showModal((onClose) => <ApiKeyDeleteObstacle onClose={onClose} />)
|
||||
}}
|
||||
/>}
|
||||
<Info>
|
||||
<ul className='fw-bold'>
|
||||
<li>use API keys with our <Link target='_blank' href='/api/graphql'>GraphQL API</Link> for authentication</li>
|
||||
|
@ -0,0 +1,2 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "Item" ADD COLUMN "apiKey" BOOLEAN NOT NULL DEFAULT false;
|
@ -419,6 +419,7 @@ model Item {
|
||||
ItemUpload ItemUpload[]
|
||||
uploadId Int?
|
||||
outlawed Boolean @default(false)
|
||||
apiKey Boolean @default(false)
|
||||
pollExpiresAt DateTime?
|
||||
Ancestors Reply[] @relation("AncestorReplyItem")
|
||||
Replies Reply[]
|
||||
|
Loading…
x
Reference in New Issue
Block a user