@examplary/ui 1.84.1 → 1.85.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.
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { ComponentType } from "react";
|
|
2
2
|
export declare const loadComponentStyles: (url: string) => void;
|
|
3
3
|
export declare const evalComponent: (js: string) => Promise<ComponentType>;
|
|
4
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Loads and evaluates the component at `url`. With a `sha256`, a component
|
|
6
|
+
* that doesn't match it (e.g. replaced after a review) is refused.
|
|
7
|
+
*/
|
|
8
|
+
export declare const fetchComponent: (url: string, sha256?: string) => Promise<ComponentType>;
|
|
@@ -78,9 +78,15 @@ export const evalComponent = async (js) => {
|
|
|
78
78
|
})();
|
|
79
79
|
return _componentResult;
|
|
80
80
|
};
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
81
|
+
const sha256Of = async (text) => Array.from(new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(text))), (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
82
|
+
/**
|
|
83
|
+
* Loads and evaluates the component at `url`. With a `sha256`, a component
|
|
84
|
+
* that doesn't match it (e.g. replaced after a review) is refused.
|
|
85
|
+
*/
|
|
86
|
+
export const fetchComponent = async (url, sha256) => {
|
|
87
|
+
const cacheKey = sha256 ? `${sha256}:${url}` : url;
|
|
88
|
+
if (componentCache.has(cacheKey)) {
|
|
89
|
+
return componentCache.get(cacheKey);
|
|
84
90
|
}
|
|
85
91
|
const js = await fetch(url).then((res) => {
|
|
86
92
|
if (!res.ok) {
|
|
@@ -88,7 +94,10 @@ export const fetchComponent = async (url) => {
|
|
|
88
94
|
}
|
|
89
95
|
return res.text();
|
|
90
96
|
});
|
|
97
|
+
if (sha256 && (await sha256Of(js)) !== sha256) {
|
|
98
|
+
throw new Error(`The component at ${url} doesn't match its digest`);
|
|
99
|
+
}
|
|
91
100
|
const res = await evalComponent(js);
|
|
92
|
-
componentCache.set(
|
|
101
|
+
componentCache.set(cacheKey, res);
|
|
93
102
|
return res;
|
|
94
103
|
};
|
|
@@ -84,7 +84,7 @@ export declare const formatQuestionType: (type: QuestionType, i18n: i18n) => {
|
|
|
84
84
|
"settings-area"?: string | undefined;
|
|
85
85
|
results?: string | undefined;
|
|
86
86
|
} | undefined;
|
|
87
|
-
|
|
87
|
+
hooks?: Record<string, string> | undefined;
|
|
88
88
|
public?: boolean | undefined;
|
|
89
89
|
deprecated?: boolean | undefined;
|
|
90
90
|
translations?: Record<string, string | Record<string, string>> | undefined;
|
|
@@ -118,9 +118,11 @@ export declare const formatQuestionType: (type: QuestionType, i18n: i18n) => {
|
|
|
118
118
|
settings?: Record<string, string | number | boolean | any[] | Record<string, any>> | undefined;
|
|
119
119
|
} | undefined;
|
|
120
120
|
} | undefined;
|
|
121
|
-
metadata?: Record<string,
|
|
121
|
+
metadata?: Record<string, import("zod").JSONType> | undefined;
|
|
122
122
|
readme?: string | undefined;
|
|
123
|
+
readmeUrls?: Record<string, string> | undefined;
|
|
123
124
|
previewImage?: string | undefined;
|
|
125
|
+
previewImageUrls?: Record<string, string> | undefined;
|
|
124
126
|
previewData?: string | undefined;
|
|
125
127
|
stylesheet?: string | undefined;
|
|
126
128
|
index?: number | undefined;
|
|
@@ -30,7 +30,6 @@ export type FrontendBaseComponentProps = {
|
|
|
30
30
|
t: (key: string | string[], options?: any) => string;
|
|
31
31
|
api: PublicApiInstance;
|
|
32
32
|
i18n: any;
|
|
33
|
-
environment: FrontendComponentEnvironment;
|
|
34
33
|
};
|
|
35
34
|
export type FrontendAssessmentComponent = ComponentType<FrontendBaseComponentProps & {
|
|
36
35
|
question: any;
|
|
@@ -39,16 +38,19 @@ export type FrontendAssessmentComponent = ComponentType<FrontendBaseComponentPro
|
|
|
39
38
|
reviewMode?: boolean;
|
|
40
39
|
answer?: Answer;
|
|
41
40
|
saveAnswer: (answer: Answer) => Promise<void>;
|
|
41
|
+
environment: FrontendComponentEnvironment;
|
|
42
42
|
}>;
|
|
43
43
|
export type FrontendPrintComponent = ComponentType<FrontendBaseComponentProps & {
|
|
44
44
|
question: any;
|
|
45
45
|
answerBoxes: boolean;
|
|
46
46
|
api: OrgApiInstance;
|
|
47
|
+
environment: FrontendComponentEnvironment;
|
|
47
48
|
}>;
|
|
48
49
|
export type FrontendResultsComponent = ComponentType<FrontendBaseComponentProps & {
|
|
49
50
|
question: any;
|
|
50
51
|
answer: Answer;
|
|
51
52
|
api: OrgApiInstance;
|
|
53
|
+
environment: FrontendComponentEnvironment;
|
|
52
54
|
}>;
|
|
53
55
|
export type FrontendQuestionSettingsAreaComponent = ComponentType<FrontendBaseComponentProps & {
|
|
54
56
|
question: any;
|
|
@@ -56,5 +58,42 @@ export type FrontendQuestionSettingsAreaComponent = ComponentType<FrontendBaseCo
|
|
|
56
58
|
api: OrgApiInstance;
|
|
57
59
|
setSetting: (settingId: string, value: any) => void;
|
|
58
60
|
setMultipleSettings: (newSettings: Record<string, any>) => void;
|
|
61
|
+
environment: FrontendComponentEnvironment;
|
|
62
|
+
}>;
|
|
63
|
+
export type FrontendSettingsFieldComponent = ComponentType<FrontendBaseComponentProps & {
|
|
64
|
+
setValue: (field: string, value: any) => void;
|
|
65
|
+
submit: () => Promise<any>;
|
|
66
|
+
}>;
|
|
67
|
+
type PrerequisiteComponentProps = FrontendBaseComponentProps & {
|
|
68
|
+
/** The prerequisite's settings for this exam */
|
|
69
|
+
settings: Record<string, any>;
|
|
70
|
+
/** The app's icon */
|
|
71
|
+
icon?: string;
|
|
72
|
+
/** Runs one of the prerequisite's functions on the server, returning its result */
|
|
73
|
+
callFunction: (name: string, input?: unknown) => Promise<any>;
|
|
74
|
+
};
|
|
75
|
+
/** Shown in the exam settings once an app's prerequisite is turned on. */
|
|
76
|
+
export type FrontendPrerequisiteSettingsComponent = ComponentType<PrerequisiteComponentProps & {
|
|
77
|
+
exam: {
|
|
78
|
+
id: string;
|
|
79
|
+
published: boolean;
|
|
80
|
+
startDateTime?: string;
|
|
81
|
+
endDateTime?: string;
|
|
82
|
+
};
|
|
83
|
+
}>;
|
|
84
|
+
/** Shown to students while an app's prerequisite isn't met. */
|
|
85
|
+
export type FrontendPrerequisitePlayerComponent = ComponentType<PrerequisiteComponentProps & {
|
|
86
|
+
exam: {
|
|
87
|
+
id: string;
|
|
88
|
+
privateUrl: string;
|
|
89
|
+
};
|
|
90
|
+
user: {
|
|
91
|
+
isAuthenticated: boolean;
|
|
92
|
+
role?: string;
|
|
93
|
+
};
|
|
94
|
+
/** Passes a value to the prerequisite's `isMet` and lets the student start */
|
|
95
|
+
setValue: (value: string) => void;
|
|
96
|
+
/** The public URL of one of the prerequisite's files */
|
|
97
|
+
fileUrl: (name: string) => string;
|
|
59
98
|
}>;
|
|
60
99
|
export {};
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@examplary/ui",
|
|
3
3
|
"description": "UI components for the Examplary testing platform.",
|
|
4
4
|
"packageManager": "yarn@4.5.3",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.85.0",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "dist/index.js",
|
|
8
8
|
"files": [
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"@tiptap/core": "^3.17.1",
|
|
45
45
|
"@tiptap/extension-bold": "^3.11.1",
|
|
46
46
|
"@tiptap/extension-collaboration": "^3.22.2",
|
|
47
|
-
"@tiptap/extension-document": "^3.
|
|
47
|
+
"@tiptap/extension-document": "^3.32.0",
|
|
48
48
|
"@tiptap/extension-file-handler": "^3.11.1",
|
|
49
49
|
"@tiptap/extension-highlight": "^3.19.0",
|
|
50
50
|
"@tiptap/extension-image": "^3.22.5",
|