@igstack/app-catalog-frontend-core 6.10.3 → 6.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/__tests__/modules/auth/AuthContext.test.d.ts +1 -0
- package/dist/esm/__tests__/modules/communityTools/likedBy.test.d.ts +1 -0
- package/dist/esm/__tests__/modules/communityTools/timeAgo.test.d.ts +1 -0
- package/dist/esm/__tests__/modules/communityTools/useTimeUp.test.d.ts +1 -0
- package/dist/esm/api/infra/trpc.d.ts +419 -0
- package/dist/esm/api/infra/trpc.js.map +1 -1
- package/dist/esm/modules/appCatalog/hooks/useUpdateApp.d.ts +1 -1
- package/dist/esm/modules/appCatalog/ui/catalog/AppDetailPanel.d.ts +2 -4
- package/dist/esm/modules/appCatalog/ui/catalog/AppDetailPanel.js +29 -101
- package/dist/esm/modules/appCatalog/ui/catalog/AppDetailPanel.js.map +1 -1
- package/dist/esm/modules/appCatalog/ui/catalog/DetailDialogShell.d.ts +26 -0
- package/dist/esm/modules/appCatalog/ui/catalog/DetailDialogShell.js +108 -0
- package/dist/esm/modules/appCatalog/ui/catalog/DetailDialogShell.js.map +1 -0
- package/dist/esm/modules/appCatalog/ui/components/ScreenshotGallery.d.ts +2 -1
- package/dist/esm/modules/appCatalog/ui/components/ScreenshotGallery.js.map +1 -1
- package/dist/esm/modules/appCatalog/ui/components/SectionTabs.d.ts +8 -0
- package/dist/esm/modules/appCatalog/ui/components/SectionTabs.js +73 -0
- package/dist/esm/modules/appCatalog/ui/components/SectionTabs.js.map +1 -0
- package/dist/esm/modules/appCatalog/ui/detail/AppDetails.js +19 -2
- package/dist/esm/modules/appCatalog/ui/detail/AppDetails.js.map +1 -1
- package/dist/esm/modules/appCatalog/ui/detail/CommentsFeed.d.ts +3 -2
- package/dist/esm/modules/appCatalog/ui/detail/CommentsFeed.js +4 -4
- package/dist/esm/modules/appCatalog/ui/detail/CommentsFeed.js.map +1 -1
- package/dist/esm/modules/appCatalog/ui/detail/CommentsHelp.d.ts +2 -1
- package/dist/esm/modules/appCatalog/ui/detail/CommentsHelp.js +2 -2
- package/dist/esm/modules/appCatalog/ui/detail/CommentsHelp.js.map +1 -1
- package/dist/esm/modules/appCatalog/ui/detail/CommunityInput.d.ts +3 -2
- package/dist/esm/modules/appCatalog/ui/detail/CommunityInput.js +13 -9
- package/dist/esm/modules/appCatalog/ui/detail/CommunityInput.js.map +1 -1
- package/dist/esm/modules/appCatalog/ui/detail/CommunitySection.d.ts +4 -2
- package/dist/esm/modules/appCatalog/ui/detail/CommunitySection.js +10 -4
- package/dist/esm/modules/appCatalog/ui/detail/CommunitySection.js.map +1 -1
- package/dist/esm/modules/appCatalog/ui/detail/communityDraft.d.ts +12 -0
- package/dist/esm/modules/appCatalog/ui/detail/communityDraft.js +4 -0
- package/dist/esm/modules/appCatalog/ui/detail/communityDraft.js.map +1 -1
- package/dist/esm/modules/appCatalog/ui/detail/composeComments.js +1 -0
- package/dist/esm/modules/appCatalog/ui/detail/composeComments.js.map +1 -1
- package/dist/esm/modules/appCatalog/ui/detail/useCommunityToolCount.d.ts +6 -0
- package/dist/esm/modules/appCatalog/ui/detail/useCommunityToolCount.js +16 -0
- package/dist/esm/modules/appCatalog/ui/detail/useCommunityToolCount.js.map +1 -0
- package/dist/esm/modules/appCatalog/ui/layout/AppCatalogLayout.js +2 -2
- package/dist/esm/modules/appCatalog/ui/layout/AppCatalogLayout.js.map +1 -1
- package/dist/esm/modules/auth/AuthContext.js +7 -3
- package/dist/esm/modules/auth/AuthContext.js.map +1 -1
- package/dist/esm/modules/auth/ui/LoginModal.js +16 -8
- package/dist/esm/modules/auth/ui/LoginModal.js.map +1 -1
- package/dist/esm/modules/communityTools/likedBy.d.ts +8 -0
- package/dist/esm/modules/communityTools/likedBy.js +23 -0
- package/dist/esm/modules/communityTools/likedBy.js.map +1 -0
- package/dist/esm/modules/communityTools/timeAgo.d.ts +2 -0
- package/dist/esm/modules/communityTools/timeAgo.js +18 -0
- package/dist/esm/modules/communityTools/timeAgo.js.map +1 -0
- package/dist/esm/modules/communityTools/ui/CardScreenshot.d.ts +13 -0
- package/dist/esm/modules/communityTools/ui/CardScreenshot.js +112 -0
- package/dist/esm/modules/communityTools/ui/CardScreenshot.js.map +1 -0
- package/dist/esm/modules/communityTools/ui/CardTitleBlock.d.ts +8 -0
- package/dist/esm/modules/communityTools/ui/CardTitleBlock.js +59 -0
- package/dist/esm/modules/communityTools/ui/CardTitleBlock.js.map +1 -0
- package/dist/esm/modules/communityTools/ui/CommunityPage.d.ts +12 -0
- package/dist/esm/modules/communityTools/ui/CommunityPage.js +547 -0
- package/dist/esm/modules/communityTools/ui/CommunityPage.js.map +1 -0
- package/dist/esm/modules/communityTools/ui/FeedRow.d.ts +42 -0
- package/dist/esm/modules/communityTools/ui/FeedRow.js +260 -0
- package/dist/esm/modules/communityTools/ui/FeedRow.js.map +1 -0
- package/dist/esm/modules/communityTools/ui/FeedSortControl.d.ts +17 -0
- package/dist/esm/modules/communityTools/ui/FeedSortControl.js +84 -0
- package/dist/esm/modules/communityTools/ui/FeedSortControl.js.map +1 -0
- package/dist/esm/modules/communityTools/ui/LifecycleBadge.d.ts +7 -0
- package/dist/esm/modules/communityTools/ui/LifecycleBadge.js +50 -0
- package/dist/esm/modules/communityTools/ui/LifecycleBadge.js.map +1 -0
- package/dist/esm/modules/communityTools/ui/LikeButton.d.ts +9 -0
- package/dist/esm/modules/communityTools/ui/LikeButton.js +56 -0
- package/dist/esm/modules/communityTools/ui/LikeButton.js.map +1 -0
- package/dist/esm/modules/communityTools/ui/MarginPreview.d.ts +18 -0
- package/dist/esm/modules/communityTools/ui/MarginPreview.js +115 -0
- package/dist/esm/modules/communityTools/ui/MarginPreview.js.map +1 -0
- package/dist/esm/modules/communityTools/ui/MyToolsShelf.d.ts +12 -0
- package/dist/esm/modules/communityTools/ui/MyToolsShelf.js +88 -0
- package/dist/esm/modules/communityTools/ui/MyToolsShelf.js.map +1 -0
- package/dist/esm/modules/communityTools/ui/OwnerPicker.d.ts +56 -0
- package/dist/esm/modules/communityTools/ui/OwnerPicker.js +245 -0
- package/dist/esm/modules/communityTools/ui/OwnerPicker.js.map +1 -0
- package/dist/esm/modules/communityTools/ui/PinButton.d.ts +14 -0
- package/dist/esm/modules/communityTools/ui/PinButton.js +72 -0
- package/dist/esm/modules/communityTools/ui/PinButton.js.map +1 -0
- package/dist/esm/modules/communityTools/ui/ShelfTile.d.ts +13 -0
- package/dist/esm/modules/communityTools/ui/ShelfTile.js +81 -0
- package/dist/esm/modules/communityTools/ui/ShelfTile.js.map +1 -0
- package/dist/esm/modules/communityTools/ui/TagPicker.d.ts +21 -0
- package/dist/esm/modules/communityTools/ui/TagPicker.js +87 -0
- package/dist/esm/modules/communityTools/ui/TagPicker.js.map +1 -0
- package/dist/esm/modules/communityTools/ui/TagRow.d.ts +22 -0
- package/dist/esm/modules/communityTools/ui/TagRow.js +92 -0
- package/dist/esm/modules/communityTools/ui/TagRow.js.map +1 -0
- package/dist/esm/modules/communityTools/ui/Toast.d.ts +19 -0
- package/dist/esm/modules/communityTools/ui/Toast.js +87 -0
- package/dist/esm/modules/communityTools/ui/Toast.js.map +1 -0
- package/dist/esm/modules/communityTools/ui/ToolCard.d.ts +22 -0
- package/dist/esm/modules/communityTools/ui/ToolCard.js +467 -0
- package/dist/esm/modules/communityTools/ui/ToolCard.js.map +1 -0
- package/dist/esm/modules/communityTools/ui/ToolFormDialog.d.ts +32 -0
- package/dist/esm/modules/communityTools/ui/ToolFormDialog.js +765 -0
- package/dist/esm/modules/communityTools/ui/ToolFormDialog.js.map +1 -0
- package/dist/esm/modules/communityTools/ui/ToolSearch.d.ts +15 -0
- package/dist/esm/modules/communityTools/ui/ToolSearch.js +92 -0
- package/dist/esm/modules/communityTools/ui/ToolSearch.js.map +1 -0
- package/dist/esm/modules/communityTools/useCommunityTools.d.ts +157 -0
- package/dist/esm/modules/communityTools/useCommunityTools.js +122 -0
- package/dist/esm/modules/communityTools/useCommunityTools.js.map +1 -0
- package/dist/esm/modules/communityTools/useCommunityToolsConfig.d.ts +10 -0
- package/dist/esm/modules/communityTools/useCommunityToolsConfig.js +20 -0
- package/dist/esm/modules/communityTools/useCommunityToolsConfig.js.map +1 -0
- package/dist/esm/modules/communityTools/useTimeUp.d.ts +5 -0
- package/dist/esm/modules/communityTools/useTimeUp.js +13 -0
- package/dist/esm/modules/communityTools/useTimeUp.js.map +1 -0
- package/dist/esm/node_modules/.pnpm/zod@4.3.5/node_modules/zod/v4/classic/schemas.js +2 -2
- package/dist/esm/node_modules/.pnpm/zod@4.3.5/node_modules/zod/v4/core/schemas.js +1 -1
- package/dist/esm/routeTree.gen.d.ts +96 -3
- package/dist/esm/routeTree.gen.js +19 -0
- package/dist/esm/routeTree.gen.js.map +1 -1
- package/dist/esm/routes/_layout/community.$slug.d.ts +22 -0
- package/dist/esm/routes/_layout/community._slug.js +10 -0
- package/dist/esm/routes/_layout/community._slug.js.map +1 -0
- package/dist/esm/routes/_layout/community.d.ts +23 -0
- package/dist/esm/routes/_layout/community.js +71 -0
- package/dist/esm/routes/_layout/community.js.map +1 -0
- package/dist/esm/ui/components/header/Header.js +7 -3
- package/dist/esm/ui/components/header/Header.js.map +1 -1
- package/dist/esm/util/highlightMatches.d.ts +2 -0
- package/dist/esm/util/highlightMatches.js +32 -0
- package/dist/esm/util/highlightMatches.js.map +1 -0
- package/dist/index.css +6 -0
- package/package.json +5 -5
- package/src/__tests__/modules/appCatalog/ui/catalog/AppDetailPanel.appSwitch.test.tsx +3 -0
- package/src/__tests__/modules/appCatalog/ui/catalog/AppDetailPanel.enter.test.tsx +3 -0
- package/src/__tests__/modules/appCatalog/ui/detail/AppDetails.background.test.tsx +3 -0
- package/src/__tests__/modules/appCatalog/ui/detail/AppDetails.behindThisCard.test.tsx +4 -0
- package/src/__tests__/modules/appCatalog/ui/detail/AppDetails.doorAndTabs.test.tsx +3 -0
- package/src/__tests__/modules/appCatalog/ui/detail/AppDetails.escape.test.tsx +3 -0
- package/src/__tests__/modules/appCatalog/ui/detail/AppDetails.knowMore.test.tsx +3 -0
- package/src/__tests__/modules/appCatalog/ui/detail/AppDetails.sectionOrder.test.tsx +3 -0
- package/src/__tests__/modules/appCatalog/ui/detail/AppDetails.subResourceTab.test.tsx +3 -0
- package/src/__tests__/modules/appCatalog/ui/detail/AppDetails.tags.test.tsx +3 -0
- package/src/__tests__/modules/appCatalog/ui/detail/CommunitySection.feed.test.tsx +10 -3
- package/src/__tests__/modules/appCatalog/ui/detail/CommunitySection.help.test.tsx +4 -1
- package/src/__tests__/modules/appCatalog/ui/detail/CommunitySection.input.test.tsx +12 -2
- package/src/__tests__/modules/appCatalog/ui/detail/composeComments.test.ts +1 -0
- package/src/__tests__/modules/auth/AuthContext.test.tsx +55 -0
- package/src/__tests__/modules/communityTools/likedBy.test.ts +45 -0
- package/src/__tests__/modules/communityTools/timeAgo.test.ts +28 -0
- package/src/__tests__/modules/communityTools/useTimeUp.test.ts +31 -0
- package/src/__tests__/ui/components/header/Header.login.test.tsx +4 -4
- package/src/api/infra/trpc.ts +2 -0
- package/src/index.css +6 -0
- package/src/modules/appCatalog/ui/catalog/AppDetailPanel.tsx +33 -176
- package/src/modules/appCatalog/ui/catalog/DetailDialogShell.tsx +199 -0
- package/src/modules/appCatalog/ui/components/ScreenshotGallery.tsx +2 -1
- package/src/modules/appCatalog/ui/components/SectionTabs.tsx +81 -0
- package/src/modules/appCatalog/ui/detail/AppDetails.tsx +17 -2
- package/src/modules/appCatalog/ui/detail/CommentsFeed.tsx +9 -4
- package/src/modules/appCatalog/ui/detail/CommentsHelp.tsx +6 -3
- package/src/modules/appCatalog/ui/detail/CommunityInput.tsx +15 -10
- package/src/modules/appCatalog/ui/detail/CommunitySection.tsx +10 -5
- package/src/modules/appCatalog/ui/detail/communityDraft.ts +16 -0
- package/src/modules/appCatalog/ui/detail/composeComments.ts +1 -0
- package/src/modules/appCatalog/ui/detail/useCommunityToolCount.ts +18 -0
- package/src/modules/appCatalog/ui/layout/AppCatalogLayout.tsx +2 -2
- package/src/modules/auth/AuthContext.tsx +9 -3
- package/src/modules/auth/ui/LoginModal.tsx +7 -2
- package/src/modules/communityTools/likedBy.ts +32 -0
- package/src/modules/communityTools/timeAgo.ts +16 -0
- package/src/modules/communityTools/ui/CardScreenshot.tsx +124 -0
- package/src/modules/communityTools/ui/CardTitleBlock.tsx +58 -0
- package/src/modules/communityTools/ui/CommunityPage.tsx +626 -0
- package/src/modules/communityTools/ui/FeedRow.tsx +310 -0
- package/src/modules/communityTools/ui/FeedSortControl.tsx +97 -0
- package/src/modules/communityTools/ui/LifecycleBadge.tsx +44 -0
- package/src/modules/communityTools/ui/LikeButton.tsx +56 -0
- package/src/modules/communityTools/ui/MarginPreview.tsx +143 -0
- package/src/modules/communityTools/ui/MyToolsShelf.tsx +112 -0
- package/src/modules/communityTools/ui/OwnerPicker.tsx +311 -0
- package/src/modules/communityTools/ui/PinButton.tsx +87 -0
- package/src/modules/communityTools/ui/ShelfTile.tsx +83 -0
- package/src/modules/communityTools/ui/TagPicker.tsx +118 -0
- package/src/modules/communityTools/ui/TagRow.tsx +118 -0
- package/src/modules/communityTools/ui/Toast.tsx +105 -0
- package/src/modules/communityTools/ui/ToolCard.tsx +519 -0
- package/src/modules/communityTools/ui/ToolFormDialog.tsx +922 -0
- package/src/modules/communityTools/ui/ToolSearch.tsx +111 -0
- package/src/modules/communityTools/useCommunityTools.ts +146 -0
- package/src/modules/communityTools/useCommunityToolsConfig.ts +26 -0
- package/src/modules/communityTools/useTimeUp.ts +14 -0
- package/src/routeTree.gen.ts +52 -0
- package/src/routes/_layout/community.$slug.tsx +7 -0
- package/src/routes/_layout/community.tsx +97 -0
- package/src/ui/components/header/Header.tsx +9 -3
- package/src/util/highlightMatches.tsx +34 -0
- package/dist/esm/modules/appCatalog/ui/components/ViewToggle.d.ts +0 -12
- package/dist/esm/modules/appCatalog/ui/components/ViewToggle.js +0 -56
- package/dist/esm/modules/appCatalog/ui/components/ViewToggle.js.map +0 -1
- package/src/modules/appCatalog/ui/components/ViewToggle.tsx +0 -59
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { jsx, Fragment } from "react/jsx-runtime";
|
|
2
|
+
import React__default from "react";
|
|
3
|
+
function escapeRegex(str) {
|
|
4
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
5
|
+
}
|
|
6
|
+
function highlightMatches(text, query) {
|
|
7
|
+
if (!query) return text;
|
|
8
|
+
const safeQuery = escapeRegex(query);
|
|
9
|
+
const regex = new RegExp(`(${safeQuery})`, "gi");
|
|
10
|
+
const parts = text.split(regex);
|
|
11
|
+
return /* @__PURE__ */ jsx(Fragment, { children: parts.map((part, idx) => {
|
|
12
|
+
const key = `${part}-${text.indexOf(part, idx)}`;
|
|
13
|
+
return idx % 2 === 1 ? /* @__PURE__ */ jsx("span", { className: "bg-highlight", children: part }, key) : /* @__PURE__ */ jsx(React__default.Fragment, { children: part }, key);
|
|
14
|
+
}) });
|
|
15
|
+
}
|
|
16
|
+
function highlightTokens(text, tokens) {
|
|
17
|
+
const words = tokens.filter(Boolean);
|
|
18
|
+
if (words.length === 0) return text;
|
|
19
|
+
const alternation = [...words].sort((a, b) => b.length - a.length).map(escapeRegex).join("|");
|
|
20
|
+
const parts = text.split(new RegExp(`(${alternation})`, "gi"));
|
|
21
|
+
let offset = 0;
|
|
22
|
+
return /* @__PURE__ */ jsx(Fragment, { children: parts.map((part, idx) => {
|
|
23
|
+
const key = `${offset}-${idx % 2}`;
|
|
24
|
+
offset += part.length;
|
|
25
|
+
return idx % 2 === 1 ? /* @__PURE__ */ jsx("span", { className: "rounded-[3px] bg-highlight", children: part }, key) : /* @__PURE__ */ jsx(React__default.Fragment, { children: part }, key);
|
|
26
|
+
}) });
|
|
27
|
+
}
|
|
28
|
+
export {
|
|
29
|
+
highlightMatches,
|
|
30
|
+
highlightTokens
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=highlightMatches.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"highlightMatches.js","sources":["../../../src/util/highlightMatches.tsx"],"sourcesContent":["import React from 'react'\n\n// Escape regex special characters\nfunction escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n}\n\nexport function highlightMatches(text: string, query: string): React.ReactNode {\n if (!query) return text\n\n const safeQuery = escapeRegex(query)\n const regex = new RegExp(`(${safeQuery})`, 'gi')\n const parts = text.split(regex)\n\n return (\n <>\n {parts.map((part, idx) => {\n const key = `${part}-${text.indexOf(part, idx)}`\n return idx % 2 === 1 ? (\n <span key={key} className=\"bg-highlight\">\n {part}\n </span>\n ) : (\n <React.Fragment key={key}>{part}</React.Fragment>\n )\n })}\n </>\n )\n}\n\n/** Like `highlightMatches`, for several search words at once, in any order. */\nexport function highlightTokens(\n text: string,\n tokens: string[],\n): React.ReactNode {\n const words = tokens.filter(Boolean)\n if (words.length === 0) return text\n\n // Longest first, so \"runbook\" wins over its own prefix \"run\".\n const alternation = [...words]\n .sort((a, b) => b.length - a.length)\n .map(escapeRegex)\n .join('|')\n const parts = text.split(new RegExp(`(${alternation})`, 'gi'))\n\n let offset = 0\n return (\n <>\n {parts.map((part, idx) => {\n // An empty part shares its offset with the match after it; parity splits them.\n const key = `${offset}-${idx % 2}`\n offset += part.length\n return idx % 2 === 1 ? (\n <span key={key} className=\"rounded-[3px] bg-highlight\">\n {part}\n </span>\n ) : (\n <React.Fragment key={key}>{part}</React.Fragment>\n )\n })}\n </>\n )\n}\n"],"names":["React"],"mappings":";;AAGA,SAAS,YAAY,KAAqB;AACxC,SAAO,IAAI,QAAQ,uBAAuB,MAAM;AAClD;AAEO,SAAS,iBAAiB,MAAc,OAAgC;AAC7E,MAAI,CAAC,MAAO,QAAO;AAEnB,QAAM,YAAY,YAAY,KAAK;AACnC,QAAM,QAAQ,IAAI,OAAO,IAAI,SAAS,KAAK,IAAI;AAC/C,QAAM,QAAQ,KAAK,MAAM,KAAK;AAE9B,SACE,oBAAA,UAAA,EACG,UAAA,MAAM,IAAI,CAAC,MAAM,QAAQ;AACxB,UAAM,MAAM,GAAG,IAAI,IAAI,KAAK,QAAQ,MAAM,GAAG,CAAC;AAC9C,WAAO,MAAM,MAAM,IACjB,oBAAC,UAAe,WAAU,gBACvB,UAAA,KAAA,GADQ,GAEX,IAEA,oBAACA,eAAM,UAAN,EAA0B,kBAAN,GAAW;AAAA,EAEpC,CAAC,EAAA,CACH;AAEJ;AAGO,SAAS,gBACd,MACA,QACiB;AACjB,QAAM,QAAQ,OAAO,OAAO,OAAO;AACnC,MAAI,MAAM,WAAW,EAAG,QAAO;AAG/B,QAAM,cAAc,CAAC,GAAG,KAAK,EAC1B,KAAK,CAAC,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM,EAClC,IAAI,WAAW,EACf,KAAK,GAAG;AACX,QAAM,QAAQ,KAAK,MAAM,IAAI,OAAO,IAAI,WAAW,KAAK,IAAI,CAAC;AAE7D,MAAI,SAAS;AACb,SACE,oBAAA,UAAA,EACG,UAAA,MAAM,IAAI,CAAC,MAAM,QAAQ;AAExB,UAAM,MAAM,GAAG,MAAM,IAAI,MAAM,CAAC;AAChC,cAAU,KAAK;AACf,WAAO,MAAM,MAAM,IACjB,oBAAC,UAAe,WAAU,8BACvB,UAAA,KAAA,GADQ,GAEX,IAEA,oBAACA,eAAM,UAAN,EAA0B,kBAAN,GAAW;AAAA,EAEpC,CAAC,EAAA,CACH;AAEJ;"}
|
package/dist/index.css
CHANGED
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
--muted-foreground: oklch(0.52 0.025 60);
|
|
34
34
|
--accent: oklch(0.93 0.05 70); /* soft amber accent */
|
|
35
35
|
--accent-foreground: oklch(0.36 0.04 55);
|
|
36
|
+
--highlight: oklch(0.88 0.11 80); /* search-match marker */
|
|
36
37
|
--destructive: oklch(0.6368 0.2078 25.3313);
|
|
37
38
|
--destructive-foreground: oklch(1 0 0);
|
|
38
39
|
--border: oklch(0.9 0.018 80); /* warm hairline */
|
|
@@ -714,6 +715,11 @@
|
|
|
714
715
|
font-style: italic;
|
|
715
716
|
color: var(--muted-foreground);
|
|
716
717
|
}
|
|
718
|
+
/* A line the system wrote when a tool changed: context, not someone's note. */
|
|
719
|
+
.comment__text.is-system {
|
|
720
|
+
font-size: 0.84375rem;
|
|
721
|
+
color: var(--muted-foreground);
|
|
722
|
+
}
|
|
717
723
|
.comment__reply {
|
|
718
724
|
margin-top: 0.25rem;
|
|
719
725
|
font-size: 0.84375rem;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@igstack/app-catalog-frontend-core",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.11.0",
|
|
4
4
|
"description": "Frontend core library for App Catalog",
|
|
5
5
|
"homepage": "https://github.com/lislon/app-catalog",
|
|
6
6
|
"repository": {
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
"@tanstack/react-query": "^5.90.12",
|
|
74
74
|
"@tanstack/react-query-devtools": "^5.91.1",
|
|
75
75
|
"@tanstack/react-table": "^8.21.3",
|
|
76
|
-
"@tanstack/react-virtual": "3.
|
|
76
|
+
"@tanstack/react-virtual": "3.14.21",
|
|
77
77
|
"@tanstack/router-plugin": "1.168.42",
|
|
78
78
|
"@tiptap/extension-link": "^2.10.0",
|
|
79
79
|
"@tiptap/extension-placeholder": "^2.10.0",
|
|
@@ -118,7 +118,7 @@
|
|
|
118
118
|
"tailwindcss": "^4.1.7",
|
|
119
119
|
"tiptap-markdown": "^0.8.0",
|
|
120
120
|
"tslib": "^2.3.0",
|
|
121
|
-
"@igstack/app-catalog-shared-core": "6.
|
|
121
|
+
"@igstack/app-catalog-shared-core": "6.11.0"
|
|
122
122
|
},
|
|
123
123
|
"devDependencies": {
|
|
124
124
|
"@tailwindcss/vite": "^4.0.5",
|
|
@@ -146,7 +146,7 @@
|
|
|
146
146
|
"vite-plugin-static-copy": "^3.1.4",
|
|
147
147
|
"vite-plugin-svgr": "^4.2.0",
|
|
148
148
|
"vitest": "^4.1.2",
|
|
149
|
-
"@igstack/app-catalog-backend-core": "6.
|
|
149
|
+
"@igstack/app-catalog-backend-core": "6.11.0"
|
|
150
150
|
},
|
|
151
151
|
"peerDependencies": {
|
|
152
152
|
"@tanstack/react-router": "1.170.41",
|
|
@@ -156,7 +156,7 @@
|
|
|
156
156
|
"vite": "^6.3.5",
|
|
157
157
|
"vite-plugin-svgr": "^4.2.0"
|
|
158
158
|
},
|
|
159
|
-
"gitHead": "
|
|
159
|
+
"gitHead": "f4c72c2178cd9a3ec6695cfbb243ff3d0737ad1b",
|
|
160
160
|
"scripts": {
|
|
161
161
|
"build": "vite build",
|
|
162
162
|
"build:lenient": "vite build --mode lenient",
|
|
@@ -23,6 +23,9 @@ vi.mock('~/modules/appCatalog/context/AppCatalogContext', () => ({
|
|
|
23
23
|
vi.mock('~/modules/appCatalog/hooks/useAppClickHistory', () => ({
|
|
24
24
|
useAppClickHistory: vi.fn(() => ({ recordClick: vi.fn() })),
|
|
25
25
|
}))
|
|
26
|
+
vi.mock('~/modules/appCatalog/ui/detail/useCommunityToolCount', () => ({
|
|
27
|
+
useCommunityToolCount: vi.fn(() => 0),
|
|
28
|
+
}))
|
|
26
29
|
vi.mock('~/modules/appCatalog/hooks/useUpdateApp', () => ({
|
|
27
30
|
useUpdateApp: vi.fn(() => ({ mutate: vi.fn() })),
|
|
28
31
|
}))
|
|
@@ -20,6 +20,9 @@ vi.mock('~/modules/appCatalog/context/AppCatalogContext', () => ({
|
|
|
20
20
|
vi.mock('~/modules/appCatalog/hooks/useAppClickHistory', () => ({
|
|
21
21
|
useAppClickHistory: vi.fn(() => ({ recordClick: vi.fn() })),
|
|
22
22
|
}))
|
|
23
|
+
vi.mock('~/modules/appCatalog/ui/detail/useCommunityToolCount', () => ({
|
|
24
|
+
useCommunityToolCount: vi.fn(() => 0),
|
|
25
|
+
}))
|
|
23
26
|
vi.mock('~/modules/appCatalog/hooks/useUpdateApp', () => ({
|
|
24
27
|
useUpdateApp: vi.fn(() => ({ mutate: vi.fn() })),
|
|
25
28
|
}))
|
|
@@ -21,6 +21,9 @@ vi.mock('~/modules/appCatalog/context/AppCatalogContext', () => ({
|
|
|
21
21
|
vi.mock('~/modules/appCatalog/hooks/useAppClickHistory', () => ({
|
|
22
22
|
useAppClickHistory: vi.fn(() => ({ recordClick: vi.fn() })),
|
|
23
23
|
}))
|
|
24
|
+
vi.mock('~/modules/appCatalog/ui/detail/useCommunityToolCount', () => ({
|
|
25
|
+
useCommunityToolCount: vi.fn(() => 0),
|
|
26
|
+
}))
|
|
24
27
|
vi.mock('~/modules/appCatalog/hooks/useUpdateApp', () => ({
|
|
25
28
|
useUpdateApp: vi.fn(() => ({ mutate: vi.fn() })),
|
|
26
29
|
}))
|
|
@@ -28,6 +28,9 @@ vi.mock('~/modules/appCatalog/context/AppCatalogContext', () => ({
|
|
|
28
28
|
vi.mock('~/modules/appCatalog/hooks/useAppClickHistory', () => ({
|
|
29
29
|
useAppClickHistory: vi.fn(() => ({ recordClick: vi.fn() })),
|
|
30
30
|
}))
|
|
31
|
+
vi.mock('~/modules/appCatalog/ui/detail/useCommunityToolCount', () => ({
|
|
32
|
+
useCommunityToolCount: vi.fn(() => 0),
|
|
33
|
+
}))
|
|
31
34
|
vi.mock('~/modules/appCatalog/hooks/useUpdateApp', () => ({
|
|
32
35
|
useUpdateApp: vi.fn(() => ({ mutate: vi.fn() })),
|
|
33
36
|
}))
|
|
@@ -283,6 +286,7 @@ const pendingNote = {
|
|
|
283
286
|
reviewedAt: null,
|
|
284
287
|
editedAt: null,
|
|
285
288
|
isMine: false,
|
|
289
|
+
isSystem: false,
|
|
286
290
|
canEditUntil: null,
|
|
287
291
|
status: null,
|
|
288
292
|
reviewerReply: null,
|
|
@@ -26,6 +26,9 @@ vi.mock('~/modules/appCatalog/context/AppCatalogContext', () => ({
|
|
|
26
26
|
vi.mock('~/modules/appCatalog/hooks/useAppClickHistory', () => ({
|
|
27
27
|
useAppClickHistory: vi.fn(() => ({ recordClick: vi.fn() })),
|
|
28
28
|
}))
|
|
29
|
+
vi.mock('~/modules/appCatalog/ui/detail/useCommunityToolCount', () => ({
|
|
30
|
+
useCommunityToolCount: vi.fn(() => 0),
|
|
31
|
+
}))
|
|
29
32
|
vi.mock('~/modules/appCatalog/hooks/useUpdateApp', () => ({
|
|
30
33
|
useUpdateApp: vi.fn(() => ({ mutate: vi.fn() })),
|
|
31
34
|
}))
|
|
@@ -22,6 +22,9 @@ vi.mock('~/modules/appCatalog/context/AppCatalogContext', () => ({
|
|
|
22
22
|
vi.mock('~/modules/appCatalog/hooks/useAppClickHistory', () => ({
|
|
23
23
|
useAppClickHistory: vi.fn(() => ({ recordClick: vi.fn() })),
|
|
24
24
|
}))
|
|
25
|
+
vi.mock('~/modules/appCatalog/ui/detail/useCommunityToolCount', () => ({
|
|
26
|
+
useCommunityToolCount: vi.fn(() => 0),
|
|
27
|
+
}))
|
|
25
28
|
vi.mock('~/modules/appCatalog/hooks/useUpdateApp', () => ({
|
|
26
29
|
useUpdateApp: vi.fn(() => ({ mutate: vi.fn() })),
|
|
27
30
|
}))
|
|
@@ -22,6 +22,9 @@ vi.mock('~/modules/appCatalog/context/AppCatalogContext', () => ({
|
|
|
22
22
|
vi.mock('~/modules/appCatalog/hooks/useAppClickHistory', () => ({
|
|
23
23
|
useAppClickHistory: vi.fn(() => ({ recordClick: vi.fn() })),
|
|
24
24
|
}))
|
|
25
|
+
vi.mock('~/modules/appCatalog/ui/detail/useCommunityToolCount', () => ({
|
|
26
|
+
useCommunityToolCount: vi.fn(() => 0),
|
|
27
|
+
}))
|
|
25
28
|
vi.mock('~/modules/appCatalog/hooks/useUpdateApp', () => ({
|
|
26
29
|
useUpdateApp: vi.fn(() => ({ mutate: vi.fn() })),
|
|
27
30
|
}))
|
|
@@ -23,6 +23,9 @@ vi.mock('~/modules/appCatalog/context/AppCatalogContext', () => ({
|
|
|
23
23
|
vi.mock('~/modules/appCatalog/hooks/useAppClickHistory', () => ({
|
|
24
24
|
useAppClickHistory: vi.fn(() => ({ recordClick: vi.fn() })),
|
|
25
25
|
}))
|
|
26
|
+
vi.mock('~/modules/appCatalog/ui/detail/useCommunityToolCount', () => ({
|
|
27
|
+
useCommunityToolCount: vi.fn(() => 0),
|
|
28
|
+
}))
|
|
26
29
|
vi.mock('~/modules/appCatalog/hooks/useUpdateApp', () => ({
|
|
27
30
|
useUpdateApp: vi.fn(() => ({ mutate: vi.fn() })),
|
|
28
31
|
}))
|
|
@@ -56,6 +56,9 @@ vi.mock('~/modules/appCatalog/context/AppCatalogContext', () => ({
|
|
|
56
56
|
vi.mock('~/modules/appCatalog/hooks/useAppClickHistory', () => ({
|
|
57
57
|
useAppClickHistory: vi.fn(() => ({ recordClick: vi.fn() })),
|
|
58
58
|
}))
|
|
59
|
+
vi.mock('~/modules/appCatalog/ui/detail/useCommunityToolCount', () => ({
|
|
60
|
+
useCommunityToolCount: vi.fn(() => 0),
|
|
61
|
+
}))
|
|
59
62
|
vi.mock('~/modules/appCatalog/hooks/useUpdateApp', () => ({
|
|
60
63
|
useUpdateApp: vi.fn(() => ({ mutate: vi.fn() })),
|
|
61
64
|
}))
|
|
@@ -21,6 +21,9 @@ vi.mock('~/modules/appCatalog/context/AppCatalogContext', () => ({
|
|
|
21
21
|
vi.mock('~/modules/appCatalog/hooks/useAppClickHistory', () => ({
|
|
22
22
|
useAppClickHistory: vi.fn(() => ({ recordClick: vi.fn() })),
|
|
23
23
|
}))
|
|
24
|
+
vi.mock('~/modules/appCatalog/ui/detail/useCommunityToolCount', () => ({
|
|
25
|
+
useCommunityToolCount: vi.fn(() => 0),
|
|
26
|
+
}))
|
|
24
27
|
vi.mock('~/modules/appCatalog/hooks/useUpdateApp', () => ({
|
|
25
28
|
useUpdateApp: vi.fn(() => ({ mutate: vi.fn() })),
|
|
26
29
|
}))
|
|
@@ -50,6 +50,7 @@ const note = {
|
|
|
50
50
|
reviewedAt: null as string | null,
|
|
51
51
|
editedAt: null,
|
|
52
52
|
isMine: false,
|
|
53
|
+
isSystem: false,
|
|
53
54
|
canEditUntil: null as string | null,
|
|
54
55
|
status: null as string | null,
|
|
55
56
|
reviewerReply: null as string | null,
|
|
@@ -58,7 +59,7 @@ const note = {
|
|
|
58
59
|
function mount(claims: Claim[] = []) {
|
|
59
60
|
render(
|
|
60
61
|
<CommunitySection
|
|
61
|
-
|
|
62
|
+
target={{ resourceSlug: 'example-app' }}
|
|
62
63
|
appName="Example App"
|
|
63
64
|
claims={claims}
|
|
64
65
|
/>,
|
|
@@ -190,7 +191,10 @@ describe('CommunitySection — the Comments feed', () => {
|
|
|
190
191
|
it('offers Dismiss on your own open note, and not once it is answered', () => {
|
|
191
192
|
state.items = [{ ...note, isMine: true }]
|
|
192
193
|
const { unmount } = render(
|
|
193
|
-
<CommunitySection
|
|
194
|
+
<CommunitySection
|
|
195
|
+
target={{ resourceSlug: 'example-app' }}
|
|
196
|
+
appName="Example App"
|
|
197
|
+
/>,
|
|
194
198
|
)
|
|
195
199
|
expect(screen.getByRole('button', { name: 'Dismiss' })).toBeInTheDocument()
|
|
196
200
|
expect(screen.queryByRole('button', { name: 'Edit' })).toBeNull()
|
|
@@ -262,7 +266,10 @@ describe('CommunitySection — the Comments feed', () => {
|
|
|
262
266
|
isPending: true,
|
|
263
267
|
} as never)
|
|
264
268
|
const { unmount } = render(
|
|
265
|
-
<CommunitySection
|
|
269
|
+
<CommunitySection
|
|
270
|
+
target={{ resourceSlug: 'example-app' }}
|
|
271
|
+
appName="Example App"
|
|
272
|
+
/>,
|
|
266
273
|
)
|
|
267
274
|
expect(screen.getByText('Loading comments…')).toBeInTheDocument()
|
|
268
275
|
unmount()
|
|
@@ -52,7 +52,10 @@ function mount(plugins: AcPlugin[] | undefined) {
|
|
|
52
52
|
return render(
|
|
53
53
|
<ExtensionsContext value={plugins}>
|
|
54
54
|
<Card onClose={onCardClose}>
|
|
55
|
-
<CommunitySection
|
|
55
|
+
<CommunitySection
|
|
56
|
+
target={{ resourceSlug: 'test-app' }}
|
|
57
|
+
appName="Test App"
|
|
58
|
+
/>
|
|
56
59
|
</Card>
|
|
57
60
|
</ExtensionsContext>,
|
|
58
61
|
)
|
|
@@ -85,7 +85,12 @@ afterEach(() => {
|
|
|
85
85
|
})
|
|
86
86
|
|
|
87
87
|
const mount = () =>
|
|
88
|
-
render(
|
|
88
|
+
render(
|
|
89
|
+
<CommunitySection
|
|
90
|
+
target={{ resourceSlug: 'team-board' }}
|
|
91
|
+
appName="Team Board"
|
|
92
|
+
/>,
|
|
93
|
+
)
|
|
89
94
|
const field = () =>
|
|
90
95
|
screen.getByRole('textbox', { name: 'Know more about Team Board?' })
|
|
91
96
|
const send = () => screen.getByText('Send')
|
|
@@ -349,7 +354,12 @@ describe('CommunitySection — screenshots', () => {
|
|
|
349
354
|
await userEvent.type(field(), 'about this one')
|
|
350
355
|
first.unmount()
|
|
351
356
|
|
|
352
|
-
render(
|
|
357
|
+
render(
|
|
358
|
+
<CommunitySection
|
|
359
|
+
target={{ resourceSlug: 'other-app' }}
|
|
360
|
+
appName="Other"
|
|
361
|
+
/>,
|
|
362
|
+
)
|
|
353
363
|
expect(
|
|
354
364
|
screen.getByRole('textbox', { name: 'Know more about Other?' }),
|
|
355
365
|
).toHaveValue('')
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { renderHook, waitFor } from '@testing-library/react'
|
|
2
|
+
import { afterEach, describe, expect, it, vi } from 'vitest'
|
|
3
|
+
import { AuthProvider, useAuth } from '~/modules/auth/AuthContext'
|
|
4
|
+
|
|
5
|
+
// The session endpoint answers `{ ...session, isAdmin }`: admin rights sit
|
|
6
|
+
// beside the user, not on it.
|
|
7
|
+
function serveSession(body: unknown) {
|
|
8
|
+
vi.stubGlobal(
|
|
9
|
+
'fetch',
|
|
10
|
+
vi.fn().mockResolvedValue({ ok: true, json: async () => body }),
|
|
11
|
+
)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function renderAuth() {
|
|
15
|
+
return renderHook(() => useAuth(), {
|
|
16
|
+
wrapper: ({ children }) => <AuthProvider>{children}</AuthProvider>,
|
|
17
|
+
})
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
describe('AuthProvider', () => {
|
|
21
|
+
afterEach(() => {
|
|
22
|
+
vi.unstubAllGlobals()
|
|
23
|
+
localStorage.clear()
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
it('session with top-level isAdmin yields user.isAdmin true', async () => {
|
|
27
|
+
serveSession({ user: { id: 'u1', name: 'Ada Admin' }, isAdmin: true })
|
|
28
|
+
|
|
29
|
+
const { result } = renderAuth()
|
|
30
|
+
|
|
31
|
+
await waitFor(() => expect(result.current.isLoading).toBe(false))
|
|
32
|
+
expect(result.current.user).toEqual({
|
|
33
|
+
id: 'u1',
|
|
34
|
+
name: 'Ada Admin',
|
|
35
|
+
isAdmin: true,
|
|
36
|
+
})
|
|
37
|
+
// The optimistic copy the next load renders from keeps it too.
|
|
38
|
+
expect(JSON.parse(localStorage.getItem('ac_auth_user') ?? 'null')).toEqual(
|
|
39
|
+
result.current.user,
|
|
40
|
+
)
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
it('session without isAdmin yields user.isAdmin false', async () => {
|
|
44
|
+
serveSession({ user: { id: 'u2', name: 'Robin Reader' } })
|
|
45
|
+
|
|
46
|
+
const { result } = renderAuth()
|
|
47
|
+
|
|
48
|
+
await waitFor(() => expect(result.current.isLoading).toBe(false))
|
|
49
|
+
expect(result.current.user).toEqual({
|
|
50
|
+
id: 'u2',
|
|
51
|
+
name: 'Robin Reader',
|
|
52
|
+
isAdmin: false,
|
|
53
|
+
})
|
|
54
|
+
})
|
|
55
|
+
})
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import type { CommunityTool } from '@igstack/app-catalog-shared-core'
|
|
3
|
+
import { likedByText, withLike } from '~/modules/communityTools/likedBy'
|
|
4
|
+
|
|
5
|
+
describe('likedByText', () => {
|
|
6
|
+
const text = (likes: number, likedByMe: boolean, likedBy: string[]) =>
|
|
7
|
+
likedByText({ likes, likedByMe, likedBy })
|
|
8
|
+
const nine = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
|
|
9
|
+
|
|
10
|
+
it('names colleagues, the last after "and"', () => {
|
|
11
|
+
expect(text(0, false, [])).toBe('No likes yet')
|
|
12
|
+
expect(text(1, false, ['Ann'])).toBe('Liked by Ann')
|
|
13
|
+
expect(text(3, false, ['Ann', 'Bob', 'Cy'])).toBe(
|
|
14
|
+
'Liked by Ann, Bob and Cy',
|
|
15
|
+
)
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
it('puts you first', () => {
|
|
19
|
+
expect(text(1, true, [])).toBe('Liked by you')
|
|
20
|
+
expect(text(2, true, ['Ann'])).toBe('Liked by you and Ann')
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('names eight colleagues at most, and counts the rest', () => {
|
|
24
|
+
expect(text(13, true, nine)).toBe(
|
|
25
|
+
'Liked by you, A, B, C, D, E, F, G, H and 4 others',
|
|
26
|
+
)
|
|
27
|
+
expect(text(9, false, nine)).toBe(
|
|
28
|
+
'Liked by A, B, C, D, E, F, G, H and 1 other',
|
|
29
|
+
)
|
|
30
|
+
})
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
describe('withLike', () => {
|
|
34
|
+
const tool = { likes: 2, likedByMe: false, likedBy: ['Bob'] } as CommunityTool
|
|
35
|
+
|
|
36
|
+
it('counts my like in, and out again', () => {
|
|
37
|
+
const liked = withLike(tool, true)
|
|
38
|
+
expect(liked).toMatchObject({ likes: 3, likedByMe: true, likedBy: ['Bob'] })
|
|
39
|
+
expect(withLike(liked, false)).toMatchObject(tool)
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
it('leaves a tool that already reads that way alone', () => {
|
|
43
|
+
expect(withLike(tool, false)).toBe(tool)
|
|
44
|
+
})
|
|
45
|
+
})
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import { timeAgo } from '~/modules/communityTools/timeAgo'
|
|
3
|
+
|
|
4
|
+
describe('timeAgo', () => {
|
|
5
|
+
const now = new Date(2026, 9, 21, 9, 0)
|
|
6
|
+
const before = (days: number) =>
|
|
7
|
+
new Date(2026, 9, 21 - days, 23, 30).toISOString()
|
|
8
|
+
|
|
9
|
+
it('counts calendar days, then months, then years', () => {
|
|
10
|
+
expect(
|
|
11
|
+
[0, 1, 3, 30, 31, 61, 364, 365, 800].map((d) => timeAgo(before(d), now)),
|
|
12
|
+
).toEqual([
|
|
13
|
+
'today',
|
|
14
|
+
'yesterday',
|
|
15
|
+
'3 days ago',
|
|
16
|
+
'30 days ago',
|
|
17
|
+
'1 month ago',
|
|
18
|
+
'2 months ago',
|
|
19
|
+
'12 months ago',
|
|
20
|
+
'1 year ago',
|
|
21
|
+
'2 years ago',
|
|
22
|
+
])
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it('reads a time in the future as today', () => {
|
|
26
|
+
expect(timeAgo(new Date(2026, 9, 22).toISOString(), now)).toBe('today')
|
|
27
|
+
})
|
|
28
|
+
})
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { act, renderHook } from '@testing-library/react'
|
|
2
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
3
|
+
import { useTimeUp } from '~/modules/communityTools/useTimeUp'
|
|
4
|
+
|
|
5
|
+
const TWO_MINUTES = 2 * 60 * 1000
|
|
6
|
+
|
|
7
|
+
describe('useTimeUp', () => {
|
|
8
|
+
beforeEach(() => vi.useFakeTimers())
|
|
9
|
+
afterEach(() => vi.useRealTimers())
|
|
10
|
+
|
|
11
|
+
it('turns true at the limit and not a moment before', () => {
|
|
12
|
+
const { result } = renderHook(() => useTimeUp('fresh-tool', TWO_MINUTES))
|
|
13
|
+
act(() => vi.advanceTimersByTime(TWO_MINUTES - 1))
|
|
14
|
+
expect(result.current).toBe(false)
|
|
15
|
+
act(() => vi.advanceTimersByTime(1))
|
|
16
|
+
expect(result.current).toBe(true)
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
it('starts again for a new key', () => {
|
|
20
|
+
const { result, rerender } = renderHook(
|
|
21
|
+
({ key }) => useTimeUp(key, TWO_MINUTES),
|
|
22
|
+
{ initialProps: { key: 'fresh-tool' } },
|
|
23
|
+
)
|
|
24
|
+
act(() => vi.advanceTimersByTime(TWO_MINUTES))
|
|
25
|
+
expect(result.current).toBe(true)
|
|
26
|
+
rerender({ key: 'other-tool' })
|
|
27
|
+
expect(result.current).toBe(false)
|
|
28
|
+
act(() => vi.advanceTimersByTime(TWO_MINUTES))
|
|
29
|
+
expect(result.current).toBe(true)
|
|
30
|
+
})
|
|
31
|
+
})
|
|
@@ -54,11 +54,11 @@ beforeEach(() => {
|
|
|
54
54
|
})
|
|
55
55
|
|
|
56
56
|
describe('Header login button', () => {
|
|
57
|
-
it('offers an anonymous visitor a
|
|
57
|
+
it('offers an anonymous visitor a Sign in button that opens the sign-in modal', async () => {
|
|
58
58
|
window.history.pushState({}, '', '/app/sample-review-app?tab=access')
|
|
59
59
|
render(<Header />)
|
|
60
60
|
|
|
61
|
-
await userEvent.click(screen.getByRole('button', { name: '
|
|
61
|
+
await userEvent.click(screen.getByRole('button', { name: 'Sign in' }))
|
|
62
62
|
|
|
63
63
|
// Comes back to where the visitor was after signing in.
|
|
64
64
|
expect(openLoginModal).toHaveBeenCalledWith(
|
|
@@ -75,7 +75,7 @@ describe('Header login button', () => {
|
|
|
75
75
|
expect(
|
|
76
76
|
screen.getByRole('button', { name: 'DEV Login' }),
|
|
77
77
|
).toBeInTheDocument()
|
|
78
|
-
expect(screen.getByRole('button', { name: '
|
|
78
|
+
expect(screen.getByRole('button', { name: 'Sign in' })).toBeInTheDocument()
|
|
79
79
|
})
|
|
80
80
|
|
|
81
81
|
it('leaves no empty flex child in the header row', () => {
|
|
@@ -95,6 +95,6 @@ describe('Header login button', () => {
|
|
|
95
95
|
render(<Header />)
|
|
96
96
|
|
|
97
97
|
expect(screen.getByTestId('user-avatar-button')).toBeInTheDocument()
|
|
98
|
-
expect(screen.queryByRole('button', { name: '
|
|
98
|
+
expect(screen.queryByRole('button', { name: 'Sign in' })).toBeNull()
|
|
99
99
|
})
|
|
100
100
|
})
|
package/src/api/infra/trpc.ts
CHANGED
|
@@ -3,4 +3,6 @@ import type { TRPCRouter } from '@igstack/app-catalog-backend-core'
|
|
|
3
3
|
|
|
4
4
|
const { TRPCProvider, useTRPC, useTRPCClient } = createTRPCContext<TRPCRouter>()
|
|
5
5
|
|
|
6
|
+
// Re-export with explicit types to avoid portable type errors
|
|
6
7
|
export { TRPCProvider, useTRPC, useTRPCClient }
|
|
8
|
+
export type { TRPCRouter }
|
package/src/index.css
CHANGED
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
--muted-foreground: oklch(0.52 0.025 60);
|
|
34
34
|
--accent: oklch(0.93 0.05 70); /* soft amber accent */
|
|
35
35
|
--accent-foreground: oklch(0.36 0.04 55);
|
|
36
|
+
--highlight: oklch(0.88 0.11 80); /* search-match marker */
|
|
36
37
|
--destructive: oklch(0.6368 0.2078 25.3313);
|
|
37
38
|
--destructive-foreground: oklch(1 0 0);
|
|
38
39
|
--border: oklch(0.9 0.018 80); /* warm hairline */
|
|
@@ -714,6 +715,11 @@
|
|
|
714
715
|
font-style: italic;
|
|
715
716
|
color: var(--muted-foreground);
|
|
716
717
|
}
|
|
718
|
+
/* A line the system wrote when a tool changed: context, not someone's note. */
|
|
719
|
+
.comment__text.is-system {
|
|
720
|
+
font-size: 0.84375rem;
|
|
721
|
+
color: var(--muted-foreground);
|
|
722
|
+
}
|
|
717
723
|
.comment__reply {
|
|
718
724
|
margin-top: 0.25rem;
|
|
719
725
|
font-size: 0.84375rem;
|