mgv-backoffice 1.45.0 → 1.47.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/README.md +56 -0
- package/dist/components/BaseGroupedChecklist.vue.d.ts +26 -0
- package/dist/components/BaseIdChip.vue.d.ts +24 -0
- package/dist/composables/useDirtyState.d.ts +24 -0
- package/dist/index.d.ts +5 -1
- package/dist/types/checklist.d.ts +6 -0
- package/dist/ui-lib.css +1 -1
- package/dist/ui-lib.js +341 -189
- package/dist/ui-lib.umd.cjs +1 -1
- package/dist/utils/format.d.ts +15 -0
- package/package.json +1 -1
- package/src/components/BaseGroupedChecklist.test.ts +73 -0
- package/src/components/BaseGroupedChecklist.vue +122 -0
- package/src/components/BaseIdChip.test.ts +26 -0
- package/src/components/BaseIdChip.vue +51 -0
- package/src/composables/useDirtyState.test.ts +38 -0
- package/src/composables/useDirtyState.ts +44 -0
- package/src/index.ts +6 -0
- package/src/types/checklist.ts +6 -0
- package/src/utils/format.test.ts +322 -290
- package/src/utils/format.ts +42 -0
package/README.md
CHANGED
|
@@ -774,6 +774,8 @@ epoch/numeric formatters (`fmtDateTime`, `fmtDateShort`, `fmtDateTimeMs`,
|
|
|
774
774
|
| `fmtPct` | `(n: number, digits = 2) => string` | Percentage with explicit sign, e.g. `"+2.50%"`. |
|
|
775
775
|
| `fmtUsd` | `(v: number) => string` | Signed USD amount with leading sign, e.g. `"+$5.00"`. |
|
|
776
776
|
| `fmtMoney` | `(n: number \| string \| null \| undefined, digits = 2, currency = '$') => string` | Money with the minus BEFORE the currency (`"-$2.26"`, never `"$-2.26"`), digit grouping, no `+` on gains; a value rounding to zero reads unsigned; em-dash for missing input (since 1.45.0). |
|
|
777
|
+
| `currencySymbol` | `(code: string \| null \| undefined) => string \| null` | Display symbol for a currency code: `€` EUR, `£` GBP, `$` for USD, USDT, USDC and a missing code; `null` for anything else (BTC, ETH…) so the caller suffixes the code (since 1.47.0). |
|
|
778
|
+
| `fmtCurrencyAmount` | `(n, code, digits = 2) => string` | An amount in its own currency: `"€20.00"`, `"-$1.50"`, `"$25.00 USDT"` (stablecoin ticker kept), `"0.5 BTC"` (plain quantity, up to 8 decimals); em-dash for missing input (since 1.47.0). |
|
|
777
779
|
| `formatJson` | `(content: string) => string` | Pretty-prints parseable JSON with 2-space indentation; returns anything else verbatim. |
|
|
778
780
|
| `stringifyValue` | `(value: unknown) => string` | Display string for an unknown value: strings pass through, null/undefined → `''`, everything else JSON-serialized (`String()` fallback). |
|
|
779
781
|
|
|
@@ -1782,6 +1784,57 @@ Extracted from TradeAutomation's variant-stats modal.
|
|
|
1782
1784
|
|
|
1783
1785
|
---
|
|
1784
1786
|
|
|
1787
|
+
### BaseGroupedChecklist
|
|
1788
|
+
|
|
1789
|
+
Grouped multi-select checklist (since 1.46.0): a master "Select all (N)"
|
|
1790
|
+
checkbox, a per-group select-all, and one checkbox per item. Built for
|
|
1791
|
+
"pick which records this action applies to" confirmation modals. Empty groups
|
|
1792
|
+
are not rendered; items are plain strings, unique across groups.
|
|
1793
|
+
|
|
1794
|
+
| Prop | Type | Default | Description |
|
|
1795
|
+
| ---------------- | -------------------------- | ------------------ | ----------- |
|
|
1796
|
+
| `groups` | `ChecklistGroup[]` | **required** | `{ key, label, items: string[] }` per group, in display order. |
|
|
1797
|
+
| `modelValue` | `string[]` | **required** | Selected items (`v-model`); emitted in group order. |
|
|
1798
|
+
| `allLabel` | `string` | `'Select all'` | Master checkbox text; group checkboxes are labelled `"<allLabel> <group label>"`. |
|
|
1799
|
+
| `allAriaLabel` | `string` | `'Select all items'` | Accessible name of the master checkbox. |
|
|
1800
|
+
| `itemAriaLabel` | `(item: string) => string` | the item itself | Accessible name per item checkbox. |
|
|
1801
|
+
| `mono` | `boolean` | `false` | Monospace item labels (tickers, ids). |
|
|
1802
|
+
| `maxHeightClass` | `string` | `'max-h-72'` | Scroll cap of the group list. |
|
|
1803
|
+
|
|
1804
|
+
```vue
|
|
1805
|
+
<BaseGroupedChecklist
|
|
1806
|
+
v-model="selected"
|
|
1807
|
+
:groups="[{ key: 'STOCK', label: 'Stocks', items: ['AMD', 'NVDA'] }]"
|
|
1808
|
+
all-aria-label="Select all symbols"
|
|
1809
|
+
:item-aria-label="(s) => `Apply to ${s}`"
|
|
1810
|
+
mono
|
|
1811
|
+
/>
|
|
1812
|
+
```
|
|
1813
|
+
|
|
1814
|
+
---
|
|
1815
|
+
|
|
1816
|
+
### BaseIdChip
|
|
1817
|
+
|
|
1818
|
+
Compact id cell (since 1.47.0): a small uppercase label, the id truncated in a
|
|
1819
|
+
`<code>` pill with the full value in its tooltip, a copy button, and an optional
|
|
1820
|
+
magnifier button. Built for dense rows that carry several ids side by side.
|
|
1821
|
+
|
|
1822
|
+
| Prop | Type | Default | Description |
|
|
1823
|
+
| --------------- | -------- | -------------------- | ----------- |
|
|
1824
|
+
| `value` | `string` | **required** | The id — shown truncated, copied in full. |
|
|
1825
|
+
| `label` | `string` | `''` | Uppercase prefix (`"id"`, `"ord"`). |
|
|
1826
|
+
| `copyLabel` | `string` | `"<label> <value>"` | Noun for the copy button's tooltip / aria-label. |
|
|
1827
|
+
| `actionLabel` | `string` | — | Tooltip / aria-label of the magnifier button; the button renders only when set. |
|
|
1828
|
+
| `maxWidthClass` | `string` | `'max-w-[90px]'` | Width cap of the truncated id. |
|
|
1829
|
+
|
|
1830
|
+
Emits `action(value)` when the magnifier is clicked.
|
|
1831
|
+
|
|
1832
|
+
```vue
|
|
1833
|
+
<BaseIdChip label="ord" :value="row.buyOrderId" action-label="Search this order id" @action="search" />
|
|
1834
|
+
```
|
|
1835
|
+
|
|
1836
|
+
---
|
|
1837
|
+
|
|
1785
1838
|
### BaseSearchSelect
|
|
1786
1839
|
|
|
1787
1840
|
Searchable select (combobox): type to filter, pick with the mouse or
|
|
@@ -1952,6 +2005,8 @@ import {
|
|
|
1952
2005
|
usePolling,
|
|
1953
2006
|
useLatestRequest,
|
|
1954
2007
|
isAbortError,
|
|
2008
|
+
useDirtyState,
|
|
2009
|
+
stableStringify,
|
|
1955
2010
|
} from 'mgv-backoffice'
|
|
1956
2011
|
import type {
|
|
1957
2012
|
UseThemeOptions,
|
|
@@ -1976,6 +2031,7 @@ import type {
|
|
|
1976
2031
|
| `useFieldClasses()` | Shared form-field class strings for the gray/emerald form skin: `{ label, input, requiredInput(value) }`. `requiredInput` returns a red border+ring skin while the value is empty and the standard skin otherwise. |
|
|
1977
2032
|
| `usePolling(fn, intervalMs, { immediate?, pauseWhenHidden? })` | Visibility-gated polling loop bound to the component lifecycle: starts on mount, stops on unmount, pauses while the tab is hidden and refreshes + resumes on return to visible (both default on). Pass `intervalMs: null` for refresh-only mode (run on mount + each return-to-visible, no timer). Returns `{ start, stop, active }`. A loop stopped via `stop()` stays stopped across hide/show cycles (since 1.36.0) — only a visibility-paused loop auto-resumes. Catch errors inside `fn` — the loop never swallows rejections. |
|
|
1978
2033
|
| `useLatestRequest()` | "Latest request wins" guard for views that refetch on filter changes / polls / Refresh (since 1.45.0). `begin()` aborts the previous in-flight request and returns `{ signal, isLatest() }` — pass `signal` to `fetch`, and check `isLatest()` after every `await` before writing state (and before clearing a loading flag in `finally`). `cancel()` aborts + invalidates without starting a new request. Auto-cancels on unmount when called in setup. Pair with `isAbortError(e)` to swallow superseded requests silently. |
|
|
2034
|
+
| `useDirtyState(snapshot)` | Unsaved-changes tracking for edit forms (since 1.46.0): `snapshot()` returns the form state (read reactively); `dirty` is true while it differs from the last baseline, `markClean()` makes the current state the baseline (call after load / save). Structural, key-order-insensitive comparison via `stableStringify` (also exported), so a server echo that reorders keys never reads as an edit. |
|
|
1979
2035
|
|
|
1980
2036
|
---
|
|
1981
2037
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ChecklistGroup } from '../types/checklist';
|
|
2
|
+
interface Props {
|
|
3
|
+
groups: ChecklistGroup[];
|
|
4
|
+
modelValue: string[];
|
|
5
|
+
/** Text of the master checkbox; group checkboxes read "<allLabel> <group>". */
|
|
6
|
+
allLabel?: string;
|
|
7
|
+
allAriaLabel?: string;
|
|
8
|
+
/** Accessible name per item checkbox (defaults to the item itself). */
|
|
9
|
+
itemAriaLabel?: (item: string) => string;
|
|
10
|
+
/** Render item labels in a monospace font (tickers, ids). */
|
|
11
|
+
mono?: boolean;
|
|
12
|
+
maxHeightClass?: string;
|
|
13
|
+
}
|
|
14
|
+
declare const __VLS_export: import('vue').DefineComponent<Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {} & {
|
|
15
|
+
"update:modelValue": (value: string[]) => any;
|
|
16
|
+
}, string, import('vue').PublicProps, Readonly<Props> & Readonly<{
|
|
17
|
+
"onUpdate:modelValue"?: ((value: string[]) => any) | undefined;
|
|
18
|
+
}>, {
|
|
19
|
+
maxHeightClass: string;
|
|
20
|
+
mono: boolean;
|
|
21
|
+
allLabel: string;
|
|
22
|
+
allAriaLabel: string;
|
|
23
|
+
itemAriaLabel: (item: string) => string;
|
|
24
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
25
|
+
declare const _default: typeof __VLS_export;
|
|
26
|
+
export default _default;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
/** The id itself — shown truncated, copied in full. */
|
|
3
|
+
value: string;
|
|
4
|
+
/** Short uppercase prefix ("id", "ord", "sell"). Omit for no prefix. */
|
|
5
|
+
label?: string;
|
|
6
|
+
/** Copy button's tooltip / aria noun; defaults to "<label> <value>". */
|
|
7
|
+
copyLabel?: string;
|
|
8
|
+
/** Tooltip / aria-label of the action button; the button only renders when set. */
|
|
9
|
+
actionLabel?: string;
|
|
10
|
+
/** Width cap of the truncated id. */
|
|
11
|
+
maxWidthClass?: string;
|
|
12
|
+
};
|
|
13
|
+
declare const __VLS_export: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
|
|
14
|
+
action: (value: string) => any;
|
|
15
|
+
}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
16
|
+
onAction?: ((value: string) => any) | undefined;
|
|
17
|
+
}>, {
|
|
18
|
+
label: string;
|
|
19
|
+
maxWidthClass: string;
|
|
20
|
+
copyLabel: string;
|
|
21
|
+
actionLabel: string;
|
|
22
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
23
|
+
declare const _default: typeof __VLS_export;
|
|
24
|
+
export default _default;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ComputedRef } from 'vue';
|
|
2
|
+
/**
|
|
3
|
+
* JSON-serialise a value with object keys sorted at every depth, so two
|
|
4
|
+
* structurally equal values always produce the same string regardless of
|
|
5
|
+
* key insertion order (arrays keep their order).
|
|
6
|
+
*/
|
|
7
|
+
export declare function stableStringify(value: unknown): string;
|
|
8
|
+
/**
|
|
9
|
+
* Unsaved-changes tracking for an edit form. `snapshot` returns the form's
|
|
10
|
+
* current state (read reactively); `dirty` is true whenever it differs from
|
|
11
|
+
* the last clean baseline. Call `markClean()` after loading or saving to make
|
|
12
|
+
* the current state the new baseline. Comparison is structural (key order is
|
|
13
|
+
* ignored), so a server echo that reorders keys never reads as an edit.
|
|
14
|
+
*
|
|
15
|
+
* ```ts
|
|
16
|
+
* const form = reactive({ name: '', params: {} })
|
|
17
|
+
* const { dirty, markClean } = useDirtyState(() => form)
|
|
18
|
+
* // …load → assign form → markClean(); Save enabled while dirty.value
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export declare function useDirtyState(snapshot: () => unknown): {
|
|
22
|
+
dirty: ComputedRef<boolean>;
|
|
23
|
+
markClean: () => void;
|
|
24
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -44,6 +44,8 @@ export { default as BaseFilterChip } from './components/BaseFilterChip.vue';
|
|
|
44
44
|
export { default as BaseCredentialsForm } from './components/BaseCredentialsForm.vue';
|
|
45
45
|
export { default as BasePillPickerModal } from './components/BasePillPickerModal.vue';
|
|
46
46
|
export { default as BaseBarDistribution } from './components/BaseBarDistribution.vue';
|
|
47
|
+
export { default as BaseGroupedChecklist } from './components/BaseGroupedChecklist.vue';
|
|
48
|
+
export { default as BaseIdChip } from './components/BaseIdChip.vue';
|
|
47
49
|
export type { CredentialsView, CredentialsUpdate } from './components/BaseCredentialsForm.vue';
|
|
48
50
|
export { default as BaseDateTimePicker } from './components/BaseDateTimePicker.vue';
|
|
49
51
|
export type { DateTimePickerMode } from './components/BaseDateTimePicker.vue';
|
|
@@ -75,6 +77,7 @@ export type { FieldClasses } from './composables/useFieldClasses';
|
|
|
75
77
|
export { usePolling } from './composables/usePolling';
|
|
76
78
|
export type { UsePollingOptions } from './composables/usePolling';
|
|
77
79
|
export { useLatestRequest, isAbortError } from './composables/useLatestRequest';
|
|
80
|
+
export { useDirtyState, stableStringify } from './composables/useDirtyState';
|
|
78
81
|
export type { LatestRequestToken } from './composables/useLatestRequest';
|
|
79
82
|
export { AlertEnum } from './enums/AlertEnum';
|
|
80
83
|
export { BaseBadgeEnum } from './enums/BaseBadgeEnum';
|
|
@@ -98,12 +101,13 @@ export type { SpecField, SpecFieldType, SpecFieldValue } from './types/specField
|
|
|
98
101
|
export type { StatBreakdownItem } from './types/statBreakdown';
|
|
99
102
|
export type { PillPickerItem } from './types/pillPicker';
|
|
100
103
|
export type { DistributionBar } from './types/distribution';
|
|
104
|
+
export type { ChecklistGroup } from './types/checklist';
|
|
101
105
|
export { getBaseColor, getBaseColorOf } from './utils/util';
|
|
102
106
|
export { methodBadgeSolid, methodBadgeBright, methodBadgeTinted, statusBadgeSolid, statusBadgeTinted, statusBadgeSoft, } from './utils/httpColors';
|
|
103
107
|
export { rowKeyMissing, rowValueMissing } from './utils/kvRows';
|
|
104
108
|
export type { KeyValueRowLike } from './utils/kvRows';
|
|
105
109
|
export { sanitizeHtml, isSafeHref } from './utils/sanitizeHtml';
|
|
106
|
-
export { fmtNumber, fmtDate, fmtDateTime, fmtDateTimeMs, fmtDateShort, fmtCalendarDate, fmtCalendarDateTime, fmtMsAsSeconds, fmtBytes, fmtPrice, fmtPct, fmtUsd, fmtMoney, fmtDuration, formatJson, stringifyValue, } from './utils/format';
|
|
110
|
+
export { fmtNumber, fmtDate, fmtDateTime, fmtDateTimeMs, fmtDateShort, fmtCalendarDate, fmtCalendarDateTime, fmtMsAsSeconds, fmtBytes, fmtPrice, fmtPct, fmtUsd, fmtMoney, currencySymbol, fmtCurrencyAmount, fmtDuration, formatJson, stringifyValue, } from './utils/format';
|
|
107
111
|
export { isValidAbsoluteUrl, isValidJson, isValidXml, isValidBase64, } from './utils/validate';
|
|
108
112
|
export { buildSpecParams, firstInvalidNumericSpec } from './utils/specForm';
|
|
109
113
|
export { humanizeEnum, humanizeTextVNodes } from './utils/humanize';
|