CI & Build / Python lint (push) Successful in 9s
CI & Build / Plugin hooks (push) Successful in 22s
CI & Build / TypeScript typecheck (push) Successful in 1m0s
CI & Build / integration (push) Successful in 1m55s
CI & Build / Python tests (push) Successful in 2m20s
CI & Build / Build & push image (push) Successful in 1m7s
Components, stores, api clients, router, types and shared CSS now state what each piece is and why, without the milestone that introduced it. diff.ts names its consumers instead of the copy history; stores/notes and tasks state their current scope instead of the cleanup that set it; theme.css states the token practice instead of the sweep that established it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
68 lines
2.5 KiB
Vue
68 lines
2.5 KiB
Vue
<script setup lang="ts">
|
||
/**
|
||
* "N/M used" on a list row — surfaced vs opened, for any record kind.
|
||
*
|
||
* Shared by the snippet and rule lists. The counts read identically for both; what differs
|
||
* is the ADVICE, which is why that is a prop. A snippet surfaced repeatedly
|
||
* and never opened should probably go; a rule in the same position may simply
|
||
* have a `when_to_apply` that fires on the wrong thing, and telling an
|
||
* operator to delete it would be the wrong nudge half the time.
|
||
*/
|
||
import type { RecordUsage } from "@/types/usage";
|
||
|
||
const props = defineProps<{
|
||
usage?: RecordUsage | null;
|
||
/** What to suggest when this record looks like dead weight. Appended to the
|
||
* tooltip; kind-specific, because the remedies are. */
|
||
deadWeightAdvice: string;
|
||
/** What the record is called in the tooltip's own sentence. */
|
||
noun?: string;
|
||
}>();
|
||
|
||
/** Offered repeatedly and never opened. Three rather than one because one or
|
||
* two surfacings is noise — the record may simply not have come up in a
|
||
* relevant context yet. */
|
||
const isDeadWeight = () =>
|
||
!!props.usage && props.usage.pull_count === 0 && props.usage.surfaced_count >= 3;
|
||
|
||
/** "" renders nothing. A record nobody has surfaced yet gets no badge at all:
|
||
* "0/0" would read as a verdict when it is an absence of evidence — and on a
|
||
* freshly-migrated install that is every row. */
|
||
const label = () => {
|
||
const u = props.usage;
|
||
if (!u || u.surfaced_count === 0) return "";
|
||
return `${u.pull_count}/${u.surfaced_count} used`;
|
||
};
|
||
|
||
const title = () => {
|
||
const u = props.usage;
|
||
if (!u) return "";
|
||
const last = u.last_pulled_at
|
||
? `Last opened ${new Date(u.last_pulled_at).toLocaleDateString()}.`
|
||
: "Never opened.";
|
||
const verdict = isDeadWeight() ? ` ${props.deadWeightAdvice}` : "";
|
||
// Said only when it happened: "0× elsewhere" on every row would read as a
|
||
// finding about records that simply have not been near another project.
|
||
const awaySurfaced = u.surfaced_away_count ?? 0;
|
||
const away = awaySurfaced
|
||
? ` On other projects: surfaced ${awaySurfaced}×, opened ${u.pulled_away_count ?? 0}×.`
|
||
: "";
|
||
return (
|
||
`Surfaced to an agent ${u.surfaced_count}×, opened in full ` +
|
||
`${u.pull_count}×.${away} ${last}${verdict}`
|
||
);
|
||
};
|
||
</script>
|
||
|
||
<template>
|
||
<span
|
||
v-if="label()"
|
||
class="usage-tag"
|
||
:class="{ 'usage-dead': isDeadWeight() }"
|
||
:title="title()"
|
||
>{{ label() }}</span>
|
||
</template>
|
||
|
||
<!-- The look lives in components.css (canon). Nothing scoped here on purpose:
|
||
a view that needs different spacing keeps that as its own remainder. -->
|