~ knotless Search/
↑↓ move↵ open⇧↵ all results

chadtmiller.com/pds.js

An atproto PDS in JavaScript, for Cloudflare Workers and Node

0
0
main
105 lines · 3.4 KB Raw History
import { Info } from 'lucide-react';
import { Button } from '#/components/atoms/button.jsx';
import { Dialog } from '#/components/molecules/dialog.jsx';
import { JsonView } from '#/components/molecules/json-view.jsx';
import { sourceAuthLabel } from '#/lib/spaces.js';

/** A labelled line in the dialog. */
function Line({ label, children }) {
  return (
    <div className="flex flex-col gap-0.5 py-2">
      <span className="text-muted-foreground text-xs">{label}</span>
      <span className="break-all font-mono text-[12.5px] text-foreground">
        {children}
      </span>
    </div>
  );
}

/**
 * Where a screen's values came from: the method that answered, the server it
 * was addressed to, what was presented to it, and the response itself.
 *
 * A space is served by two roles on two different hosts, and which one answered
 * is the thing a reader most often wants and can least often tell. The response
 * is shown whole rather than summarised, because the point is to be able to
 * check the page against it.
 *
 * @param {Object} props
 * @param {import('#/lib/spaces.js').Source} props.source
 * @param {unknown} props.value - the response body, shown as it arrived
 * @param {string} [props.note] - what the host was acting as
 * @param {Record<string, string>} [props.fields] - which key feeds which row
 */
export function SourceDialog({ source, value, note, fields }) {
  return (
    <Dialog
      title="Where this came from"
      className="max-w-lg"
      trigger={
        <Button
          variant="ghost"
          size="icon-xs"
          title="Where these values came from"
          aria-label="Where these values came from"
        >
          <Info />
        </Button>
      }
    >
      <div className="flex flex-col">
        {note && (
          <p className="pb-2 text-muted-foreground text-sm leading-relaxed">
            {note}
          </p>
        )}

        <div className="divide-y divide-border">
          <Line label="Method">{source.method}</Line>
          <Line label="Server">{source.host}</Line>
          <Line label="Presented">{sourceAuthLabel(source)}</Line>
          {source.after && (
            <Line label="Asked first">
              {source.after}
              <span className="ml-2 font-sans text-faint text-xs">
                answered 501, so the other name was tried
              </span>
            </Line>
          )}
        </div>

        {fields && (
          <div className="pt-4">
            <h4 className="pb-1.5 font-semibold text-[13px] text-foreground">
              What each row reads
            </h4>
            <div className="divide-y divide-border">
              {Object.entries(fields).map(([row, path]) => (
                <div
                  key={row}
                  className="flex flex-wrap items-baseline justify-between gap-x-4 gap-y-0.5 py-1.5"
                >
                  <span className="text-[13px] text-muted-foreground">
                    {row}
                  </span>
                  <span className="font-mono text-[12px] text-foreground">
                    {path}
                  </span>
                </div>
              ))}
            </div>
          </div>
        )}

        <div className="pt-4">
          <h4 className="pb-1.5 font-semibold text-[13px] text-foreground">
            The response
          </h4>
          <div className="rounded-xl bg-muted p-3">
            <JsonView value={value} />
          </div>
        </div>
      </div>
    </Dialog>
  );
}