@flamingo-stack/openframe-frontend-core 0.0.744 → 0.0.746
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/build/export-map.json +1 -1
- package/dist/{chunk-LJ46XYYP.cjs → chunk-2ZVNXD74.cjs} +24 -24
- package/dist/{chunk-FTYQS6VI.cjs → chunk-3AUTORMB.cjs} +13 -13
- package/dist/{chunk-2JRCJV3M.cjs → chunk-3KVB5FQZ.cjs} +5 -5
- package/dist/{chunk-2UBR53AN.cjs → chunk-3OAACQQG.cjs} +4 -4
- package/dist/{chunk-QSO56JZ2.cjs → chunk-5X3F2KL7.cjs} +90 -90
- package/dist/{chunk-AT6ZI4CO.cjs → chunk-7AKFKPBV.cjs} +12 -12
- package/dist/{chunk-4N7KGOBS.cjs → chunk-B24U6KNJ.cjs} +3 -3
- package/dist/{chunk-H62FNZGG.cjs → chunk-DJ4YDVBF.cjs} +18 -18
- package/dist/{chunk-QZYF2YQ3.cjs → chunk-FAN73OTP.cjs} +6 -6
- package/dist/{chunk-HJ4KGA2M.cjs → chunk-GPSHFEF2.cjs} +1084 -890
- package/dist/{chunk-OC2LBQQJ.cjs → chunk-GSFANY2L.cjs} +80 -80
- package/dist/{chunk-URVIPSAJ.cjs → chunk-HNLI4OU5.cjs} +14 -14
- package/dist/{chunk-PYWHDPVC.cjs → chunk-IRKUFXVV.cjs} +38 -38
- package/dist/{chunk-ABLUMGCI.cjs → chunk-JHQNUWFM.cjs} +83 -33
- package/dist/{chunk-4A6OF4HI.cjs → chunk-KVPSV4ZI.cjs} +44 -44
- package/dist/{chunk-UY6A6TEY.cjs → chunk-L2IQESTQ.cjs} +2 -2
- package/dist/{chunk-YIOWV7LS.cjs → chunk-NZMQIAQC.cjs} +2 -2
- package/dist/{chunk-YJRMCFX3.cjs → chunk-O4J4NIMB.cjs} +7 -7
- package/dist/{chunk-GAGNKWOC.cjs → chunk-OWABNVDV.cjs} +2 -2
- package/dist/{chunk-HTQJYN47.cjs → chunk-PLBJ3XVC.cjs} +32 -32
- package/dist/{chunk-OWGLRE74.cjs → chunk-PSIKUDUV.cjs} +8 -8
- package/dist/{chunk-NURAL5HD.cjs → chunk-SDDZHPVK.cjs} +24 -24
- package/dist/{chunk-HHL23RFC.cjs → chunk-SLODGX6D.cjs} +35 -35
- package/dist/{chunk-7YDF3QBN.cjs → chunk-TILK7SC4.cjs} +320 -207
- package/dist/{chunk-U2O5YQRP.cjs → chunk-U6XWGK53.cjs} +33 -33
- package/dist/{chunk-JGZEHBBD.cjs → chunk-VZGCSVH7.cjs} +10 -10
- package/dist/{chunk-35IQLGV3.cjs → chunk-X4Y74M5K.cjs} +74 -74
- package/dist/{chunk-HMSUYWSB.cjs → chunk-XQJOYPPN.cjs} +4 -4
- package/dist/{chunk-65LJNDR2.cjs → chunk-YKF66VQY.cjs} +20 -20
- package/dist/{chunk-5TCIRWHL.cjs → chunk-YRULLK7N.cjs} +5 -5
- package/dist/{cloud-tenants-JPXAXSPE.cjs → cloud-tenants-OKUFSNPW.cjs} +13 -13
- package/dist/components/case-studies/index.cjs +25 -25
- package/dist/components/chat/index.cjs +9 -9
- package/dist/components/contact/index.cjs +14 -14
- package/dist/components/docs/index.cjs +17 -17
- package/dist/components/embeds/index.cjs +14 -14
- package/dist/components/embeds/reddit-embed-client.d.ts +3 -1
- package/dist/components/embeds/reddit-embed-client.d.ts.map +1 -1
- package/dist/components/embeds/reddit-embed-client.js +5 -3
- package/dist/components/embeds/twitter-embed-client.d.ts +3 -1
- package/dist/components/embeds/twitter-embed-client.d.ts.map +1 -1
- package/dist/components/embeds/twitter-embed-client.js +5 -3
- package/dist/components/faq/index.cjs +15 -15
- package/dist/components/features/index.cjs +13 -13
- package/dist/components/help-center-pages/index.cjs +116 -116
- package/dist/components/index.cjs +123 -125
- package/dist/components/meeting-scheduler/index.cjs +63 -63
- package/dist/components/navigation/index.cjs +16 -16
- package/dist/components/onboarding-guides/index.cjs +16 -16
- package/dist/components/product-demo/index.cjs +9 -9
- package/dist/components/related-content/index.cjs +7 -7
- package/dist/components/tickets/index.cjs +19 -19
- package/dist/components/ui/filter-checkbox-item.d.ts +8 -2
- package/dist/components/ui/filter-checkbox-item.d.ts.map +1 -1
- package/dist/components/ui/filter-checkbox-item.js +14 -4
- package/dist/components/ui/index.cjs +17 -13
- package/dist/components/ui/index.d.ts +1 -0
- package/dist/components/ui/index.d.ts.map +1 -1
- package/dist/components/ui/index.js +1 -0
- package/dist/components/ui/markdown/base-components.d.ts.map +1 -1
- package/dist/components/ui/markdown/base-components.js +3 -2
- package/dist/components/ui/markdown/rich/embed-overrides.d.ts.map +1 -1
- package/dist/components/ui/markdown/rich/embed-overrides.js +11 -8
- package/dist/components/ui/markdown-editor.d.ts.map +1 -1
- package/dist/components/ui/markdown-editor.js +4 -0
- package/dist/components/ui/markdown-link-command.d.ts +37 -0
- package/dist/components/ui/markdown-link-command.d.ts.map +1 -0
- package/dist/components/ui/markdown-link-command.js +180 -0
- package/dist/components/unified-filter-logic.js +1 -1
- package/dist/components/vendor-tag.d.ts +12 -0
- package/dist/components/vendor-tag.d.ts.map +1 -1
- package/dist/components/vendor-tag.js +50 -47
- package/dist/{devices-ONC4JOVH.cjs → devices-URCDMYFU.cjs} +14 -14
- package/dist/{embeddable-chat-7ZEGCDVF.cjs → embeddable-chat-B35GB5B6.cjs} +80 -80
- package/dist/index.cjs +36 -18
- package/dist/{knowledge-G7XU5YST.cjs → knowledge-5MW2PREQ.cjs} +14 -14
- package/dist/{logs-5B7NY4G6.cjs → logs-LJJK5CK4.cjs} +21 -21
- package/dist/{policies-OYR3SLJN.cjs → policies-6TCEWQYG.cjs} +17 -17
- package/dist/{remote-session-N4PJB5FW.cjs → remote-session-IYT4LWJC.cjs} +7 -7
- package/dist/{scripts-6CWHTY6U.cjs → scripts-ABB2P6PT.cjs} +20 -20
- package/dist/{software-update-AJPIY4SQ.cjs → software-update-4427ZRMO.cjs} +17 -17
- package/dist/{tickets-board-O753S4ZB.cjs → tickets-board-4MT6ZB4F.cjs} +8 -8
- package/dist/utils/format.d.ts.map +1 -1
- package/dist/utils/format.js +2 -3
- package/dist/utils/index.cjs +193 -28
- package/dist/utils/index.d.ts +2 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +9 -6
- package/dist/utils/markdown-link.d.ts +44 -0
- package/dist/utils/markdown-link.d.ts.map +1 -0
- package/dist/utils/markdown-link.js +83 -0
- package/dist/utils/markdown-to-plain.d.ts +3 -16
- package/dist/utils/markdown-to-plain.d.ts.map +1 -1
- package/dist/utils/markdown-to-plain.js +33 -3
- package/dist/utils/vendor-classification.d.ts +43 -17
- package/dist/utils/vendor-classification.d.ts.map +1 -1
- package/dist/utils/vendor-classification.js +73 -22
- package/package.json +3 -1
- package/src/components/embeds/reddit-embed-client.tsx +7 -3
- package/src/components/embeds/twitter-embed-client.tsx +7 -3
- package/src/components/ui/filter-checkbox-item.tsx +21 -5
- package/src/components/ui/index.ts +1 -0
- package/src/components/ui/markdown/base-components.tsx +5 -2
- package/src/components/ui/markdown/rich/embed-overrides.tsx +12 -9
- package/src/components/ui/markdown-editor.tsx +6 -0
- package/src/components/ui/markdown-link-command.tsx +252 -0
- package/src/components/unified-filter-logic.tsx +1 -1
- package/src/components/vendor-tag.tsx +73 -69
- package/src/utils/format.ts +2 -3
- package/src/utils/index.ts +8 -5
- package/src/utils/markdown-link.ts +148 -0
- package/src/utils/markdown-to-plain.ts +64 -22
- package/src/utils/vendor-classification.ts +113 -34
- package/dist/utils/format-text-stub.d.ts +0 -5
- package/dist/utils/format-text-stub.d.ts.map +0 -1
- package/dist/utils/format-text-stub.js +0 -20
- package/src/utils/format-text-stub.ts +0 -17
|
@@ -3,15 +3,24 @@
|
|
|
3
3
|
* (article-body echo in JSON-LD) and chat entity-card preview (clamped previews
|
|
4
4
|
* inside chat cards).
|
|
5
5
|
*
|
|
6
|
-
* The
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
6
|
+
* The text is what a reader of the rendered page reads: the markdown is parsed with the SAME
|
|
7
|
+
* pipeline the renderer uses (remark with GFM and line breaks, then rehype with raw HTML, as in
|
|
8
|
+
* `components/ui/markdown/engine.tsx`), and the result is the `innerText` of that HTML
|
|
9
|
+
* (`hast-util-to-text`). So link, emphasis and heading syntax, raw HTML tags (`<a rel>`, `<div>`),
|
|
10
|
+
* escapes (`\<`) and entities (`&`) all come out as their text; script and style content and
|
|
11
|
+
* comments do not. Code blocks and images are left out: their content is not prose.
|
|
10
12
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* pathological input.
|
|
13
|
+
* The two consumers differ only in whitespace — `mode: 'article'` keeps paragraph breaks;
|
|
14
|
+
* `mode: 'preview'` collapses everything to a single line.
|
|
14
15
|
*/
|
|
16
|
+
import type { Element, Root } from 'hast';
|
|
17
|
+
import { toText } from 'hast-util-to-text';
|
|
18
|
+
import rehypeRaw from 'rehype-raw';
|
|
19
|
+
import { remark } from 'remark';
|
|
20
|
+
import remarkBreaks from 'remark-breaks';
|
|
21
|
+
import remarkGfm from 'remark-gfm';
|
|
22
|
+
import remarkRehype from 'remark-rehype';
|
|
23
|
+
import { SKIP, visit } from 'unist-util-visit';
|
|
15
24
|
|
|
16
25
|
export interface MarkdownToPlainOptions {
|
|
17
26
|
/**
|
|
@@ -27,8 +36,9 @@ export interface MarkdownToPlainOptions {
|
|
|
27
36
|
maxChars?: number;
|
|
28
37
|
}
|
|
29
38
|
|
|
30
|
-
/** Strip inline markdown markers (bold, italic, inline-code, links).
|
|
31
|
-
* by `extractSections`'s `stripFormattingMarkers` and
|
|
39
|
+
/** Strip inline markdown markers (bold, italic, inline-code, links) from ONE line of text.
|
|
40
|
+
* Shared by `extractSections`'s `stripFormattingMarkers` and the heading ids, whose output is
|
|
41
|
+
* an anchor: it stays a fixed, regex-only rule so no heading id ever moves. */
|
|
32
42
|
export function stripInlineMarkdown(s: string): string {
|
|
33
43
|
return s
|
|
34
44
|
.replace(/\[([^\]]+)\]\([^)]+\)/g, '$1') // [text](url) → text
|
|
@@ -37,26 +47,58 @@ export function stripInlineMarkdown(s: string): string {
|
|
|
37
47
|
.replace(/`([^`]+)`/g, '$1'); // `inline code` → inline code
|
|
38
48
|
}
|
|
39
49
|
|
|
50
|
+
// The renderer's own pipeline, up to the HTML tree. Built once; `runSync` has no async plugins.
|
|
51
|
+
const toHtmlTree = remark()
|
|
52
|
+
.use(remarkGfm)
|
|
53
|
+
.use(remarkBreaks)
|
|
54
|
+
.use(remarkRehype, { allowDangerousHtml: true })
|
|
55
|
+
.use(rehypeRaw);
|
|
56
|
+
|
|
57
|
+
/** Elements whose content is not prose: code blocks and images. */
|
|
58
|
+
const NOT_PROSE = new Set(['pre', 'img']);
|
|
59
|
+
|
|
60
|
+
const TABLE_SECTIONS = new Set(['thead', 'tbody', 'tfoot']);
|
|
61
|
+
|
|
62
|
+
function proseTree(markdown: string): Root {
|
|
63
|
+
const tree: Root = toHtmlTree.runSync(toHtmlTree.parse(markdown));
|
|
64
|
+
visit(tree, 'element', (node: Element, index, parent) => {
|
|
65
|
+
if (NOT_PROSE.has(node.tagName) && parent && index !== undefined) {
|
|
66
|
+
parent.children.splice(index, 1);
|
|
67
|
+
return [SKIP, index];
|
|
68
|
+
}
|
|
69
|
+
// `innerText` breaks between rows of the same `thead` / `tbody` only, so the last header row
|
|
70
|
+
// ran into the first body row ("What it buysEnthusiast"). A section followed by another ends
|
|
71
|
+
// its last row with a line break.
|
|
72
|
+
if (TABLE_SECTIONS.has(node.tagName) && parent && index !== undefined) {
|
|
73
|
+
const followedBySection = parent.children
|
|
74
|
+
.slice(index + 1)
|
|
75
|
+
.some(sibling => sibling.type === 'element' && TABLE_SECTIONS.has(sibling.tagName));
|
|
76
|
+
const rows = node.children.filter(
|
|
77
|
+
(child): child is Element => child.type === 'element' && child.tagName === 'tr',
|
|
78
|
+
);
|
|
79
|
+
const lastRow = rows[rows.length - 1];
|
|
80
|
+
if (followedBySection && lastRow) {
|
|
81
|
+
lastRow.children.push({ type: 'element', tagName: 'br', properties: {}, children: [] });
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return undefined;
|
|
85
|
+
});
|
|
86
|
+
return tree;
|
|
87
|
+
}
|
|
88
|
+
|
|
40
89
|
export function markdownToPlainText(markdown: string, options: MarkdownToPlainOptions = {}): string {
|
|
41
90
|
const { mode = 'article', maxChars } = options;
|
|
42
91
|
|
|
43
|
-
let out = markdown
|
|
44
|
-
// Fenced code blocks — must run BEFORE inline strippers (otherwise the
|
|
45
|
-
// backtick-grave strip below grazes them).
|
|
46
|
-
.replace(/```[\s\S]*?```/g, '')
|
|
47
|
-
// Images — `` → empty (we drop them entirely in plain text).
|
|
48
|
-
.replace(/!\[[^\]]*\]\([^)]+\)/g, '');
|
|
49
|
-
|
|
50
|
-
out = stripInlineMarkdown(out)
|
|
51
|
-
// Heading markers (any depth).
|
|
52
|
-
.replace(/^#+\s*/gm, '')
|
|
53
|
-
// List bullets at start-of-line.
|
|
54
|
-
.replace(/^\s*[-*+]\s+/gm, '');
|
|
92
|
+
let out = toText(proseTree(markdown));
|
|
55
93
|
|
|
56
94
|
if (mode === 'preview') {
|
|
57
95
|
out = out.replace(/\s+/g, ' ').trim();
|
|
58
96
|
} else {
|
|
59
|
-
out = out
|
|
97
|
+
out = out
|
|
98
|
+
// No spaces around a line break (a soft break keeps the space that followed it).
|
|
99
|
+
.replace(/[^\S\n]*\n[^\S\n]*/g, '\n')
|
|
100
|
+
.replace(/\n{3,}/g, '\n\n')
|
|
101
|
+
.trim();
|
|
60
102
|
}
|
|
61
103
|
|
|
62
104
|
if (maxChars != null && out.length > maxChars) {
|
|
@@ -1,59 +1,138 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Vendor classifications:
|
|
2
|
+
* Vendor classifications: whatever `vendor_classification.classification` holds on the
|
|
3
|
+
* server. The database owns the vocabulary (its CHECK constraint is the list), the catalog
|
|
4
|
+
* builds its filters from the rows that exist, and nothing here limits which values are valid.
|
|
3
5
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
6
|
+
* This module only ENRICHES the values we want to present specially: a curated label, a
|
|
7
|
+
* tooltip description and a group. A value with no entry still works everywhere, labelled
|
|
8
|
+
* by title case. To present a new value better, add an entry here; to make it exist, add it
|
|
9
|
+
* to the database.
|
|
7
10
|
*
|
|
8
|
-
*
|
|
9
|
-
* - `
|
|
10
|
-
* - `
|
|
11
|
+
* Groups:
|
|
12
|
+
* - `license`: how the software is licensed.
|
|
13
|
+
* - `lifecycle`: where the product is in its life (a tag and a filter; a card's one tag stays the license).
|
|
14
|
+
* - `openframe`: drawn with the OpenFrame mark and ONE word (`word`).
|
|
11
15
|
*/
|
|
12
|
-
export
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
] as const;
|
|
19
|
-
|
|
20
|
-
export type VendorClassificationValue = (typeof VENDOR_CLASSIFICATIONS)[number];
|
|
21
|
-
|
|
22
|
-
export type OpenFrameClassification = Extract<VendorClassificationValue, `openframe_${string}`>;
|
|
23
|
-
|
|
24
|
-
export interface OpenFrameClassificationCopy {
|
|
25
|
-
/** The word drawn beside the OpenFrame mark. */
|
|
26
|
-
word: string;
|
|
27
|
-
/** The full name, for plain-text surfaces (a select option, an aria label). */
|
|
16
|
+
export type VendorClassificationValue = string;
|
|
17
|
+
|
|
18
|
+
export type VendorClassificationGroup = 'license' | 'lifecycle' | 'openframe';
|
|
19
|
+
|
|
20
|
+
export interface VendorClassificationCopy {
|
|
21
|
+
/** The label on a tag, a filter and a plain-text surface. */
|
|
28
22
|
label: string;
|
|
29
23
|
/** What the classification means, for a tooltip. */
|
|
30
24
|
description: string;
|
|
25
|
+
group: VendorClassificationGroup;
|
|
26
|
+
/** OpenFrame group only: the one word drawn beside the OpenFrame mark. */
|
|
27
|
+
word?: string;
|
|
28
|
+
/** The icon drawn beside the label, by name (resolved by the shared icon resolver), and its tone. */
|
|
29
|
+
icon?: VendorClassificationIconConfig;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* A classification's icon, as data: `name` is any name the shared resolver knows (an alias such
|
|
34
|
+
* as `openframe-logo`, an icon of the design set by its kebab name, or a lucide name). `tone`:
|
|
35
|
+
* `accent` (the brand colour), `neutral` (secondary text on a tile) or `warning`.
|
|
36
|
+
*/
|
|
37
|
+
export interface VendorClassificationIconConfig {
|
|
38
|
+
name: string;
|
|
39
|
+
tone: 'accent' | 'neutral' | 'warning';
|
|
31
40
|
}
|
|
32
41
|
|
|
33
|
-
|
|
42
|
+
/** In display order: a filter list shows OpenFrame first, then license, then lifecycle. */
|
|
43
|
+
export const VENDOR_CLASSIFICATION_COPY: Readonly<Record<string, VendorClassificationCopy>> = {
|
|
34
44
|
openframe_selected: {
|
|
35
|
-
word: 'Selected',
|
|
36
45
|
label: 'OpenFrame Selected',
|
|
46
|
+
word: 'Selected',
|
|
37
47
|
description:
|
|
38
48
|
'OpenFrame is a unified platform that integrates multiple open-source IT and security tools into a single dashboard for MSPs. This filter shows vendors selected by our team for their excellence, community support, and MSP-specific value.',
|
|
49
|
+
group: 'openframe',
|
|
50
|
+
icon: { name: 'openframe-logo', tone: 'accent' },
|
|
51
|
+
},
|
|
52
|
+
openframe_connect: {
|
|
53
|
+
label: 'OpenFrame Connect',
|
|
54
|
+
word: 'Connect',
|
|
55
|
+
description:
|
|
56
|
+
'Services OpenFrame connects to and manages for every client, such as Microsoft 365 and Google Workspace, beside devices and tickets.',
|
|
57
|
+
group: 'openframe',
|
|
58
|
+
icon: { name: 'openframe-logo', tone: 'accent' },
|
|
39
59
|
},
|
|
40
60
|
openframe_shipped: {
|
|
41
|
-
word: 'Shipped',
|
|
42
61
|
label: 'OpenFrame Shipped',
|
|
62
|
+
word: 'Shipped',
|
|
43
63
|
description: 'Tools and OpenFrame products that are in the released OpenFrame product today, not on the roadmap.',
|
|
64
|
+
group: 'openframe',
|
|
65
|
+
icon: { name: 'openframe-logo', tone: 'accent' },
|
|
44
66
|
},
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
67
|
+
open_source: {
|
|
68
|
+
label: 'Open Source',
|
|
69
|
+
description: 'Released under an OSI-approved open-source license.',
|
|
70
|
+
group: 'license',
|
|
71
|
+
icon: { name: 'code', tone: 'accent' },
|
|
72
|
+
},
|
|
73
|
+
source_available: {
|
|
74
|
+
label: 'Source-available',
|
|
48
75
|
description:
|
|
49
|
-
'
|
|
76
|
+
'The source code is public, but the license restricts how it may be used (for example SSPL, BSL, the Elastic License, or limits on company size or on offering it as a service).',
|
|
77
|
+
group: 'license',
|
|
78
|
+
icon: { name: 'file-code', tone: 'neutral' },
|
|
79
|
+
},
|
|
80
|
+
commercial: {
|
|
81
|
+
label: 'Commercial',
|
|
82
|
+
description: 'Proprietary software sold by the vendor.',
|
|
83
|
+
group: 'license',
|
|
84
|
+
icon: { name: 'dollar', tone: 'neutral' },
|
|
85
|
+
},
|
|
86
|
+
end_of_life: {
|
|
87
|
+
label: 'End of life',
|
|
88
|
+
description: 'The vendor has discontinued or retired the product. No new releases.',
|
|
89
|
+
group: 'lifecycle',
|
|
90
|
+
icon: { name: 'alert-triangle', tone: 'warning' },
|
|
91
|
+
},
|
|
92
|
+
end_of_support: {
|
|
93
|
+
label: 'End of support',
|
|
94
|
+
description: 'The vendor no longer provides support or security fixes, though the product can still be obtained.',
|
|
95
|
+
group: 'lifecycle',
|
|
96
|
+
icon: { name: 'clock', tone: 'warning' },
|
|
97
|
+
},
|
|
98
|
+
unmaintained: {
|
|
99
|
+
label: 'Unmaintained',
|
|
100
|
+
description: 'No release for years and no official end-of-life notice.',
|
|
101
|
+
group: 'lifecycle',
|
|
102
|
+
icon: { name: 'pause-circle', tone: 'warning' },
|
|
50
103
|
},
|
|
51
104
|
};
|
|
52
105
|
|
|
53
|
-
|
|
54
|
-
|
|
106
|
+
/** The enrichment of a classification, or undefined for a value we do not present specially. */
|
|
107
|
+
export function vendorClassificationCopy(value: string | null | undefined): VendorClassificationCopy | undefined {
|
|
108
|
+
if (!value || !Object.prototype.hasOwnProperty.call(VENDOR_CLASSIFICATION_COPY, value)) return undefined;
|
|
109
|
+
return VENDOR_CLASSIFICATION_COPY[value];
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** The group of a classification, or undefined for a value with no enrichment. */
|
|
113
|
+
export function vendorClassificationGroup(value: string | null | undefined): VendorClassificationGroup | undefined {
|
|
114
|
+
return vendorClassificationCopy(value)?.group;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** A classification drawn with the OpenFrame mark (it has a `word`). */
|
|
118
|
+
export function isOpenFrameClassification(value: string | null | undefined): boolean {
|
|
119
|
+
return vendorClassificationGroup(value) === 'openframe';
|
|
55
120
|
}
|
|
56
121
|
|
|
57
|
-
|
|
58
|
-
|
|
122
|
+
const DISPLAY_ORDER = Object.keys(VENDOR_CLASSIFICATION_COPY);
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Sort order for a list of classifications (a filter list): the enriched values in their
|
|
126
|
+
* display order (OpenFrame Selected, Connect, Shipped, then license, then lifecycle), then
|
|
127
|
+
* every other value the server holds, alphabetically.
|
|
128
|
+
*/
|
|
129
|
+
export function compareVendorClassifications(a: string, b: string): number {
|
|
130
|
+
const ia = DISPLAY_ORDER.indexOf(a);
|
|
131
|
+
const ib = DISPLAY_ORDER.indexOf(b);
|
|
132
|
+
if (ia !== -1 || ib !== -1) {
|
|
133
|
+
if (ia === -1) return 1;
|
|
134
|
+
if (ib === -1) return -1;
|
|
135
|
+
return ia - ib;
|
|
136
|
+
}
|
|
137
|
+
return a.localeCompare(b);
|
|
59
138
|
}
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
export declare function formatText(text: string): string;
|
|
2
|
-
export declare function truncateText(text: string, maxLength: number): string;
|
|
3
|
-
export declare function formatClassification(classification: string): string;
|
|
4
|
-
export declare function formatPricingModel(pricing: string): string;
|
|
5
|
-
//# sourceMappingURL=format-text-stub.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"format-text-stub.d.ts","sourceRoot":"","sources":["../../src/utils/format-text-stub.ts"],"names":[],"mappings":"AACA,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAGpE;AAED,wBAAgB,oBAAoB,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAEnE;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE1D"}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
function formatText(text) {
|
|
3
|
-
return text;
|
|
4
|
-
}
|
|
5
|
-
function truncateText(text, maxLength) {
|
|
6
|
-
if (text.length <= maxLength) return text;
|
|
7
|
-
return text.slice(0, maxLength) + "...";
|
|
8
|
-
}
|
|
9
|
-
function formatClassification(classification) {
|
|
10
|
-
return classification.replace(/_/g, " ").replace(/\b\w/g, (l) => l.toUpperCase());
|
|
11
|
-
}
|
|
12
|
-
function formatPricingModel(pricing) {
|
|
13
|
-
return pricing.replace(/_/g, " ").replace(/\b\w/g, (l) => l.toUpperCase());
|
|
14
|
-
}
|
|
15
|
-
export {
|
|
16
|
-
formatClassification,
|
|
17
|
-
formatPricingModel,
|
|
18
|
-
formatText,
|
|
19
|
-
truncateText
|
|
20
|
-
};
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
// Stub for format-text utilities
|
|
2
|
-
export function formatText(text: string): string {
|
|
3
|
-
return text;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
export function truncateText(text: string, maxLength: number): string {
|
|
7
|
-
if (text.length <= maxLength) return text;
|
|
8
|
-
return text.slice(0, maxLength) + '...';
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export function formatClassification(classification: string): string {
|
|
12
|
-
return classification.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase());
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export function formatPricingModel(pricing: string): string {
|
|
16
|
-
return pricing.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase());
|
|
17
|
-
}
|