Compare commits

...

7 Commits

Author SHA1 Message Date
Ben Allen
9e6675b8d2
Add 200ms delay to scroll in capture worker (#1088)
* fix: add 200ms delay to scroll in capture worker

* use: new Promise to wait for timeout
2024-04-18 10:49:42 -05:00
keyan
a77f778f27 fix hidden wallet balance layout shift 2024-04-17 17:22:17 -05:00
ekzyis
59b3d1c375
Round sats in FORWARDEDTIP push notification (#1086) 2024-04-17 14:24:07 -05:00
keyan
f9a99a7deb give 1 sat fee button overlay but not button text 2024-04-17 14:22:31 -05:00
ekzyis
dd6e921e2e
Fix local env in docker-compose.yaml (#1085)
* Allow docker env override via .env.local

* Make .env.local optional

* Fix env var expansion ignoring .env.local

* Rename .env.development to .env.docker

* Use YAML anchors

* Revert rename of .env.development
2024-04-17 13:46:18 -05:00
keyan
0ea261428c give edit and countdown space again 2024-04-17 13:19:10 -05:00
ekzyis
40463d526c
Fix TypeError: Failed to construct 'URL': Invalid URL (#1083) 2024-04-17 12:15:36 -05:00
10 changed files with 77 additions and 107 deletions

View File

@ -94,6 +94,7 @@ app.get('/*', async (req, res) => {
if (commentId) { if (commentId) {
console.timeLog(timeLabel, 'scrolling to comment') console.timeLog(timeLabel, 'scrolling to comment')
await page.waitForSelector('.outline-it') await page.waitForSelector('.outline-it')
await new Promise((resolve, _reject) => setTimeout(resolve, 100))
} }
const file = await page.screenshot({ type: 'png', captureBeyondViewport: false }) const file = await page.screenshot({ type: 'png', captureBeyondViewport: false })

View File

@ -8,7 +8,7 @@ export default function ActionTooltip ({ children, notForm, disable, overlayText
if (!notForm) { if (!notForm) {
formik = useFormikContext() formik = useFormikContext()
} }
if (disable) { if (disable || !overlayText) {
return children return children
} }
return ( return (
@ -16,7 +16,7 @@ export default function ActionTooltip ({ children, notForm, disable, overlayText
placement={placement || 'bottom'} placement={placement || 'bottom'}
overlay={ overlay={
<Tooltip> <Tooltip>
{overlayText || '1 sat'} {overlayText}
</Tooltip> </Tooltip>
} }
trigger={['hover', 'focus']} trigger={['hover', 'focus']}

View File

@ -118,12 +118,12 @@ export default function FeeButton ({ ChildButton = SubmitButton, variant, text,
? 'free' ? 'free'
: total > 1 : total > 1
? numWithUnits(total, { abbreviate: false, format: true }) ? numWithUnits(total, { abbreviate: false, format: true })
: total === 1 ? undefined : 'free' : undefined
disabled ||= ctxDisabled disabled ||= ctxDisabled
return ( return (
<div className={styles.feeButton}> <div className={styles.feeButton}>
<ActionTooltip overlayText={feeText}> <ActionTooltip overlayText={!free && total === 1 ? '1 sat' : feeText}>
<ChildButton variant={variant} disabled={disabled} nonDisabledText={feeText}>{text}</ChildButton> <ChildButton variant={variant} disabled={disabled} nonDisabledText={feeText}>{text}</ChildButton>
</ActionTooltip> </ActionTooltip>
{!me && <AnonInfo />} {!me && <AnonInfo />}

View File

@ -1,4 +1,4 @@
import { useState, useRef, useEffect } from 'react' import { useState, useMemo } from 'react'
import { abbrNum, numWithUnits } from '@/lib/format' import { abbrNum, numWithUnits } from '@/lib/format'
import { useMe } from './me' import { useMe } from './me'
@ -6,19 +6,19 @@ export default function HiddenWalletSummary ({ abbreviate, fixedWidth }) {
const me = useMe() const me = useMe()
const [hover, setHover] = useState(false) const [hover, setHover] = useState(false)
// prevent layout shifts when hovering by fixing width to initial rendered width const fixedWidthAbbrSats = useMemo(() => {
const ref = useRef() const abbr = abbrNum(me.privates?.sats).toString()
const [width, setWidth] = useState(undefined) if (abbr.length >= 6) return abbr
useEffect(() => {
setWidth(ref.current?.offsetWidth) // add leading spaces if abbr is shorter than 6 characters
}, []) return ' '.repeat(6 - abbr.length) + abbr
}, [me.privates?.sats])
return ( return (
<span <span
ref={ref} style={{ width: fixedWidth ? width : undefined }} className='text-monospace' style={{ whiteSpace: 'pre-wrap' }} align='right' onPointerEnter={() => setHover(true)} onPointerLeave={() => setHover(false)}
className='text-monospace' align='right' onPointerEnter={() => setHover(true)} onPointerLeave={() => setHover(false)}
> >
{hover ? (abbreviate ? abbrNum(me.privates?.sats) : numWithUnits(me.privates?.sats, { abbreviate: false, format: true })) : '******'} {hover ? (abbreviate ? fixedWidthAbbrSats : numWithUnits(me.privates?.sats, { abbreviate: false, format: true })) : '******'}
</span> </span>
) )
} }

View File

@ -140,7 +140,7 @@ export default function ItemInfo ({
className='text-reset pointer' className='text-reset pointer'
onClick={() => onEdit ? onEdit() : router.push(`/items/${item.id}/edit`)} onClick={() => onEdit ? onEdit() : router.push(`/items/${item.id}/edit`)}
> >
{editText || 'edit'} <span>{editText || 'edit'} </span>
<Countdown <Countdown
date={editThreshold} date={editThreshold}
onComplete={() => { onComplete={() => {

View File

@ -52,7 +52,7 @@ export default function Poll ({ item }) {
const variables = { id: v.id } const variables = { id: v.id }
return ( return (
<ActionTooltip placement='left' notForm> <ActionTooltip placement='left' notForm overlayText='1 sat'>
<Button <Button
variant='outline-info' className={styles.pollButton} variant='outline-info' className={styles.pollButton}
onClick={me onClick={me

View File

@ -178,7 +178,12 @@ export default memo(function Text ({ rel, imgproxyUrls, children, tab, itemId, o
// If [text](url) was parsed as <a> and text is not empty and not a link itself, // If [text](url) was parsed as <a> and text is not empty and not a link itself,
// we don't render it as an image since it was probably a conscious choice to include text. // we don't render it as an image since it was probably a conscious choice to include text.
const text = children[0] const text = children[0]
const url = !href.startsWith('/') && new URL(href) let url
try {
url = !href.startsWith('/') && new URL(href)
} catch {
// ignore invalid URLs
}
const internalURL = process.env.NEXT_PUBLIC_URL const internalURL = process.env.NEXT_PUBLIC_URL
if (!!text && !/^https?:\/\//.test(text)) { if (!!text && !/^https?:\/\//.test(text)) {
if (props['data-footnote-ref'] || typeof props['data-footnote-backref'] !== 'undefined') { if (props['data-footnote-ref'] || typeof props['data-footnote-backref'] !== 'undefined') {
@ -191,7 +196,7 @@ export default memo(function Text ({ rel, imgproxyUrls, children, tab, itemId, o
</Link> </Link>
) )
} }
if (href.startsWith('/') || url.origin === internalURL) { if (href.startsWith('/') || url?.origin === internalURL) {
return ( return (
<Link <Link
id={props.id} id={props.id}

View File

@ -1,20 +1,38 @@
x-env_file: &env_file
- .env.development
- path: .env.local
required: false
x-healthcheck: &healthcheck
interval: 10s
timeout: 10s
retries: 10
start_period: 1m
x-depends-on-db: &depends_on_db
db:
condition: service_healthy
restart: true
x-depends-on-app: &depends_on_app
app:
condition: service_healthy
restart: true
x-depends-on-bitcoin: &depends_on_bitcoin
bitcoin:
condition: service_healthy
restart: true
services: services:
db: db:
container_name: db container_name: db
build: ./docker/db build: ./docker/db
restart: unless-stopped restart: unless-stopped
healthcheck: healthcheck:
<<: *healthcheck
test: ["CMD-SHELL", "PGPASSWORD=${POSTGRES_PASSWORD} pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB} -h 127.0.0.1 && psql -U ${POSTGRES_USER} ${POSTGRES_DB} -c 'SELECT 1 FROM users LIMIT 1'"] test: ["CMD-SHELL", "PGPASSWORD=${POSTGRES_PASSWORD} pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB} -h 127.0.0.1 && psql -U ${POSTGRES_USER} ${POSTGRES_DB} -c 'SELECT 1 FROM users LIMIT 1'"]
interval: 10s
timeout: 10s
retries: 10
start_period: 1m
expose: expose:
- "5432" - "5432"
ports: ports:
- "5431:5432" - "5431:5432"
env_file: env_file: *env_file
- .env.development
volumes: volumes:
- ./docker/db/seed.sql:/docker-entrypoint-initdb.d/seed.sql - ./docker/db/seed.sql:/docker-entrypoint-initdb.d/seed.sql
- db:/var/lib/postgresql/data - db:/var/lib/postgresql/data
@ -29,17 +47,10 @@ services:
- GID=${CURRENT_GID} - GID=${CURRENT_GID}
restart: unless-stopped restart: unless-stopped
healthcheck: healthcheck:
<<: *healthcheck
test: ["CMD", "curl", "-f", "http://localhost:3000"] test: ["CMD", "curl", "-f", "http://localhost:3000"]
interval: 10s depends_on: *depends_on_db
timeout: 10s env_file: *env_file
retries: 10
start_period: 1m
depends_on:
db:
condition: service_healthy
restart: true
env_file:
- .env.development
expose: expose:
- "3000" - "3000"
ports: ports:
@ -53,19 +64,13 @@ services:
build: build:
context: ./capture context: ./capture
restart: unless-stopped restart: unless-stopped
depends_on: depends_on: *depends_on_app
app:
condition: service_healthy
restart: true
profiles: profiles:
- capture - capture
healthcheck: healthcheck:
<<: *healthcheck
test: ["CMD", "curl", "-f", "http://localhost:5678/health"] test: ["CMD", "curl", "-f", "http://localhost:5678/health"]
interval: 10s env_file: *env_file
timeout: 10s
retries: 10
start_period: 1m
env_file: .env.development
environment: environment:
# configure to screenshot production, because local dev is too slow # configure to screenshot production, because local dev is too slow
- CAPTURE_URL=http://stacker.news - CAPTURE_URL=http://stacker.news
@ -84,14 +89,10 @@ services:
- GID=${CURRENT_GID} - GID=${CURRENT_GID}
restart: unless-stopped restart: unless-stopped
depends_on: depends_on:
db: <<:
condition: service_healthy - *depends_on_db
restart: true - *depends_on_app
app: env_file: *env_file
condition: service_healthy
restart: true
env_file:
- .env.development
volumes: volumes:
- ./:/app - ./:/app
entrypoint: ["/bin/sh", "-c"] entrypoint: ["/bin/sh", "-c"]
@ -103,14 +104,10 @@ services:
profiles: profiles:
- images - images
healthcheck: healthcheck:
<<: *healthcheck
test: [ "CMD", "imgproxy", "health" ] test: [ "CMD", "imgproxy", "health" ]
interval: 10s
timeout: 10s
retries: 10
start_period: 1m
restart: unless-stopped restart: unless-stopped
env_file: env_file: *env_file
- .env.development
ports: ports:
- "3001:8080" - "3001:8080"
expose: expose:
@ -129,8 +126,7 @@ services:
restart: unless-stopped restart: unless-stopped
profiles: profiles:
- images - images
env_file: env_file: *env_file
- .env.development
environment: environment:
- DEBUG=1 - DEBUG=1
ports: ports:
@ -149,14 +145,10 @@ services:
profiles: profiles:
- search - search
healthcheck: healthcheck:
<<: *healthcheck
test: ["CMD-SHELL", "curl -ku admin:${OPENSEARCH_INITIAL_ADMIN_PASSWORD} --silent --fail localhost:9200/_cluster/health || exit 1"] test: ["CMD-SHELL", "curl -ku admin:${OPENSEARCH_INITIAL_ADMIN_PASSWORD} --silent --fail localhost:9200/_cluster/health || exit 1"]
interval: 10s
timeout: 10s
retries: 10
start_period: 1m
restart: unless-stopped restart: unless-stopped
env_file: env_file: *env_file
- .env.development
environment: environment:
- OPENSEARCH_INITIAL_ADMIN_PASSWORD=mVchg1T5oA9wudUh - OPENSEARCH_INITIAL_ADMIN_PASSWORD=mVchg1T5oA9wudUh
ports: ports:
@ -194,8 +186,7 @@ services:
opensearch: opensearch:
condition: service_healthy condition: service_healthy
restart: true restart: true
env_file: env_file: *env_file
- .env.development
environment: environment:
- opensearch.ssl.verificationMode=none - opensearch.ssl.verificationMode=none
- OPENSEARCH_HOSTS=http://opensearch:9200 - OPENSEARCH_HOSTS=http://opensearch:9200
@ -213,11 +204,8 @@ services:
profiles: profiles:
- payments - payments
healthcheck: healthcheck:
<<: *healthcheck
test: ["CMD-SHELL", "bitcoin-cli -chain=regtest -rpcport=${RPC_PORT} -rpcuser=${RPC_USER} -rpcpassword=${RPC_PASS} getblockchaininfo"] test: ["CMD-SHELL", "bitcoin-cli -chain=regtest -rpcport=${RPC_PORT} -rpcuser=${RPC_USER} -rpcpassword=${RPC_PASS} getblockchaininfo"]
interval: 10s
timeout: 10s
retries: 10
start_period: 1m
command: command:
- 'bitcoind' - 'bitcoind'
- '-server=1' - '-server=1'
@ -275,17 +263,10 @@ services:
profiles: profiles:
- payments - payments
healthcheck: healthcheck:
<<: *healthcheck
test: ["CMD-SHELL", "lncli", "getinfo"] test: ["CMD-SHELL", "lncli", "getinfo"]
interval: 10s depends_on: *depends_on_bitcoin
timeout: 10s env_file: *env_file
retries: 10
start_period: 1m
depends_on:
bitcoin:
condition: service_healthy
restart: true
env_file:
- .env.development
command: command:
- 'lnd' - 'lnd'
- '--noseedbackup' - '--noseedbackup'
@ -339,17 +320,10 @@ services:
profiles: profiles:
- payments - payments
healthcheck: healthcheck:
<<: *healthcheck
test: ["CMD-SHELL", "lncli", "getinfo"] test: ["CMD-SHELL", "lncli", "getinfo"]
interval: 10s depends_on: *depends_on_bitcoin
timeout: 10s env_file: *env_file
retries: 10
start_period: 1m
depends_on:
bitcoin:
condition: service_healthy
restart: true
env_file:
- .env.development
command: command:
- 'lnd' - 'lnd'
- '--noseedbackup' - '--noseedbackup'
@ -401,17 +375,10 @@ services:
profiles: profiles:
- payments - payments
healthcheck: healthcheck:
<<: *healthcheck
test: ["CMD-SHELL", "su clightning -c 'lightning-cli --network=regtest getinfo'"] test: ["CMD-SHELL", "su clightning -c 'lightning-cli --network=regtest getinfo'"]
interval: 10s depends_on: *depends_on_bitcoin
timeout: 10s env_file: *env_file
retries: 10
start_period: 1m
depends_on:
bitcoin:
condition: service_healthy
restart: true
env_file:
- .env.development
command: command:
- 'lightningd' - 'lightningd'
- '--network=regtest' - '--network=regtest'
@ -462,11 +429,8 @@ services:
- email - email
restart: unless-stopped restart: unless-stopped
healthcheck: healthcheck:
<<: *healthcheck
test: ["CMD", "wget", "-q", "--spider", "http://localhost:8025"] test: ["CMD", "wget", "-q", "--spider", "http://localhost:8025"]
interval: 10s
timeout: 10s
retries: 10
start_period: 1m
ports: ports:
- "8025:8025" - "8025:8025"
- "1025:1025" - "1025:1025"

View File

@ -236,7 +236,7 @@ export const notifyZapped = async ({ models, id }) => {
// send push notifications to forwarded recipients // send push notifications to forwarded recipients
if (mappedForwards.length) { if (mappedForwards.length) {
await Promise.allSettled(mappedForwards.map(forward => sendUserNotification(forward.user.id, { await Promise.allSettled(mappedForwards.map(forward => sendUserNotification(forward.user.id, {
title: `you were forwarded ${numWithUnits(msatsToSats(updatedItem.msats) * forward.pct / 100)}`, title: `you were forwarded ${numWithUnits(Math.round(msatsToSats(updatedItem.msats) * forward.pct / 100))}`,
body: updatedItem.title ?? updatedItem.text, body: updatedItem.title ?? updatedItem.text,
item: updatedItem, item: updatedItem,
tag: `FORWARDEDTIP-${updatedItem.id}` tag: `FORWARDEDTIP-${updatedItem.id}`

2
sndev
View File

@ -13,7 +13,7 @@ docker__compose() {
COMPOSE_PROFILES="images,search,payments,email,capture" COMPOSE_PROFILES="images,search,payments,email,capture"
fi fi
CURRENT_UID=$(id -u) CURRENT_GID=$(id -g) COMPOSE_PROFILES=$COMPOSE_PROFILES command docker compose --env-file .env.development "$@" CURRENT_UID=$(id -u) CURRENT_GID=$(id -g) COMPOSE_PROFILES=$COMPOSE_PROFILES command docker compose --env-file .env.development --env-file .env.local "$@"
} }
docker__exec() { docker__exec() {