@genspectrum/dashboard-components 0.10.0 → 0.10.2
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/custom-elements.json +186 -23
- package/dist/assets/{mutationOverTimeWorker-CvZg52rf.js.map → mutationOverTimeWorker-Di6yP1e6.js.map} +1 -1
- package/dist/components.d.ts +95 -45
- package/dist/components.js +402 -182
- package/dist/components.js.map +1 -1
- package/dist/{utilEntrypoint-g4DsyhU7.js → dateRangeOption-du8H7LWu.js} +33 -2
- package/dist/dateRangeOption-du8H7LWu.js.map +1 -0
- package/dist/style.css +41 -0
- package/dist/util.d.ts +114 -56
- package/dist/util.js +3 -2
- package/package.json +2 -2
- package/src/preact/components/color-scale-selector.tsx +7 -3
- package/src/preact/components/error-boundary.tsx +39 -5
- package/src/preact/components/error-display.tsx +40 -5
- package/src/preact/components/min-max-range-slider.tsx +4 -4
- package/src/preact/components/percent-intput.tsx +2 -2
- package/src/preact/dateRangeSelector/computeInitialValues.spec.ts +8 -2
- package/src/preact/dateRangeSelector/computeInitialValues.ts +6 -0
- package/src/preact/dateRangeSelector/date-range-selector.stories.tsx +16 -2
- package/src/preact/dateRangeSelector/date-range-selector.tsx +20 -15
- package/src/preact/dateRangeSelector/dateRangeOption.ts +10 -5
- package/src/preact/lineageFilter/lineage-filter.stories.tsx +18 -4
- package/src/preact/lineageFilter/lineage-filter.tsx +15 -10
- package/src/preact/locationFilter/location-filter.stories.tsx +14 -0
- package/src/preact/locationFilter/location-filter.tsx +15 -10
- package/src/preact/mutationComparison/mutation-comparison-venn.tsx +17 -18
- package/src/preact/mutationComparison/mutation-comparison.tsx +18 -12
- package/src/preact/mutationFilter/mutation-filter.tsx +0 -1
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutationsByDay.ts +1326 -9341
- package/src/preact/mutationsOverTime/__mockData__/byWeek.ts +615 -4920
- package/src/preact/mutationsOverTime/__mockData__/defaultMockData.ts +2203 -17624
- package/src/preact/mutationsOverTime/mutations-over-time-grid.tsx +16 -8
- package/src/preact/mutationsOverTime/mutations-over-time.tsx +1 -3
- package/src/preact/shared/stories/expectInvalidAttributesErrorMessage.ts +13 -0
- package/src/preact/statistic/__mockData__/denominator.json +13 -0
- package/src/preact/statistic/__mockData__/numerator.json +13 -0
- package/src/preact/statistic/statistics.stories.tsx +81 -0
- package/src/preact/statistic/statistics.tsx +78 -0
- package/src/preact/webWorkers/useWebWorker.ts +8 -4
- package/src/query/queryGeneralStatistics.ts +18 -0
- package/src/query/queryMutationsOverTime.spec.ts +12 -27
- package/src/query/queryMutationsOverTime.ts +2 -6
- package/src/types.ts +19 -6
- package/src/utilEntrypoint.ts +8 -0
- package/src/utils/map2d.spec.ts +10 -10
- package/src/utils/map2d.ts +10 -10
- package/src/web-components/input/gs-date-range-selector.stories.ts +2 -2
- package/src/web-components/input/gs-date-range-selector.tsx +3 -3
- package/src/web-components/input/gs-lineage-filter.tsx +1 -1
- package/src/web-components/input/gs-location-filter.tsx +2 -2
- package/src/web-components/visualization/gs-aggregate.tsx +2 -2
- package/src/web-components/visualization/gs-statistics.stories.ts +95 -0
- package/src/web-components/visualization/gs-statistics.tsx +83 -0
- package/src/web-components/visualization/index.ts +1 -0
- package/standalone-bundle/assets/{mutationOverTimeWorker-CypX_PYM.js.map → mutationOverTimeWorker-cIyshfj_.js.map} +1 -1
- package/standalone-bundle/dashboard-components.js +7747 -7592
- package/standalone-bundle/dashboard-components.js.map +1 -1
- package/standalone-bundle/style.css +1 -1
- package/dist/utilEntrypoint-g4DsyhU7.js.map +0 -1
|
@@ -1,7 +1,33 @@
|
|
|
1
|
+
import z from "zod";
|
|
2
|
+
const lapisFilterSchema = z.record(z.union([z.string(), z.number(), z.null(), z.boolean()]));
|
|
3
|
+
const namedLapisFilterSchema = z.object({
|
|
4
|
+
lapisFilter: lapisFilterSchema,
|
|
5
|
+
displayName: z.string()
|
|
6
|
+
});
|
|
7
|
+
const sequenceTypeSchema = z.union([z.literal("nucleotide"), z.literal("amino acid")]);
|
|
8
|
+
const views = {
|
|
9
|
+
table: "table",
|
|
10
|
+
venn: "venn"
|
|
11
|
+
};
|
|
12
|
+
const mutationComparisonViewSchema = z.union([z.literal(views.table), z.literal(views.venn)]);
|
|
1
13
|
const toYYYYMMDD = (date) => {
|
|
2
14
|
const options = { year: "numeric", month: "2-digit", day: "2-digit" };
|
|
3
15
|
return date.toLocaleDateString("en-CA", options);
|
|
4
16
|
};
|
|
17
|
+
const dateRangeOptionSchema = z.object({
|
|
18
|
+
/** The label of the date range option that will be shown to the user */
|
|
19
|
+
label: z.string(),
|
|
20
|
+
/**
|
|
21
|
+
* The start date of the date range in the format `YYYY-MM-DD`.
|
|
22
|
+
* If not set, the date range selector will default to the `earliestDate` property.
|
|
23
|
+
*/
|
|
24
|
+
dateFrom: z.string().date().optional(),
|
|
25
|
+
/**
|
|
26
|
+
* The end date of the date range in the format `YYYY-MM-DD`.
|
|
27
|
+
* If not set, the date range selector will default to the current date.
|
|
28
|
+
*/
|
|
29
|
+
dateTo: z.string().date().optional()
|
|
30
|
+
});
|
|
5
31
|
class DateRangeOptionChangedEvent extends CustomEvent {
|
|
6
32
|
constructor(detail) {
|
|
7
33
|
super("gs-date-range-option-changed", {
|
|
@@ -55,7 +81,12 @@ const dateRangeOptionPresets = {
|
|
|
55
81
|
};
|
|
56
82
|
export {
|
|
57
83
|
DateRangeOptionChangedEvent as D,
|
|
84
|
+
dateRangeOptionSchema as a,
|
|
58
85
|
dateRangeOptionPresets as d,
|
|
59
|
-
|
|
86
|
+
mutationComparisonViewSchema as m,
|
|
87
|
+
namedLapisFilterSchema as n,
|
|
88
|
+
sequenceTypeSchema as s,
|
|
89
|
+
toYYYYMMDD as t,
|
|
90
|
+
views as v
|
|
60
91
|
};
|
|
61
|
-
//# sourceMappingURL=
|
|
92
|
+
//# sourceMappingURL=dateRangeOption-du8H7LWu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dateRangeOption-du8H7LWu.js","sources":["../src/types.ts","../src/preact/dateRangeSelector/dateConversion.ts","../src/preact/dateRangeSelector/dateRangeOption.ts"],"sourcesContent":["import z from 'zod';\n\nimport {\n type Deletion,\n type DeletionClass,\n type Insertion,\n type InsertionClass,\n type Substitution,\n type SubstitutionClass,\n} from './utils/mutations';\n\nexport const lapisFilterSchema = z.record(z.union([z.string(), z.number(), z.null(), z.boolean()]));\nexport type LapisFilter = z.infer<typeof lapisFilterSchema>;\n\nexport const namedLapisFilterSchema = z.object({\n lapisFilter: lapisFilterSchema,\n displayName: z.string(),\n});\nexport type NamedLapisFilter = z.infer<typeof namedLapisFilterSchema>;\n\nexport type TemporalGranularity = 'day' | 'week' | 'month' | 'year';\n\nexport const sequenceTypeSchema = z.union([z.literal('nucleotide'), z.literal('amino acid')]);\nexport type SequenceType = z.infer<typeof sequenceTypeSchema>;\n\nexport type SubstitutionOrDeletion = 'substitution' | 'deletion';\n\nexport type MutationType = SubstitutionOrDeletion | 'insertion';\n\nexport type SubstitutionEntry<T extends Substitution = SubstitutionClass> = {\n type: 'substitution';\n mutation: T;\n count: number;\n proportion: number;\n};\n\nexport type DeletionEntry<T extends Deletion = DeletionClass> = {\n type: 'deletion';\n mutation: T;\n count: number;\n proportion: number;\n};\n\nexport type InsertionEntry<T extends Insertion = InsertionClass> = { type: 'insertion'; mutation: T; count: number };\n\nexport type SubstitutionOrDeletionEntry<\n S extends Substitution = SubstitutionClass,\n D extends Deletion = DeletionClass,\n> = SubstitutionEntry<S> | DeletionEntry<D>;\n\nexport type MutationEntry = SubstitutionEntry | DeletionEntry | InsertionEntry;\n\nexport const views = {\n table: 'table',\n venn: 'venn',\n} as const;\n\nexport const mutationComparisonViewSchema = z.union([z.literal(views.table), z.literal(views.venn)]);\nexport type MutationComparisonView = z.infer<typeof mutationComparisonViewSchema>;\n","export const toYYYYMMDD = (date: Date) => {\n const options: Intl.DateTimeFormatOptions = { year: 'numeric', month: '2-digit', day: '2-digit' };\n return date.toLocaleDateString('en-CA', options);\n};\n","import z from 'zod';\n\nimport { toYYYYMMDD } from './dateConversion';\n\n/**\n * A date range option that can be used in the `gs-date-range-selector` component.\n */\nexport const dateRangeOptionSchema = z.object({\n /** The label of the date range option that will be shown to the user */\n label: z.string(),\n /**\n * The start date of the date range in the format `YYYY-MM-DD`.\n * If not set, the date range selector will default to the `earliestDate` property.\n */\n dateFrom: z.string().date().optional(),\n /**\n * The end date of the date range in the format `YYYY-MM-DD`.\n * If not set, the date range selector will default to the current date.\n */\n dateTo: z.string().date().optional(),\n});\n\nexport type DateRangeOption = z.infer<typeof dateRangeOptionSchema>;\n\nexport type DateRangeSelectOption = string | { dateFrom: string; dateTo: string };\n\nexport class DateRangeOptionChangedEvent extends CustomEvent<DateRangeSelectOption> {\n constructor(detail: DateRangeSelectOption) {\n super('gs-date-range-option-changed', {\n detail,\n bubbles: true,\n composed: true,\n });\n }\n}\n\nconst today = new Date();\n\nconst twoWeeksAgo = new Date();\ntwoWeeksAgo.setDate(today.getDate() - 14);\n\nconst lastMonth = new Date(today);\nlastMonth.setMonth(today.getMonth() - 1);\n\nconst last2Months = new Date(today);\nlast2Months.setMonth(today.getMonth() - 2);\n\nconst last3Months = new Date(today);\nlast3Months.setMonth(today.getMonth() - 3);\n\nconst last6Months = new Date(today);\nlast6Months.setMonth(today.getMonth() - 6);\n\nconst lastYear = new Date(today);\nlastYear.setFullYear(today.getFullYear() - 1);\n\n/**\n * Presets for the `gs-date-range-selector` component that can be used as `dateRangeOptions`.\n */\nexport const dateRangeOptionPresets = {\n last2Weeks: {\n label: 'Last 2 weeks',\n dateFrom: toYYYYMMDD(twoWeeksAgo),\n },\n lastMonth: {\n label: 'Last month',\n dateFrom: toYYYYMMDD(lastMonth),\n },\n last2Months: {\n label: 'Last 2 months',\n dateFrom: toYYYYMMDD(last2Months),\n },\n last3Months: {\n label: 'Last 3 months',\n dateFrom: toYYYYMMDD(last3Months),\n },\n last6Months: {\n label: 'Last 6 months',\n dateFrom: toYYYYMMDD(last6Months),\n },\n lastYear: {\n label: 'Last year',\n dateFrom: toYYYYMMDD(lastYear),\n },\n allTimes: {\n label: 'All times',\n },\n} satisfies Record<string, DateRangeOption>;\n"],"names":[],"mappings":";AAWO,MAAM,oBAAoB,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,EAAE,OAAO,GAAG,EAAE,KAAK,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC;AAGrF,MAAA,yBAAyB,EAAE,OAAO;AAAA,EAC3C,aAAa;AAAA,EACb,aAAa,EAAE,OAAO;AAC1B,CAAC;AAKM,MAAM,qBAAqB,EAAE,MAAM,CAAC,EAAE,QAAQ,YAAY,GAAG,EAAE,QAAQ,YAAY,CAAC,CAAC;AA8BrF,MAAM,QAAQ;AAAA,EACjB,OAAO;AAAA,EACP,MAAM;AACV;AAEO,MAAM,+BAA+B,EAAE,MAAM,CAAC,EAAE,QAAQ,MAAM,KAAK,GAAG,EAAE,QAAQ,MAAM,IAAI,CAAC,CAAC;ACzDtF,MAAA,aAAa,CAAC,SAAe;AACtC,QAAM,UAAsC,EAAE,MAAM,WAAW,OAAO,WAAW,KAAK;AAC/E,SAAA,KAAK,mBAAmB,SAAS,OAAO;AACnD;ACIa,MAAA,wBAAwB,EAAE,OAAO;AAAA;AAAA,EAE1C,OAAO,EAAE,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA,EAKhB,UAAU,EAAE,OAAS,EAAA,KAAA,EAAO,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA,EAKrC,QAAQ,EAAE,OAAS,EAAA,KAAA,EAAO,SAAS;AACvC,CAAC;AAMM,MAAM,oCAAoC,YAAmC;AAAA,EAChF,YAAY,QAA+B;AACvC,UAAM,gCAAgC;AAAA,MAClC;AAAA,MACA,SAAS;AAAA,MACT,UAAU;AAAA,IAAA,CACb;AAAA,EACL;AACJ;AAEA,MAAM,4BAAY;AAElB,MAAM,kCAAkB;AACxB,YAAY,QAAQ,MAAM,QAAQ,IAAI,EAAE;AAExC,MAAM,YAAY,IAAI,KAAK,KAAK;AAChC,UAAU,SAAS,MAAM,SAAS,IAAI,CAAC;AAEvC,MAAM,cAAc,IAAI,KAAK,KAAK;AAClC,YAAY,SAAS,MAAM,SAAS,IAAI,CAAC;AAEzC,MAAM,cAAc,IAAI,KAAK,KAAK;AAClC,YAAY,SAAS,MAAM,SAAS,IAAI,CAAC;AAEzC,MAAM,cAAc,IAAI,KAAK,KAAK;AAClC,YAAY,SAAS,MAAM,SAAS,IAAI,CAAC;AAEzC,MAAM,WAAW,IAAI,KAAK,KAAK;AAC/B,SAAS,YAAY,MAAM,YAAY,IAAI,CAAC;AAKrC,MAAM,yBAAyB;AAAA,EAClC,YAAY;AAAA,IACR,OAAO;AAAA,IACP,UAAU,WAAW,WAAW;AAAA,EACpC;AAAA,EACA,WAAW;AAAA,IACP,OAAO;AAAA,IACP,UAAU,WAAW,SAAS;AAAA,EAClC;AAAA,EACA,aAAa;AAAA,IACT,OAAO;AAAA,IACP,UAAU,WAAW,WAAW;AAAA,EACpC;AAAA,EACA,aAAa;AAAA,IACT,OAAO;AAAA,IACP,UAAU,WAAW,WAAW;AAAA,EACpC;AAAA,EACA,aAAa;AAAA,IACT,OAAO;AAAA,IACP,UAAU,WAAW,WAAW;AAAA,EACpC;AAAA,EACA,UAAU;AAAA,IACN,OAAO;AAAA,IACP,UAAU,WAAW,QAAQ;AAAA,EACjC;AAAA,EACA,UAAU;AAAA,IACN,OAAO;AAAA,EACX;AACJ;"}
|
package/dist/style.css
CHANGED
|
@@ -1561,6 +1561,38 @@ html {
|
|
|
1561
1561
|
.select[multiple] {
|
|
1562
1562
|
height: auto;
|
|
1563
1563
|
}
|
|
1564
|
+
.stat {
|
|
1565
|
+
display: inline-grid;
|
|
1566
|
+
width: 100%;
|
|
1567
|
+
grid-template-columns: repeat(1, 1fr);
|
|
1568
|
+
-moz-column-gap: 1rem;
|
|
1569
|
+
column-gap: 1rem;
|
|
1570
|
+
border-color: var(--fallback-bc,oklch(var(--bc)/var(--tw-border-opacity)));
|
|
1571
|
+
--tw-border-opacity: 0.1;
|
|
1572
|
+
padding-left: 1.5rem;
|
|
1573
|
+
padding-right: 1.5rem;
|
|
1574
|
+
padding-top: 1rem;
|
|
1575
|
+
padding-bottom: 1rem;
|
|
1576
|
+
}
|
|
1577
|
+
.stat-title {
|
|
1578
|
+
grid-column-start: 1;
|
|
1579
|
+
white-space: nowrap;
|
|
1580
|
+
color: var(--fallback-bc,oklch(var(--bc)/0.6));
|
|
1581
|
+
}
|
|
1582
|
+
.stat-value {
|
|
1583
|
+
grid-column-start: 1;
|
|
1584
|
+
white-space: nowrap;
|
|
1585
|
+
font-size: 2.25rem;
|
|
1586
|
+
line-height: 2.5rem;
|
|
1587
|
+
font-weight: 800;
|
|
1588
|
+
}
|
|
1589
|
+
.stat-desc {
|
|
1590
|
+
grid-column-start: 1;
|
|
1591
|
+
white-space: nowrap;
|
|
1592
|
+
font-size: 0.75rem;
|
|
1593
|
+
line-height: 1rem;
|
|
1594
|
+
color: var(--fallback-bc,oklch(var(--bc)/0.6));
|
|
1595
|
+
}
|
|
1564
1596
|
.steps {
|
|
1565
1597
|
display: inline-grid;
|
|
1566
1598
|
grid-auto-flow: column;
|
|
@@ -3427,6 +3459,15 @@ input.tab:checked + .tab-content,
|
|
|
3427
3459
|
.sm\:max-w-5xl {
|
|
3428
3460
|
max-width: 64rem;
|
|
3429
3461
|
}
|
|
3462
|
+
|
|
3463
|
+
.sm\:flex-row {
|
|
3464
|
+
flex-direction: row;
|
|
3465
|
+
}
|
|
3466
|
+
|
|
3467
|
+
.sm\:text-4xl {
|
|
3468
|
+
font-size: 2.25rem;
|
|
3469
|
+
line-height: 2.5rem;
|
|
3470
|
+
}
|
|
3430
3471
|
}.flatpickr-calendar{background:transparent;opacity:0;display:none;text-align:center;visibility:hidden;padding:0;-webkit-animation:none;animation:none;direction:ltr;border:0;font-size:14px;line-height:24px;border-radius:5px;position:absolute;width:307.875px;-webkit-box-sizing:border-box;box-sizing:border-box;-ms-touch-action:manipulation;touch-action:manipulation;background:#fff;-webkit-box-shadow:1px 0 0 #e6e6e6,-1px 0 0 #e6e6e6,0 1px 0 #e6e6e6,0 -1px 0 #e6e6e6,0 3px 13px rgba(0,0,0,0.08);box-shadow:1px 0 0 #e6e6e6,-1px 0 0 #e6e6e6,0 1px 0 #e6e6e6,0 -1px 0 #e6e6e6,0 3px 13px rgba(0,0,0,0.08)}.flatpickr-calendar.open,.flatpickr-calendar.inline{opacity:1;max-height:640px;visibility:visible}.flatpickr-calendar.open{display:inline-block;z-index:99999}.flatpickr-calendar.animate.open{-webkit-animation:fpFadeInDown 300ms cubic-bezier(.23,1,.32,1);animation:fpFadeInDown 300ms cubic-bezier(.23,1,.32,1)}.flatpickr-calendar.inline{display:block;position:relative;top:2px}.flatpickr-calendar.static{position:absolute;top:calc(100% + 2px)}.flatpickr-calendar.static.open{z-index:999;display:block}.flatpickr-calendar.multiMonth .flatpickr-days .dayContainer:nth-child(n+1) .flatpickr-day.inRange:nth-child(7n+7){-webkit-box-shadow:none !important;box-shadow:none !important}.flatpickr-calendar.multiMonth .flatpickr-days .dayContainer:nth-child(n+2) .flatpickr-day.inRange:nth-child(7n+1){-webkit-box-shadow:-2px 0 0 #e6e6e6,5px 0 0 #e6e6e6;box-shadow:-2px 0 0 #e6e6e6,5px 0 0 #e6e6e6}.flatpickr-calendar .hasWeeks .dayContainer,.flatpickr-calendar .hasTime .dayContainer{border-bottom:0;border-bottom-right-radius:0;border-bottom-left-radius:0}.flatpickr-calendar .hasWeeks .dayContainer{border-left:0}.flatpickr-calendar.hasTime .flatpickr-time{height:40px;border-top:1px solid #e6e6e6}.flatpickr-calendar.noCalendar.hasTime .flatpickr-time{height:auto}.flatpickr-calendar:before,.flatpickr-calendar:after{position:absolute;display:block;pointer-events:none;border:solid transparent;content:'';height:0;width:0;left:22px}.flatpickr-calendar.rightMost:before,.flatpickr-calendar.arrowRight:before,.flatpickr-calendar.rightMost:after,.flatpickr-calendar.arrowRight:after{left:auto;right:22px}.flatpickr-calendar.arrowCenter:before,.flatpickr-calendar.arrowCenter:after{left:50%;right:50%}.flatpickr-calendar:before{border-width:5px;margin:0 -5px}.flatpickr-calendar:after{border-width:4px;margin:0 -4px}.flatpickr-calendar.arrowTop:before,.flatpickr-calendar.arrowTop:after{bottom:100%}.flatpickr-calendar.arrowTop:before{border-bottom-color:#e6e6e6}.flatpickr-calendar.arrowTop:after{border-bottom-color:#fff}.flatpickr-calendar.arrowBottom:before,.flatpickr-calendar.arrowBottom:after{top:100%}.flatpickr-calendar.arrowBottom:before{border-top-color:#e6e6e6}.flatpickr-calendar.arrowBottom:after{border-top-color:#fff}.flatpickr-calendar:focus{outline:0}.flatpickr-wrapper{position:relative;display:inline-block}.flatpickr-months{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.flatpickr-months .flatpickr-month{background:transparent;color:rgba(0,0,0,0.9);fill:rgba(0,0,0,0.9);height:34px;line-height:1;text-align:center;position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;overflow:hidden;-webkit-box-flex:1;-webkit-flex:1;-ms-flex:1;flex:1}.flatpickr-months .flatpickr-prev-month,.flatpickr-months .flatpickr-next-month{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;text-decoration:none;cursor:pointer;position:absolute;top:0;height:34px;padding:10px;z-index:3;color:rgba(0,0,0,0.9);fill:rgba(0,0,0,0.9)}.flatpickr-months .flatpickr-prev-month.flatpickr-disabled,.flatpickr-months .flatpickr-next-month.flatpickr-disabled{display:none}.flatpickr-months .flatpickr-prev-month i,.flatpickr-months .flatpickr-next-month i{position:relative}.flatpickr-months .flatpickr-prev-month.flatpickr-prev-month,.flatpickr-months .flatpickr-next-month.flatpickr-prev-month{/*
|
|
3431
3472
|
/*rtl:begin:ignore*/left:0/*
|
|
3432
3473
|
/*rtl:end:ignore*/}/*
|
package/dist/util.d.ts
CHANGED
|
@@ -1,20 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export declare type DateRangeOption = {
|
|
5
|
-
/** The label of the date range option that will be shown to the user */
|
|
6
|
-
label: string;
|
|
7
|
-
/**
|
|
8
|
-
* The start date of the date range in the format `YYYY-MM-DD`.
|
|
9
|
-
* If not set, the date range selector will default to the `earliestDate` property.
|
|
10
|
-
*/
|
|
11
|
-
dateFrom?: string;
|
|
12
|
-
/**
|
|
13
|
-
* The end date of the date range in the format `YYYY-MM-DD`.
|
|
14
|
-
* If not set, the date range selector will default to the current date.
|
|
15
|
-
*/
|
|
16
|
-
dateTo?: string;
|
|
17
|
-
};
|
|
1
|
+
import { default as default_2 } from 'zod';
|
|
2
|
+
|
|
3
|
+
export declare type DateRangeOption = default_2.infer<typeof dateRangeOptionSchema>;
|
|
18
4
|
|
|
19
5
|
export declare class DateRangeOptionChangedEvent extends CustomEvent<DateRangeSelectOption> {
|
|
20
6
|
constructor(detail: DateRangeSelectOption);
|
|
@@ -53,11 +39,67 @@ export declare const dateRangeOptionPresets: {
|
|
|
53
39
|
};
|
|
54
40
|
};
|
|
55
41
|
|
|
42
|
+
/**
|
|
43
|
+
* A date range option that can be used in the `gs-date-range-selector` component.
|
|
44
|
+
*/
|
|
45
|
+
declare const dateRangeOptionSchema: default_2.ZodObject<{
|
|
46
|
+
/** The label of the date range option that will be shown to the user */
|
|
47
|
+
label: default_2.ZodString;
|
|
48
|
+
/**
|
|
49
|
+
* The start date of the date range in the format `YYYY-MM-DD`.
|
|
50
|
+
* If not set, the date range selector will default to the `earliestDate` property.
|
|
51
|
+
*/
|
|
52
|
+
dateFrom: default_2.ZodOptional<default_2.ZodString>;
|
|
53
|
+
/**
|
|
54
|
+
* The end date of the date range in the format `YYYY-MM-DD`.
|
|
55
|
+
* If not set, the date range selector will default to the current date.
|
|
56
|
+
*/
|
|
57
|
+
dateTo: default_2.ZodOptional<default_2.ZodString>;
|
|
58
|
+
}, "strip", default_2.ZodTypeAny, {
|
|
59
|
+
label: string;
|
|
60
|
+
dateFrom?: string | undefined;
|
|
61
|
+
dateTo?: string | undefined;
|
|
62
|
+
}, {
|
|
63
|
+
label: string;
|
|
64
|
+
dateFrom?: string | undefined;
|
|
65
|
+
dateTo?: string | undefined;
|
|
66
|
+
}>;
|
|
67
|
+
|
|
56
68
|
export declare type DateRangeSelectOption = string | {
|
|
57
69
|
dateFrom: string;
|
|
58
70
|
dateTo: string;
|
|
59
71
|
};
|
|
60
72
|
|
|
73
|
+
export declare type LapisFilter = default_2.infer<typeof lapisFilterSchema>;
|
|
74
|
+
|
|
75
|
+
declare const lapisFilterSchema: default_2.ZodRecord<default_2.ZodString, default_2.ZodUnion<[default_2.ZodString, default_2.ZodNumber, default_2.ZodNull, default_2.ZodBoolean]>>;
|
|
76
|
+
|
|
77
|
+
export declare type MutationComparisonView = default_2.infer<typeof mutationComparisonViewSchema>;
|
|
78
|
+
|
|
79
|
+
declare const mutationComparisonViewSchema: default_2.ZodUnion<[default_2.ZodLiteral<"table">, default_2.ZodLiteral<"venn">]>;
|
|
80
|
+
|
|
81
|
+
export declare type NamedLapisFilter = default_2.infer<typeof namedLapisFilterSchema>;
|
|
82
|
+
|
|
83
|
+
declare const namedLapisFilterSchema: default_2.ZodObject<{
|
|
84
|
+
lapisFilter: default_2.ZodRecord<default_2.ZodString, default_2.ZodUnion<[default_2.ZodString, default_2.ZodNumber, default_2.ZodNull, default_2.ZodBoolean]>>;
|
|
85
|
+
displayName: default_2.ZodString;
|
|
86
|
+
}, "strip", default_2.ZodTypeAny, {
|
|
87
|
+
lapisFilter: Record<string, string | number | boolean | null>;
|
|
88
|
+
displayName: string;
|
|
89
|
+
}, {
|
|
90
|
+
lapisFilter: Record<string, string | number | boolean | null>;
|
|
91
|
+
displayName: string;
|
|
92
|
+
}>;
|
|
93
|
+
|
|
94
|
+
export declare type SequenceType = default_2.infer<typeof sequenceTypeSchema>;
|
|
95
|
+
|
|
96
|
+
declare const sequenceTypeSchema: default_2.ZodUnion<[default_2.ZodLiteral<"nucleotide">, default_2.ZodLiteral<"amino acid">]>;
|
|
97
|
+
|
|
98
|
+
export declare const views: {
|
|
99
|
+
readonly table: "table";
|
|
100
|
+
readonly venn: "venn";
|
|
101
|
+
};
|
|
102
|
+
|
|
61
103
|
export { }
|
|
62
104
|
|
|
63
105
|
|
|
@@ -86,7 +128,11 @@ declare global {
|
|
|
86
128
|
|
|
87
129
|
declare global {
|
|
88
130
|
interface HTMLElementTagNameMap {
|
|
89
|
-
'gs-
|
|
131
|
+
'gs-date-range-selector': DateRangeSelectorComponent;
|
|
132
|
+
}
|
|
133
|
+
interface HTMLElementEventMap {
|
|
134
|
+
'gs-date-range-filter-changed': CustomEvent<Record<string, string>>;
|
|
135
|
+
'gs-date-range-option-changed': DateRangeOptionChangedEvent;
|
|
90
136
|
}
|
|
91
137
|
}
|
|
92
138
|
|
|
@@ -94,7 +140,7 @@ declare global {
|
|
|
94
140
|
declare global {
|
|
95
141
|
namespace JSX {
|
|
96
142
|
interface IntrinsicElements {
|
|
97
|
-
'gs-
|
|
143
|
+
'gs-date-range-selector': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
98
144
|
}
|
|
99
145
|
}
|
|
100
146
|
}
|
|
@@ -102,7 +148,10 @@ declare global {
|
|
|
102
148
|
|
|
103
149
|
declare global {
|
|
104
150
|
interface HTMLElementTagNameMap {
|
|
105
|
-
'gs-
|
|
151
|
+
'gs-location-filter': LocationFilterComponent;
|
|
152
|
+
}
|
|
153
|
+
interface HTMLElementEventMap {
|
|
154
|
+
'gs-location-changed': CustomEvent<Record<string, string>>;
|
|
106
155
|
}
|
|
107
156
|
}
|
|
108
157
|
|
|
@@ -110,7 +159,7 @@ declare global {
|
|
|
110
159
|
declare global {
|
|
111
160
|
namespace JSX {
|
|
112
161
|
interface IntrinsicElements {
|
|
113
|
-
'gs-
|
|
162
|
+
'gs-location-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
114
163
|
}
|
|
115
164
|
}
|
|
116
165
|
}
|
|
@@ -118,7 +167,10 @@ declare global {
|
|
|
118
167
|
|
|
119
168
|
declare global {
|
|
120
169
|
interface HTMLElementTagNameMap {
|
|
121
|
-
'gs-
|
|
170
|
+
'gs-text-input': TextInputComponent;
|
|
171
|
+
}
|
|
172
|
+
interface HTMLElementEventMap {
|
|
173
|
+
'gs-text-input-changed': CustomEvent<Record<string, string>>;
|
|
122
174
|
}
|
|
123
175
|
}
|
|
124
176
|
|
|
@@ -126,7 +178,7 @@ declare global {
|
|
|
126
178
|
declare global {
|
|
127
179
|
namespace JSX {
|
|
128
180
|
interface IntrinsicElements {
|
|
129
|
-
'gs-
|
|
181
|
+
'gs-text-input': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
130
182
|
}
|
|
131
183
|
}
|
|
132
184
|
}
|
|
@@ -134,7 +186,10 @@ declare global {
|
|
|
134
186
|
|
|
135
187
|
declare global {
|
|
136
188
|
interface HTMLElementTagNameMap {
|
|
137
|
-
'gs-
|
|
189
|
+
'gs-mutation-filter': MutationFilterComponent;
|
|
190
|
+
}
|
|
191
|
+
interface HTMLElementEventMap {
|
|
192
|
+
'gs-mutation-filter-changed': CustomEvent<SelectedMutationFilterStrings>;
|
|
138
193
|
}
|
|
139
194
|
}
|
|
140
195
|
|
|
@@ -142,7 +197,7 @@ declare global {
|
|
|
142
197
|
declare global {
|
|
143
198
|
namespace JSX {
|
|
144
199
|
interface IntrinsicElements {
|
|
145
|
-
'gs-
|
|
200
|
+
'gs-mutation-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
146
201
|
}
|
|
147
202
|
}
|
|
148
203
|
}
|
|
@@ -150,7 +205,10 @@ declare global {
|
|
|
150
205
|
|
|
151
206
|
declare global {
|
|
152
207
|
interface HTMLElementTagNameMap {
|
|
153
|
-
'gs-
|
|
208
|
+
'gs-lineage-filter': LineageFilterComponent;
|
|
209
|
+
}
|
|
210
|
+
interface HTMLElementEventMap {
|
|
211
|
+
'gs-lineage-filter-changed': CustomEvent<Record<string, string>>;
|
|
154
212
|
}
|
|
155
213
|
}
|
|
156
214
|
|
|
@@ -158,7 +216,7 @@ declare global {
|
|
|
158
216
|
declare global {
|
|
159
217
|
namespace JSX {
|
|
160
218
|
interface IntrinsicElements {
|
|
161
|
-
'gs-
|
|
219
|
+
'gs-lineage-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
162
220
|
}
|
|
163
221
|
}
|
|
164
222
|
}
|
|
@@ -166,7 +224,7 @@ declare global {
|
|
|
166
224
|
|
|
167
225
|
declare global {
|
|
168
226
|
interface HTMLElementTagNameMap {
|
|
169
|
-
'gs-
|
|
227
|
+
'gs-mutation-comparison-component': MutationComparisonComponent;
|
|
170
228
|
}
|
|
171
229
|
}
|
|
172
230
|
|
|
@@ -174,7 +232,7 @@ declare global {
|
|
|
174
232
|
declare global {
|
|
175
233
|
namespace JSX {
|
|
176
234
|
interface IntrinsicElements {
|
|
177
|
-
'gs-
|
|
235
|
+
'gs-mutation-comparison-component': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
178
236
|
}
|
|
179
237
|
}
|
|
180
238
|
}
|
|
@@ -182,7 +240,7 @@ declare global {
|
|
|
182
240
|
|
|
183
241
|
declare global {
|
|
184
242
|
interface HTMLElementTagNameMap {
|
|
185
|
-
'gs-mutations-
|
|
243
|
+
'gs-mutations-component': MutationsComponent;
|
|
186
244
|
}
|
|
187
245
|
}
|
|
188
246
|
|
|
@@ -190,7 +248,7 @@ declare global {
|
|
|
190
248
|
declare global {
|
|
191
249
|
namespace JSX {
|
|
192
250
|
interface IntrinsicElements {
|
|
193
|
-
'gs-mutations-
|
|
251
|
+
'gs-mutations-component': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
194
252
|
}
|
|
195
253
|
}
|
|
196
254
|
}
|
|
@@ -198,11 +256,7 @@ declare global {
|
|
|
198
256
|
|
|
199
257
|
declare global {
|
|
200
258
|
interface HTMLElementTagNameMap {
|
|
201
|
-
'gs-
|
|
202
|
-
}
|
|
203
|
-
interface HTMLElementEventMap {
|
|
204
|
-
'gs-date-range-filter-changed': CustomEvent<Record<string, string>>;
|
|
205
|
-
'gs-date-range-option-changed': DateRangeOptionChangedEvent;
|
|
259
|
+
'gs-prevalence-over-time': PrevalenceOverTimeComponent;
|
|
206
260
|
}
|
|
207
261
|
}
|
|
208
262
|
|
|
@@ -210,7 +264,7 @@ declare global {
|
|
|
210
264
|
declare global {
|
|
211
265
|
namespace JSX {
|
|
212
266
|
interface IntrinsicElements {
|
|
213
|
-
'gs-
|
|
267
|
+
'gs-prevalence-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
214
268
|
}
|
|
215
269
|
}
|
|
216
270
|
}
|
|
@@ -218,10 +272,7 @@ declare global {
|
|
|
218
272
|
|
|
219
273
|
declare global {
|
|
220
274
|
interface HTMLElementTagNameMap {
|
|
221
|
-
'gs-
|
|
222
|
-
}
|
|
223
|
-
interface HTMLElementEventMap {
|
|
224
|
-
'gs-location-changed': CustomEvent<Record<string, string>>;
|
|
275
|
+
'gs-relative-growth-advantage': RelativeGrowthAdvantageComponent;
|
|
225
276
|
}
|
|
226
277
|
}
|
|
227
278
|
|
|
@@ -229,7 +280,7 @@ declare global {
|
|
|
229
280
|
declare global {
|
|
230
281
|
namespace JSX {
|
|
231
282
|
interface IntrinsicElements {
|
|
232
|
-
'gs-
|
|
283
|
+
'gs-relative-growth-advantage': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
233
284
|
}
|
|
234
285
|
}
|
|
235
286
|
}
|
|
@@ -237,10 +288,7 @@ declare global {
|
|
|
237
288
|
|
|
238
289
|
declare global {
|
|
239
290
|
interface HTMLElementTagNameMap {
|
|
240
|
-
'gs-
|
|
241
|
-
}
|
|
242
|
-
interface HTMLElementEventMap {
|
|
243
|
-
'gs-text-input-changed': CustomEvent<Record<string, string>>;
|
|
291
|
+
'gs-aggregate': AggregateComponent;
|
|
244
292
|
}
|
|
245
293
|
}
|
|
246
294
|
|
|
@@ -248,7 +296,7 @@ declare global {
|
|
|
248
296
|
declare global {
|
|
249
297
|
namespace JSX {
|
|
250
298
|
interface IntrinsicElements {
|
|
251
|
-
'gs-
|
|
299
|
+
'gs-aggregate': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
252
300
|
}
|
|
253
301
|
}
|
|
254
302
|
}
|
|
@@ -256,10 +304,7 @@ declare global {
|
|
|
256
304
|
|
|
257
305
|
declare global {
|
|
258
306
|
interface HTMLElementTagNameMap {
|
|
259
|
-
'gs-
|
|
260
|
-
}
|
|
261
|
-
interface HTMLElementEventMap {
|
|
262
|
-
'gs-mutation-filter-changed': CustomEvent<SelectedMutationFilterStrings>;
|
|
307
|
+
'gs-number-sequences-over-time': NumberSequencesOverTimeComponent;
|
|
263
308
|
}
|
|
264
309
|
}
|
|
265
310
|
|
|
@@ -267,7 +312,7 @@ declare global {
|
|
|
267
312
|
declare global {
|
|
268
313
|
namespace JSX {
|
|
269
314
|
interface IntrinsicElements {
|
|
270
|
-
'gs-
|
|
315
|
+
'gs-number-sequences-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
271
316
|
}
|
|
272
317
|
}
|
|
273
318
|
}
|
|
@@ -275,10 +320,23 @@ declare global {
|
|
|
275
320
|
|
|
276
321
|
declare global {
|
|
277
322
|
interface HTMLElementTagNameMap {
|
|
278
|
-
'gs-
|
|
323
|
+
'gs-mutations-over-time': MutationsOverTimeComponent;
|
|
279
324
|
}
|
|
280
|
-
|
|
281
|
-
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
declare global {
|
|
329
|
+
namespace JSX {
|
|
330
|
+
interface IntrinsicElements {
|
|
331
|
+
'gs-mutations-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
declare global {
|
|
338
|
+
interface HTMLElementTagNameMap {
|
|
339
|
+
'gs-statistics': StatisticsComponent;
|
|
282
340
|
}
|
|
283
341
|
}
|
|
284
342
|
|
|
@@ -286,7 +344,7 @@ declare global {
|
|
|
286
344
|
declare global {
|
|
287
345
|
namespace JSX {
|
|
288
346
|
interface IntrinsicElements {
|
|
289
|
-
'gs-
|
|
347
|
+
'gs-statistics': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
290
348
|
}
|
|
291
349
|
}
|
|
292
350
|
}
|
package/dist/util.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { D, d } from "./
|
|
1
|
+
import { D, d, v } from "./dateRangeOption-du8H7LWu.js";
|
|
2
2
|
export {
|
|
3
3
|
D as DateRangeOptionChangedEvent,
|
|
4
|
-
d as dateRangeOptionPresets
|
|
4
|
+
d as dateRangeOptionPresets,
|
|
5
|
+
v as views
|
|
5
6
|
};
|
|
6
7
|
//# sourceMappingURL=util.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@genspectrum/dashboard-components",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.2",
|
|
4
4
|
"description": "GenSpectrum web components for building dashboards",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "AGPL-3.0-only",
|
|
@@ -132,7 +132,7 @@
|
|
|
132
132
|
"storybook": "^8.0.9",
|
|
133
133
|
"storybook-addon-fetch-mock": "^2.0.0",
|
|
134
134
|
"tailwindcss": "^3.4.3",
|
|
135
|
-
"typescript": "~5.
|
|
135
|
+
"typescript": "~5.7.2",
|
|
136
136
|
"vite": "^5.2.10",
|
|
137
137
|
"vite-plugin-dts": "^4.0.3",
|
|
138
138
|
"vitest": "^2.0.1"
|
|
@@ -54,7 +54,11 @@ export const ColorScaleSelector: FunctionComponent<ColorScaleSelectorProps> = ({
|
|
|
54
54
|
);
|
|
55
55
|
};
|
|
56
56
|
|
|
57
|
-
export const getColorWithingScale = (value: number, colorScale: ColorScale) => {
|
|
57
|
+
export const getColorWithingScale = (value: number | undefined, colorScale: ColorScale) => {
|
|
58
|
+
if (value === undefined) {
|
|
59
|
+
return 'lightgrey';
|
|
60
|
+
}
|
|
61
|
+
|
|
58
62
|
if (colorScale.min === colorScale.max) {
|
|
59
63
|
return singleGraphColorRGBByName(colorScale.color, 0);
|
|
60
64
|
}
|
|
@@ -66,8 +70,8 @@ export const getColorWithingScale = (value: number, colorScale: ColorScale) => {
|
|
|
66
70
|
return singleGraphColorRGBByName(colorScale.color, alpha);
|
|
67
71
|
};
|
|
68
72
|
|
|
69
|
-
export const getTextColorForScale = (value: number, colorScale: ColorScale) => {
|
|
70
|
-
if (colorScale.min === colorScale.max) {
|
|
73
|
+
export const getTextColorForScale = (value: number | undefined, colorScale: ColorScale) => {
|
|
74
|
+
if (value === undefined || colorScale.min === colorScale.max) {
|
|
71
75
|
return 'black';
|
|
72
76
|
}
|
|
73
77
|
|
|
@@ -1,16 +1,26 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import { useErrorBoundary } from 'preact/hooks';
|
|
1
|
+
import { type RenderableProps } from 'preact';
|
|
2
|
+
import { useErrorBoundary, useMemo } from 'preact/hooks';
|
|
3
|
+
import { type ZodSchema } from 'zod';
|
|
3
4
|
|
|
4
|
-
import { ErrorDisplay, type ErrorDisplayProps } from './error-display';
|
|
5
|
+
import { ErrorDisplay, type ErrorDisplayProps, InvalidPropsError } from './error-display';
|
|
5
6
|
import { ResizeContainer, type Size } from './resize-container';
|
|
6
7
|
|
|
7
|
-
type ErrorBoundaryProps = {
|
|
8
|
+
type ErrorBoundaryProps<T> = {
|
|
8
9
|
size: Size;
|
|
9
10
|
layout?: ErrorDisplayProps['layout'];
|
|
11
|
+
componentProps?: T;
|
|
12
|
+
schema?: ZodSchema<T>;
|
|
10
13
|
};
|
|
11
14
|
|
|
12
|
-
export const ErrorBoundary
|
|
15
|
+
export const ErrorBoundary = <T extends Record<string, unknown>>({
|
|
16
|
+
size,
|
|
17
|
+
layout,
|
|
18
|
+
componentProps,
|
|
19
|
+
schema,
|
|
20
|
+
children,
|
|
21
|
+
}: RenderableProps<ErrorBoundaryProps<T>>) => {
|
|
13
22
|
const [internalError, resetError] = useErrorBoundary();
|
|
23
|
+
const componentPropsParseError = useCheckComponentProps(schema, componentProps);
|
|
14
24
|
|
|
15
25
|
if (internalError) {
|
|
16
26
|
return (
|
|
@@ -20,5 +30,29 @@ export const ErrorBoundary: FunctionComponent<ErrorBoundaryProps> = ({ size, lay
|
|
|
20
30
|
);
|
|
21
31
|
}
|
|
22
32
|
|
|
33
|
+
if (componentPropsParseError !== undefined) {
|
|
34
|
+
return (
|
|
35
|
+
<ResizeContainer size={size}>
|
|
36
|
+
<ErrorDisplay error={componentPropsParseError} layout={layout} />
|
|
37
|
+
</ResizeContainer>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
23
41
|
return <>{children}</>;
|
|
24
42
|
};
|
|
43
|
+
|
|
44
|
+
// TODO #554 - make both arguments required once all components validate their props
|
|
45
|
+
function useCheckComponentProps<T extends Record<string, unknown>>(schema?: ZodSchema<T>, componentProps?: T) {
|
|
46
|
+
return useMemo(() => {
|
|
47
|
+
if (schema === undefined || componentProps === undefined) {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const parseResult = schema.safeParse(componentProps);
|
|
52
|
+
if (parseResult.success) {
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return new InvalidPropsError(parseResult.error, componentProps);
|
|
57
|
+
}, [componentProps, schema]);
|
|
58
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type FunctionComponent } from 'preact';
|
|
2
2
|
import { useEffect, useRef } from 'preact/hooks';
|
|
3
|
+
import { type ZodError } from 'zod';
|
|
3
4
|
|
|
4
5
|
import { LapisError, UnknownLapisError } from '../../lapisApi/lapisApi';
|
|
5
6
|
|
|
@@ -24,9 +25,19 @@ export class UserFacingError extends Error {
|
|
|
24
25
|
}
|
|
25
26
|
}
|
|
26
27
|
|
|
28
|
+
export class InvalidPropsError extends Error {
|
|
29
|
+
constructor(
|
|
30
|
+
public readonly zodError: ZodError,
|
|
31
|
+
public readonly componentProps: Record<string, unknown>,
|
|
32
|
+
) {
|
|
33
|
+
super(zodError.message);
|
|
34
|
+
this.name = 'InvalidPropsError';
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
27
38
|
export type ErrorDisplayProps = {
|
|
28
39
|
error: Error;
|
|
29
|
-
resetError
|
|
40
|
+
resetError?: () => void;
|
|
30
41
|
layout?: 'horizontal' | 'vertical';
|
|
31
42
|
};
|
|
32
43
|
|
|
@@ -76,10 +87,12 @@ export const ErrorDisplay: FunctionComponent<ErrorDisplayProps> = ({ error, rese
|
|
|
76
87
|
)}
|
|
77
88
|
</div>
|
|
78
89
|
</div>
|
|
79
|
-
|
|
80
|
-
<
|
|
81
|
-
|
|
82
|
-
|
|
90
|
+
{resetError !== undefined && (
|
|
91
|
+
<button onClick={resetError} className='btn btn-sm flex items-center m-4'>
|
|
92
|
+
<span className='iconify mdi--reload text-lg' />
|
|
93
|
+
Try again
|
|
94
|
+
</button>
|
|
95
|
+
)}
|
|
83
96
|
</div>
|
|
84
97
|
);
|
|
85
98
|
};
|
|
@@ -115,5 +128,27 @@ function getDisplayedErrorMessage(error: Error) {
|
|
|
115
128
|
};
|
|
116
129
|
}
|
|
117
130
|
|
|
131
|
+
if (error instanceof InvalidPropsError) {
|
|
132
|
+
const firstError = error.zodError.errors[0];
|
|
133
|
+
let message = error.zodError.issues
|
|
134
|
+
.map((issue) => {
|
|
135
|
+
const actual =
|
|
136
|
+
issue.path[0] in error.componentProps
|
|
137
|
+
? ` '${JSON.stringify(error.componentProps[issue.path[0]])}'`
|
|
138
|
+
: '';
|
|
139
|
+
return `Unexpected value${actual} for "${issue.path.join('.')}": ${issue.message}`;
|
|
140
|
+
})
|
|
141
|
+
.join(' - ');
|
|
142
|
+
|
|
143
|
+
if (firstError.code === 'invalid_type' && firstError.received === 'null') {
|
|
144
|
+
message = `Is the "${firstError.path[0]}" attribute in the HTML of the correct type? ${message}`;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
headline: 'Error - Invalid component attributes',
|
|
149
|
+
details: { headline: 'Invalid component attributes', message },
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
118
153
|
return { headline: 'Error', details: undefined };
|
|
119
154
|
}
|