Compare commits
7 Commits
7d587c7cf8
...
9e6675b8d2
Author | SHA1 | Date | |
---|---|---|---|
|
9e6675b8d2 | ||
|
a77f778f27 | ||
|
59b3d1c375 | ||
|
f9a99a7deb | ||
|
dd6e921e2e | ||
|
0ea261428c | ||
|
40463d526c |
@ -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 })
|
||||||
|
@ -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']}
|
||||||
|
@ -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 />}
|
||||||
|
@ -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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -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={() => {
|
||||||
|
@ -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
|
||||||
|
@ -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}
|
||||||
|
@ -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"
|
||||||
|
@ -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
2
sndev
@ -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() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user