@pie-players/pie-assessment-toolkit 0.2.7 → 0.2.10
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 +200 -67
- package/dist/attempt/TestSession.d.ts +23 -21
- package/dist/attempt/TestSession.d.ts.map +1 -1
- package/dist/attempt/TestSession.js +17 -15
- package/dist/attempt/TestSession.js.map +1 -1
- package/dist/attempt/adapters/activity-to-test-attempt-session.d.ts +50 -0
- package/dist/attempt/adapters/activity-to-test-attempt-session.d.ts.map +1 -0
- package/dist/attempt/adapters/activity-to-test-attempt-session.js +135 -0
- package/dist/attempt/adapters/activity-to-test-attempt-session.js.map +1 -0
- package/dist/components/ItemToolBar.custom-element.js +953 -0
- package/dist/components/PieAssessmentToolkit.custom-element.js +757 -0
- package/dist/components/SectionToolBar.custom-element.js +162 -0
- package/dist/components/item-toolbar-element.d.ts +3 -0
- package/dist/components/item-toolbar-element.d.ts.map +1 -0
- package/dist/components/item-toolbar-element.js +2 -0
- package/dist/components/item-toolbar-element.js.map +1 -0
- package/dist/components/pie-assessment-toolkit-element.d.ts +3 -0
- package/dist/components/pie-assessment-toolkit-element.d.ts.map +1 -0
- package/dist/components/pie-assessment-toolkit-element.js +2 -0
- package/dist/components/pie-assessment-toolkit-element.js.map +1 -0
- package/dist/components/section-toolbar-element.d.ts +3 -0
- package/dist/components/section-toolbar-element.d.ts.map +1 -0
- package/dist/components/section-toolbar-element.js +2 -0
- package/dist/components/section-toolbar-element.js.map +1 -0
- package/dist/context/assessment-toolkit-context.d.ts +52 -0
- package/dist/context/assessment-toolkit-context.d.ts.map +1 -0
- package/dist/context/assessment-toolkit-context.js +6 -0
- package/dist/context/assessment-toolkit-context.js.map +1 -0
- package/dist/context/runtime-context-consumer.d.ts +14 -0
- package/dist/context/runtime-context-consumer.d.ts.map +1 -0
- package/dist/context/runtime-context-consumer.js +52 -0
- package/dist/context/runtime-context-consumer.js.map +1 -0
- package/dist/index.d.ts +19 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -11
- package/dist/index.js.map +1 -1
- package/dist/runtime/RuntimeRegistry.d.ts +13 -0
- package/dist/runtime/RuntimeRegistry.d.ts.map +1 -0
- package/dist/runtime/RuntimeRegistry.js +50 -0
- package/dist/runtime/RuntimeRegistry.js.map +1 -0
- package/dist/runtime/SectionRuntimeEngine.d.ts +45 -0
- package/dist/runtime/SectionRuntimeEngine.d.ts.map +1 -0
- package/dist/runtime/SectionRuntimeEngine.js +81 -0
- package/dist/runtime/SectionRuntimeEngine.js.map +1 -0
- package/dist/runtime/registration-events.d.ts +19 -0
- package/dist/runtime/registration-events.d.ts.map +1 -0
- package/dist/runtime/registration-events.js +4 -0
- package/dist/runtime/registration-events.js.map +1 -0
- package/dist/runtime/runtime-event-guards.d.ts +3 -0
- package/dist/runtime/runtime-event-guards.d.ts.map +1 -0
- package/dist/runtime/runtime-event-guards.js +9 -0
- package/dist/runtime/runtime-event-guards.js.map +1 -0
- package/dist/runtime/tool-host-contract.d.ts +30 -0
- package/dist/runtime/tool-host-contract.d.ts.map +1 -0
- package/dist/runtime/tool-host-contract.js +48 -0
- package/dist/runtime/tool-host-contract.js.map +1 -0
- package/dist/services/HighlightCoordinator.d.ts +9 -0
- package/dist/services/HighlightCoordinator.d.ts.map +1 -1
- package/dist/services/HighlightCoordinator.js +196 -55
- package/dist/services/HighlightCoordinator.js.map +1 -1
- package/dist/services/TTSService.d.ts +21 -1
- package/dist/services/TTSService.d.ts.map +1 -1
- package/dist/services/TTSService.js +356 -117
- package/dist/services/TTSService.js.map +1 -1
- package/dist/services/ThemeProvider.d.ts +1 -0
- package/dist/services/ThemeProvider.d.ts.map +1 -1
- package/dist/services/ThemeProvider.js +82 -46
- package/dist/services/ThemeProvider.js.map +1 -1
- package/dist/services/ToolConfigResolver.d.ts +1 -1
- package/dist/services/ToolConfigResolver.js +1 -1
- package/dist/services/ToolCoordinator.d.ts +1 -1
- package/dist/services/ToolCoordinator.d.ts.map +1 -1
- package/dist/services/ToolRegistry.d.ts +76 -67
- package/dist/services/ToolRegistry.d.ts.map +1 -1
- package/dist/services/ToolRegistry.js +73 -22
- package/dist/services/ToolRegistry.js.map +1 -1
- package/dist/services/ToolkitCoordinator.d.ts +126 -8
- package/dist/services/ToolkitCoordinator.d.ts.map +1 -1
- package/dist/services/ToolkitCoordinator.js +607 -72
- package/dist/services/ToolkitCoordinator.js.map +1 -1
- package/dist/services/createDefaultToolRegistry.d.ts +11 -12
- package/dist/services/createDefaultToolRegistry.d.ts.map +1 -1
- package/dist/services/createDefaultToolRegistry.js +9 -56
- package/dist/services/createDefaultToolRegistry.js.map +1 -1
- package/dist/services/defaultPersonalNeedsProfile.d.ts +4 -0
- package/dist/services/defaultPersonalNeedsProfile.d.ts.map +1 -0
- package/dist/services/defaultPersonalNeedsProfile.js +25 -0
- package/dist/services/defaultPersonalNeedsProfile.js.map +1 -0
- package/dist/services/interfaces.d.ts +62 -2
- package/dist/services/interfaces.d.ts.map +1 -1
- package/dist/services/interfaces.js.map +1 -1
- package/dist/services/pnp-standard-features.d.ts +3 -4
- package/dist/services/pnp-standard-features.d.ts.map +1 -1
- package/dist/services/pnp-standard-features.js +0 -3
- package/dist/services/pnp-standard-features.js.map +1 -1
- package/dist/services/section-controller-types.d.ts +37 -0
- package/dist/services/section-controller-types.d.ts.map +1 -0
- package/dist/services/section-controller-types.js +2 -0
- package/dist/services/section-controller-types.js.map +1 -0
- package/dist/services/tool-config-defaults.d.ts +14 -0
- package/dist/services/tool-config-defaults.d.ts.map +1 -0
- package/dist/services/tool-config-defaults.js +23 -0
- package/dist/services/tool-config-defaults.js.map +1 -0
- package/dist/services/tool-context.d.ts +4 -4
- package/dist/services/tool-context.d.ts.map +1 -1
- package/dist/services/tool-context.js +156 -20
- package/dist/services/tool-context.js.map +1 -1
- package/dist/services/tool-instance-id.d.ts +15 -0
- package/dist/services/tool-instance-id.d.ts.map +1 -0
- package/dist/services/tool-instance-id.js +55 -0
- package/dist/services/tool-instance-id.js.map +1 -0
- package/dist/services/tool-providers/IToolProvider.d.ts +2 -3
- package/dist/services/tool-providers/IToolProvider.d.ts.map +1 -1
- package/dist/services/tool-providers/IToolProvider.js +1 -2
- package/dist/services/tool-providers/IToolProvider.js.map +1 -1
- package/dist/services/tool-providers/MathJsToolProvider.d.ts +25 -0
- package/dist/services/tool-providers/MathJsToolProvider.d.ts.map +1 -0
- package/dist/services/tool-providers/MathJsToolProvider.js +53 -0
- package/dist/services/tool-providers/MathJsToolProvider.js.map +1 -0
- package/dist/services/tool-providers/index.d.ts +2 -0
- package/dist/services/tool-providers/index.d.ts.map +1 -1
- package/dist/services/tool-providers/index.js +1 -0
- package/dist/services/tool-providers/index.js.map +1 -1
- package/dist/services/toolbar-items.d.ts +26 -0
- package/dist/services/toolbar-items.d.ts.map +1 -0
- package/dist/services/toolbar-items.js +10 -0
- package/dist/services/toolbar-items.js.map +1 -0
- package/dist/services/tools-config-normalizer.d.ts +26 -0
- package/dist/services/tools-config-normalizer.d.ts.map +1 -0
- package/dist/services/tools-config-normalizer.js +62 -0
- package/dist/services/tools-config-normalizer.js.map +1 -0
- package/dist/services/tts/browser-provider.d.ts.map +1 -1
- package/dist/services/tts/browser-provider.js +201 -34
- package/dist/services/tts/browser-provider.js.map +1 -1
- package/dist/services/tts/text-processing.d.ts +17 -0
- package/dist/services/tts/text-processing.d.ts.map +1 -0
- package/dist/services/tts/text-processing.js +144 -0
- package/dist/services/tts/text-processing.js.map +1 -0
- package/dist/tools/calculators/ti-provider.d.ts.map +1 -1
- package/dist/tools/calculators/ti-provider.js +127 -4
- package/dist/tools/calculators/ti-provider.js.map +1 -1
- package/dist/tools/client.d.ts +2 -1
- package/dist/tools/client.d.ts.map +1 -1
- package/dist/tools/client.js +2 -1
- package/dist/tools/client.js.map +1 -1
- package/dist/tools/default-tool-module-loaders.d.ts +9 -0
- package/dist/tools/default-tool-module-loaders.d.ts.map +1 -0
- package/dist/tools/default-tool-module-loaders.js +11 -0
- package/dist/tools/default-tool-module-loaders.js.map +1 -0
- package/dist/tools/index.d.ts +2 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +2 -1
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/library-loader.d.ts +1 -1
- package/dist/tools/library-loader.d.ts.map +1 -1
- package/dist/tools/library-loader.js +7 -2
- package/dist/tools/library-loader.js.map +1 -1
- package/dist/tools/registrations/accessibility-tools.d.ts +8 -11
- package/dist/tools/registrations/accessibility-tools.d.ts.map +1 -1
- package/dist/tools/registrations/accessibility-tools.js +108 -120
- package/dist/tools/registrations/accessibility-tools.js.map +1 -1
- package/dist/tools/registrations/calculator.d.ts +2 -2
- package/dist/tools/registrations/calculator.d.ts.map +1 -1
- package/dist/tools/registrations/calculator.js +42 -55
- package/dist/tools/registrations/calculator.js.map +1 -1
- package/dist/tools/registrations/interaction-tools.d.ts.map +1 -1
- package/dist/tools/registrations/interaction-tools.js +77 -52
- package/dist/tools/registrations/interaction-tools.js.map +1 -1
- package/dist/tools/registrations/measurement-tools.d.ts.map +1 -1
- package/dist/tools/registrations/measurement-tools.js +63 -38
- package/dist/tools/registrations/measurement-tools.js.map +1 -1
- package/dist/tools/registrations/subject-specific-tools.d.ts.map +1 -1
- package/dist/tools/registrations/subject-specific-tools.js +63 -38
- package/dist/tools/registrations/subject-specific-tools.js.map +1 -1
- package/dist/tools/registrations/tts.d.ts +1 -1
- package/dist/tools/registrations/tts.d.ts.map +1 -1
- package/dist/tools/registrations/tts.js +171 -41
- package/dist/tools/registrations/tts.js.map +1 -1
- package/dist/tools/response-discovery.d.ts +12 -14
- package/dist/tools/response-discovery.d.ts.map +1 -1
- package/dist/tools/response-discovery.js +23 -80
- package/dist/tools/response-discovery.js.map +1 -1
- package/dist/tools/tool-tag-map.d.ts +3 -3
- package/dist/tools/tool-tag-map.d.ts.map +1 -1
- package/dist/tools/tool-tag-map.js +4 -4
- package/dist/tools/tool-tag-map.js.map +1 -1
- package/dist/tools/types.d.ts +3 -1
- package/dist/tools/types.d.ts.map +1 -1
- package/package.json +28 -27
- package/src/README.md +16 -32
- package/src/components/ItemToolBar.svelte +701 -0
- package/src/components/PieAssessmentToolkit.svelte +610 -0
- package/src/components/SectionToolBar.svelte +58 -0
- package/src/components/ToolButton.svelte +11 -11
- package/src/components/ToolButtonGroup.svelte +27 -11
- package/src/tools/README.md +6 -5
- package/src/tools/calculators/README.md +4 -4
- package/dist/player/AssessmentPlayer.d.ts +0 -397
- package/dist/player/AssessmentPlayer.d.ts.map +0 -1
- package/dist/player/AssessmentPlayer.js +0 -974
- package/dist/player/AssessmentPlayer.js.map +0 -1
- package/dist/player/index.d.ts +0 -17
- package/dist/player/index.d.ts.map +0 -1
- package/dist/player/index.js +0 -15
- package/dist/player/index.js.map +0 -1
- package/dist/player/navigation-types.d.ts +0 -63
- package/dist/player/navigation-types.d.ts.map +0 -1
- package/dist/player/navigation-types.js +0 -7
- package/dist/player/navigation-types.js.map +0 -1
- package/dist/player/qti-navigation.d.ts +0 -29
- package/dist/player/qti-navigation.d.ts.map +0 -1
- package/dist/player/qti-navigation.js +0 -160
- package/dist/player/qti-navigation.js.map +0 -1
- package/dist/reference-layout/index.d.ts +0 -19
- package/dist/reference-layout/index.d.ts.map +0 -1
- package/dist/reference-layout/index.js +0 -20
- package/dist/reference-layout/index.js.map +0 -1
- package/dist/services/AnnotationToolbarConfig.d.ts +0 -134
- package/dist/services/AnnotationToolbarConfig.d.ts.map +0 -1
- package/dist/services/AnnotationToolbarConfig.js +0 -100
- package/dist/services/AnnotationToolbarConfig.js.map +0 -1
- package/dist/services/AssessmentAuthoringService.d.ts +0 -60
- package/dist/services/AssessmentAuthoringService.d.ts.map +0 -1
- package/dist/services/AssessmentAuthoringService.js +0 -183
- package/dist/services/AssessmentAuthoringService.js.map +0 -1
- package/dist/services/PNPMapper.d.ts +0 -81
- package/dist/services/PNPMapper.d.ts.map +0 -1
- package/dist/services/PNPMapper.js +0 -108
- package/dist/services/PNPMapper.js.map +0 -1
- package/dist/services/tts/provider-interface.d.ts +0 -131
- package/dist/services/tts/provider-interface.d.ts.map +0 -1
- package/dist/services/tts/provider-interface.js +0 -10
- package/dist/services/tts/provider-interface.js.map +0 -1
- package/src/components/PNPProfileTester.example.svelte +0 -188
- package/src/components/PNPProfileTester.svelte +0 -397
- package/src/components/PNPProvenanceViewer.svelte +0 -260
- package/src/components/QuestionToolBar.svelte +0 -483
- package/src/player/AssessmentLayout.svelte +0 -68
- package/src/player/README.md +0 -154
- package/src/reference-layout/README.md +0 -135
- package/src/reference-layout/ReferenceLayout.svelte +0 -201
- package/src/reference-layout/components/AssessmentContent.svelte +0 -259
- package/src/reference-layout/components/AssessmentFooter.svelte +0 -89
- package/src/reference-layout/components/AssessmentHeader.svelte +0 -250
- package/src/reference-layout/components/AssessmentNavigation.svelte +0 -134
- package/src/reference-layout/components/AssessmentToolsBar.svelte +0 -176
- package/src/reference-layout/components/ItemPanel.svelte +0 -200
- package/src/reference-layout/components/NotesPanel.svelte +0 -179
- package/src/reference-layout/components/PassagePanel.svelte +0 -76
|
@@ -1,397 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
// PNP Profile Tester Component
|
|
3
|
-
// Development and testing tool for overriding PNP profiles in real-time.
|
|
4
|
-
// See PNP_TESTING.md for usage documentation.
|
|
5
|
-
import type { PersonalNeedsProfile } from '@pie-players/pie-players-shared/types';
|
|
6
|
-
import {
|
|
7
|
-
EXAMPLE_PNP_CONFIGURATIONS,
|
|
8
|
-
QTI_STANDARD_ACCESS_FEATURES,
|
|
9
|
-
getFeatureCategory,
|
|
10
|
-
} from '@pie-players/pie-assessment-toolkit/services/pnp-standard-features';
|
|
11
|
-
|
|
12
|
-
interface Props {
|
|
13
|
-
/** Callback when profile changes */
|
|
14
|
-
onProfileChange?: (profile: PersonalNeedsProfile | null) => void;
|
|
15
|
-
/** Initial profile (optional) */
|
|
16
|
-
initialProfile?: PersonalNeedsProfile | null;
|
|
17
|
-
/** Show compact view */
|
|
18
|
-
compact?: boolean;
|
|
19
|
-
/** Allow custom feature entry */
|
|
20
|
-
allowCustomFeatures?: boolean;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
let {
|
|
24
|
-
onProfileChange = () => {},
|
|
25
|
-
initialProfile = null,
|
|
26
|
-
compact = false,
|
|
27
|
-
allowCustomFeatures = true
|
|
28
|
-
}: Props = $props();
|
|
29
|
-
|
|
30
|
-
// Default profile with all tools enabled
|
|
31
|
-
const DEFAULT_ALL_TOOLS_PROFILE = [
|
|
32
|
-
'calculator',
|
|
33
|
-
'calculatorScientific',
|
|
34
|
-
'calculatorGraphing',
|
|
35
|
-
'graphingTool',
|
|
36
|
-
'periodicTable',
|
|
37
|
-
'protractor',
|
|
38
|
-
'ruler',
|
|
39
|
-
'readingGuide',
|
|
40
|
-
'magnification',
|
|
41
|
-
'screenMagnifier',
|
|
42
|
-
'textToSpeech',
|
|
43
|
-
'answerEliminator'
|
|
44
|
-
];
|
|
45
|
-
|
|
46
|
-
// Current state - initialize with default profile if no initialProfile provided
|
|
47
|
-
let activeFeatures = $state<Set<string>>(
|
|
48
|
-
new Set(initialProfile?.supports || DEFAULT_ALL_TOOLS_PROFILE),
|
|
49
|
-
);
|
|
50
|
-
let selectedPreset = $state<string | null>(initialProfile ? null : 'default');
|
|
51
|
-
let customFeature = $state('');
|
|
52
|
-
let showCategoryFilter = $state<string | null>(null);
|
|
53
|
-
let searchQuery = $state('');
|
|
54
|
-
let statusMessage = $state('');
|
|
55
|
-
|
|
56
|
-
// Computed profile
|
|
57
|
-
$effect(() => {
|
|
58
|
-
const profile: PersonalNeedsProfile = {
|
|
59
|
-
supports: Array.from(activeFeatures),
|
|
60
|
-
};
|
|
61
|
-
onProfileChange(activeFeatures.size > 0 ? profile : null);
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
// Get all standard features as array
|
|
65
|
-
const allStandardFeatures = Object.entries(QTI_STANDARD_ACCESS_FEATURES).flatMap(
|
|
66
|
-
([category, features]) =>
|
|
67
|
-
Object.entries(features).map(([key, value]) => ({
|
|
68
|
-
id: value,
|
|
69
|
-
name: key,
|
|
70
|
-
category,
|
|
71
|
-
})),
|
|
72
|
-
);
|
|
73
|
-
|
|
74
|
-
// Filter features
|
|
75
|
-
let filteredFeatures = $derived.by(() => {
|
|
76
|
-
let filtered = allStandardFeatures;
|
|
77
|
-
|
|
78
|
-
if (showCategoryFilter) {
|
|
79
|
-
filtered = filtered.filter((f) => f.category === showCategoryFilter);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
if (searchQuery) {
|
|
83
|
-
const query = searchQuery.toLowerCase();
|
|
84
|
-
filtered = filtered.filter(
|
|
85
|
-
(f) =>
|
|
86
|
-
f.id.toLowerCase().includes(query) ||
|
|
87
|
-
f.name.toLowerCase().includes(query),
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
return filtered;
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
function applyPreset(presetKey: string) {
|
|
95
|
-
const preset = EXAMPLE_PNP_CONFIGURATIONS[presetKey as keyof typeof EXAMPLE_PNP_CONFIGURATIONS];
|
|
96
|
-
if (!preset) return;
|
|
97
|
-
|
|
98
|
-
selectedPreset = presetKey;
|
|
99
|
-
// Create a new Set to trigger Svelte 5 reactivity
|
|
100
|
-
activeFeatures = new Set(preset.features);
|
|
101
|
-
statusMessage = `Profile changed to ${preset.label.replace('Example: ', '')}. ${preset.features.length} features enabled.`;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
function toggleFeature(featureId: string) {
|
|
105
|
-
// Create a new Set to trigger Svelte 5 reactivity
|
|
106
|
-
const newFeatures = new Set(activeFeatures);
|
|
107
|
-
const wasEnabled = newFeatures.has(featureId);
|
|
108
|
-
if (wasEnabled) {
|
|
109
|
-
newFeatures.delete(featureId);
|
|
110
|
-
} else {
|
|
111
|
-
newFeatures.add(featureId);
|
|
112
|
-
}
|
|
113
|
-
activeFeatures = newFeatures;
|
|
114
|
-
selectedPreset = null; // Clear preset when manually changing
|
|
115
|
-
statusMessage = `${featureId} ${wasEnabled ? 'disabled' : 'enabled'}. ${activeFeatures.size} features active.`;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function addCustomFeature() {
|
|
119
|
-
if (customFeature.trim()) {
|
|
120
|
-
const newFeatures = new Set(activeFeatures);
|
|
121
|
-
const featureId = customFeature.trim();
|
|
122
|
-
newFeatures.add(featureId);
|
|
123
|
-
activeFeatures = newFeatures;
|
|
124
|
-
customFeature = '';
|
|
125
|
-
selectedPreset = null;
|
|
126
|
-
statusMessage = `Custom feature ${featureId} added. ${activeFeatures.size} features active.`;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
function clearAll() {
|
|
131
|
-
activeFeatures = new Set();
|
|
132
|
-
selectedPreset = null;
|
|
133
|
-
statusMessage = 'All features cleared.';
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
function exportProfile() {
|
|
137
|
-
const profile: PersonalNeedsProfile = {
|
|
138
|
-
supports: Array.from(activeFeatures),
|
|
139
|
-
};
|
|
140
|
-
const json = JSON.stringify(profile, null, 2);
|
|
141
|
-
const blob = new Blob([json], { type: 'application/json' });
|
|
142
|
-
const url = URL.createObjectURL(blob);
|
|
143
|
-
const a = document.createElement('a');
|
|
144
|
-
a.href = url;
|
|
145
|
-
a.download = 'pnp-profile.json';
|
|
146
|
-
a.click();
|
|
147
|
-
URL.revokeObjectURL(url);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
function importProfile(event: Event) {
|
|
151
|
-
const input = event.target as HTMLInputElement;
|
|
152
|
-
const file = input.files?.[0];
|
|
153
|
-
if (!file) return;
|
|
154
|
-
|
|
155
|
-
const reader = new FileReader();
|
|
156
|
-
reader.onload = (e) => {
|
|
157
|
-
try {
|
|
158
|
-
const profile = JSON.parse(e.target?.result as string) as PersonalNeedsProfile;
|
|
159
|
-
if (profile.supports && Array.isArray(profile.supports)) {
|
|
160
|
-
activeFeatures = new Set(profile.supports);
|
|
161
|
-
selectedPreset = null;
|
|
162
|
-
}
|
|
163
|
-
} catch (err) {
|
|
164
|
-
console.error('Failed to import PNP profile:', err);
|
|
165
|
-
}
|
|
166
|
-
};
|
|
167
|
-
reader.readAsText(file);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
const categories = Object.keys(QTI_STANDARD_ACCESS_FEATURES);
|
|
171
|
-
</script>
|
|
172
|
-
|
|
173
|
-
<div class="pnp-profile-tester" class:compact>
|
|
174
|
-
<!-- Header -->
|
|
175
|
-
<div class="flex items-center gap-2 mb-3">
|
|
176
|
-
<h3 class="text-sm font-semibold">PNP Profile Tester</h3>
|
|
177
|
-
<div class="badge badge-neutral badge-sm">
|
|
178
|
-
{activeFeatures.size} feature{activeFeatures.size !== 1 ? 's' : ''}
|
|
179
|
-
</div>
|
|
180
|
-
</div>
|
|
181
|
-
|
|
182
|
-
<!-- Preset Selector and Search Row -->
|
|
183
|
-
<div class="grid grid-cols-1 {compact ? '' : 'md:grid-cols-2'} gap-2 mb-3">
|
|
184
|
-
<!-- Preset Selector -->
|
|
185
|
-
<div class="form-control">
|
|
186
|
-
<label for="preset-selector" class="label label-text text-xs font-semibold py-1">
|
|
187
|
-
Example Profiles
|
|
188
|
-
</label>
|
|
189
|
-
<select
|
|
190
|
-
id="preset-selector"
|
|
191
|
-
class="select select-sm select-bordered w-full"
|
|
192
|
-
value={selectedPreset || ''}
|
|
193
|
-
aria-label="Select an example accessibility profile"
|
|
194
|
-
onchange={(e) => {
|
|
195
|
-
const value = (e.target as HTMLSelectElement).value;
|
|
196
|
-
if (value === 'default') {
|
|
197
|
-
activeFeatures = new Set(DEFAULT_ALL_TOOLS_PROFILE);
|
|
198
|
-
selectedPreset = 'default';
|
|
199
|
-
statusMessage = `Default profile applied. ${activeFeatures.size} features enabled.`;
|
|
200
|
-
} else if (value === '') {
|
|
201
|
-
clearAll();
|
|
202
|
-
} else {
|
|
203
|
-
applyPreset(value);
|
|
204
|
-
}
|
|
205
|
-
}}
|
|
206
|
-
>
|
|
207
|
-
<option value="default">Default - All Tools</option>
|
|
208
|
-
<option value="">None (Clear All)</option>
|
|
209
|
-
<optgroup label="Example Profiles">
|
|
210
|
-
{#each Object.entries(EXAMPLE_PNP_CONFIGURATIONS) as [key, preset]}
|
|
211
|
-
<option value={key}>{preset.label.replace('Example: ', '')}</option>
|
|
212
|
-
{/each}
|
|
213
|
-
</optgroup>
|
|
214
|
-
</select>
|
|
215
|
-
</div>
|
|
216
|
-
|
|
217
|
-
<!-- Search -->
|
|
218
|
-
{#if !compact}
|
|
219
|
-
<div class="form-control">
|
|
220
|
-
<label for="feature-search" class="label label-text text-xs font-semibold py-1">
|
|
221
|
-
Search Features
|
|
222
|
-
</label>
|
|
223
|
-
<input
|
|
224
|
-
id="feature-search"
|
|
225
|
-
type="text"
|
|
226
|
-
placeholder="Search features..."
|
|
227
|
-
class="input input-bordered input-sm w-full"
|
|
228
|
-
bind:value={searchQuery}
|
|
229
|
-
aria-label="Search accessibility features by name or ID"
|
|
230
|
-
/>
|
|
231
|
-
</div>
|
|
232
|
-
{/if}
|
|
233
|
-
</div>
|
|
234
|
-
|
|
235
|
-
<!-- Category Filter -->
|
|
236
|
-
{#if !compact}
|
|
237
|
-
<div class="mb-3">
|
|
238
|
-
<div class="text-xs font-semibold mb-2">Filter by Category</div>
|
|
239
|
-
<div class="flex flex-wrap gap-1">
|
|
240
|
-
<button
|
|
241
|
-
class="btn btn-xs"
|
|
242
|
-
class:btn-primary={showCategoryFilter === null}
|
|
243
|
-
aria-pressed={showCategoryFilter === null}
|
|
244
|
-
onclick={() => (showCategoryFilter = null)}
|
|
245
|
-
>
|
|
246
|
-
All
|
|
247
|
-
</button>
|
|
248
|
-
{#each categories as category}
|
|
249
|
-
<button
|
|
250
|
-
class="btn btn-xs"
|
|
251
|
-
class:btn-primary={showCategoryFilter === category}
|
|
252
|
-
aria-pressed={showCategoryFilter === category}
|
|
253
|
-
onclick={() =>
|
|
254
|
-
(showCategoryFilter = showCategoryFilter === category ? null : category)}
|
|
255
|
-
>
|
|
256
|
-
{category}
|
|
257
|
-
</button>
|
|
258
|
-
{/each}
|
|
259
|
-
</div>
|
|
260
|
-
</div>
|
|
261
|
-
{/if}
|
|
262
|
-
|
|
263
|
-
<!-- Feature Toggles -->
|
|
264
|
-
<div class="border border-base-300 rounded-lg p-3 mb-3 bg-base-100">
|
|
265
|
-
<div class="text-xs font-semibold mb-2">
|
|
266
|
-
Standard Features
|
|
267
|
-
{#if filteredFeatures.length !== allStandardFeatures.length}
|
|
268
|
-
<span class="text-base-content/60 font-normal">
|
|
269
|
-
(showing {filteredFeatures.length} of {allStandardFeatures.length})
|
|
270
|
-
</span>
|
|
271
|
-
{/if}
|
|
272
|
-
</div>
|
|
273
|
-
<div class="max-h-80 overflow-y-auto space-y-0.5 pr-2">
|
|
274
|
-
{#each filteredFeatures as feature}
|
|
275
|
-
<label class="flex items-center gap-2 cursor-pointer hover:bg-base-200 p-2 rounded transition-colors">
|
|
276
|
-
<input
|
|
277
|
-
type="checkbox"
|
|
278
|
-
class="checkbox checkbox-sm"
|
|
279
|
-
checked={activeFeatures.has(feature.id)}
|
|
280
|
-
onchange={() => toggleFeature(feature.id)}
|
|
281
|
-
/>
|
|
282
|
-
<span class="text-sm flex-1">{feature.name}</span>
|
|
283
|
-
{#if !compact}
|
|
284
|
-
<span class="badge badge-xs badge-ghost">{feature.category}</span>
|
|
285
|
-
{/if}
|
|
286
|
-
</label>
|
|
287
|
-
{/each}
|
|
288
|
-
{#if filteredFeatures.length === 0}
|
|
289
|
-
<div class="text-center text-sm text-base-content/60 py-4">
|
|
290
|
-
No features match your search
|
|
291
|
-
</div>
|
|
292
|
-
{/if}
|
|
293
|
-
</div>
|
|
294
|
-
</div>
|
|
295
|
-
|
|
296
|
-
<!-- Custom Features -->
|
|
297
|
-
{#if allowCustomFeatures}
|
|
298
|
-
<div class="border border-base-300 rounded-lg p-3 mb-3 bg-base-100">
|
|
299
|
-
<div class="text-xs font-semibold mb-2">Custom Features</div>
|
|
300
|
-
<div class="flex gap-2 mb-2">
|
|
301
|
-
<label for="custom-feature-input" class="sr-only">Custom feature ID</label>
|
|
302
|
-
<input
|
|
303
|
-
id="custom-feature-input"
|
|
304
|
-
type="text"
|
|
305
|
-
placeholder="e.g., ext:custom-feature"
|
|
306
|
-
class="input input-bordered input-sm flex-1"
|
|
307
|
-
bind:value={customFeature}
|
|
308
|
-
aria-label="Enter custom feature ID"
|
|
309
|
-
onkeydown={(e) => e.key === 'Enter' && addCustomFeature()}
|
|
310
|
-
/>
|
|
311
|
-
<button class="btn btn-sm btn-primary" onclick={addCustomFeature}> Add </button>
|
|
312
|
-
</div>
|
|
313
|
-
|
|
314
|
-
{#if Array.from(activeFeatures).some((f) => !allStandardFeatures.find((sf) => sf.id === f))}
|
|
315
|
-
<div class="space-y-1 mt-2">
|
|
316
|
-
{#each Array.from(activeFeatures).filter((f) => !allStandardFeatures.find((sf) => sf.id === f)) as feature}
|
|
317
|
-
<div
|
|
318
|
-
class="flex items-center gap-2 text-sm bg-warning/10 p-2 rounded border border-warning/20"
|
|
319
|
-
>
|
|
320
|
-
<span class="flex-1 font-mono text-xs">{feature}</span>
|
|
321
|
-
<button
|
|
322
|
-
class="btn btn-xs btn-circle btn-ghost"
|
|
323
|
-
onclick={() => toggleFeature(feature)}
|
|
324
|
-
aria-label="Remove custom feature {feature}"
|
|
325
|
-
>
|
|
326
|
-
✕
|
|
327
|
-
</button>
|
|
328
|
-
</div>
|
|
329
|
-
{/each}
|
|
330
|
-
</div>
|
|
331
|
-
{:else}
|
|
332
|
-
<div class="text-xs text-base-content/60 mt-2">
|
|
333
|
-
Add non-standard QTI features for testing
|
|
334
|
-
</div>
|
|
335
|
-
{/if}
|
|
336
|
-
</div>
|
|
337
|
-
{/if}
|
|
338
|
-
|
|
339
|
-
<!-- Active Features Summary -->
|
|
340
|
-
{#if !compact && activeFeatures.size > 0}
|
|
341
|
-
<details class="mt-3">
|
|
342
|
-
<summary class="cursor-pointer text-xs font-semibold text-base-content/70">
|
|
343
|
-
Active Features ({activeFeatures.size})
|
|
344
|
-
</summary>
|
|
345
|
-
<div class="mt-2 p-2 bg-base-200 rounded text-xs">
|
|
346
|
-
<code class="whitespace-pre-wrap">
|
|
347
|
-
{JSON.stringify({ supports: Array.from(activeFeatures) }, null, 2)}
|
|
348
|
-
</code>
|
|
349
|
-
</div>
|
|
350
|
-
</details>
|
|
351
|
-
{/if}
|
|
352
|
-
|
|
353
|
-
<!-- Live region for status announcements -->
|
|
354
|
-
<div role="status" aria-live="polite" aria-atomic="true" class="sr-only">
|
|
355
|
-
{statusMessage}
|
|
356
|
-
</div>
|
|
357
|
-
</div>
|
|
358
|
-
|
|
359
|
-
<style>
|
|
360
|
-
.pnp-profile-tester {
|
|
361
|
-
font-family: system-ui, -apple-system, sans-serif;
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
.pnp-profile-tester.compact {
|
|
365
|
-
font-size: 0.875rem;
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
/* Custom scrollbar for feature list */
|
|
369
|
-
.pnp-profile-tester .max-h-80::-webkit-scrollbar {
|
|
370
|
-
width: 8px;
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
.pnp-profile-tester .max-h-80::-webkit-scrollbar-track {
|
|
374
|
-
background: transparent;
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
.pnp-profile-tester .max-h-80::-webkit-scrollbar-thumb {
|
|
378
|
-
background: hsl(var(--bc) / 0.2);
|
|
379
|
-
border-radius: 4px;
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
.pnp-profile-tester .max-h-80::-webkit-scrollbar-thumb:hover {
|
|
383
|
-
background: hsl(var(--bc) / 0.3);
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
/* Firefox scrollbar */
|
|
387
|
-
.pnp-profile-tester .max-h-80 {
|
|
388
|
-
scrollbar-width: thin;
|
|
389
|
-
scrollbar-color: hsl(var(--bc) / 0.2) transparent;
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
/* Improve form control spacing */
|
|
393
|
-
.pnp-profile-tester .form-control .label {
|
|
394
|
-
padding-top: 0.25rem;
|
|
395
|
-
padding-bottom: 0.25rem;
|
|
396
|
-
}
|
|
397
|
-
</style>
|
|
@@ -1,260 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import type { PNPResolutionProvenance } from '@pie-players/pie-assessment-toolkit/services/pnp-provenance';
|
|
3
|
-
|
|
4
|
-
// PNP Provenance Viewer Component
|
|
5
|
-
// Visualizes how PNP resolution decisions were made.
|
|
6
|
-
// See PNP_TESTING.md for usage documentation.
|
|
7
|
-
|
|
8
|
-
interface Props {
|
|
9
|
-
provenance: PNPResolutionProvenance;
|
|
10
|
-
compact?: boolean;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
let { provenance, compact = false }: Props = $props();
|
|
14
|
-
|
|
15
|
-
let features = $derived(Array.from(provenance.features.values()));
|
|
16
|
-
let enabledFeatures = $derived(features.filter((f) => f.finalState === 'enabled'));
|
|
17
|
-
let blockedFeatures = $derived(features.filter((f) => f.finalState === 'blocked'));
|
|
18
|
-
|
|
19
|
-
function getRuleBadgeClass(rule: string): string {
|
|
20
|
-
const classes: Record<string, string> = {
|
|
21
|
-
'district-block': 'badge-error',
|
|
22
|
-
'test-admin-override': 'badge-warning',
|
|
23
|
-
'item-restriction': 'badge-info',
|
|
24
|
-
'item-requirement': 'badge-success',
|
|
25
|
-
'district-requirement': 'badge-success',
|
|
26
|
-
'pnp-support': 'badge-primary',
|
|
27
|
-
'system-default': 'badge-ghost'
|
|
28
|
-
};
|
|
29
|
-
return classes[rule] || 'badge-ghost';
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function getActionIcon(action: string): string {
|
|
33
|
-
const icons: Record<string, string> = {
|
|
34
|
-
enable: '✓',
|
|
35
|
-
block: '✗',
|
|
36
|
-
skip: '○'
|
|
37
|
-
};
|
|
38
|
-
return icons[action] || '?';
|
|
39
|
-
}
|
|
40
|
-
</script>
|
|
41
|
-
|
|
42
|
-
<div class="pnp-provenance-viewer" class:compact>
|
|
43
|
-
<!-- Summary -->
|
|
44
|
-
<div class="card bg-base-100 shadow-sm mb-4">
|
|
45
|
-
<div class="card-body">
|
|
46
|
-
<h3 class="card-title text-sm">Resolution Summary</h3>
|
|
47
|
-
<div class="stats stats-vertical lg:stats-horizontal shadow">
|
|
48
|
-
<div class="stat">
|
|
49
|
-
<div class="stat-title">Total Features</div>
|
|
50
|
-
<div class="stat-value text-2xl">{provenance.summary.totalFeatures}</div>
|
|
51
|
-
</div>
|
|
52
|
-
<div class="stat">
|
|
53
|
-
<div class="stat-title">Enabled</div>
|
|
54
|
-
<div class="stat-value text-2xl text-success">{provenance.summary.enabled}</div>
|
|
55
|
-
</div>
|
|
56
|
-
<div class="stat">
|
|
57
|
-
<div class="stat-title">Blocked</div>
|
|
58
|
-
<div class="stat-value text-2xl text-error">{provenance.summary.blocked}</div>
|
|
59
|
-
</div>
|
|
60
|
-
</div>
|
|
61
|
-
|
|
62
|
-
<div class="text-xs text-base-content/70 mt-2">
|
|
63
|
-
Resolved at: {provenance.resolvedAt.toLocaleString()}
|
|
64
|
-
</div>
|
|
65
|
-
</div>
|
|
66
|
-
</div>
|
|
67
|
-
|
|
68
|
-
<!-- Configuration Sources -->
|
|
69
|
-
{#if !compact}
|
|
70
|
-
<div class="card bg-base-100 shadow-sm mb-4">
|
|
71
|
-
<div class="card-body">
|
|
72
|
-
<h3 class="card-title text-sm">Configuration Sources</h3>
|
|
73
|
-
<div class="space-y-2">
|
|
74
|
-
{#each Object.entries(provenance.sources) as [type, source]}
|
|
75
|
-
<div class="flex items-center gap-2">
|
|
76
|
-
<div class="badge badge-outline">{type}</div>
|
|
77
|
-
<div class="text-sm">
|
|
78
|
-
{source.name || source.id}
|
|
79
|
-
<span class="text-xs text-base-content/50">({source.id})</span>
|
|
80
|
-
</div>
|
|
81
|
-
</div>
|
|
82
|
-
{/each}
|
|
83
|
-
</div>
|
|
84
|
-
</div>
|
|
85
|
-
</div>
|
|
86
|
-
{/if}
|
|
87
|
-
|
|
88
|
-
<!-- Feature Resolution -->
|
|
89
|
-
<div class="space-y-4">
|
|
90
|
-
<!-- Enabled Features -->
|
|
91
|
-
{#if enabledFeatures.length > 0}
|
|
92
|
-
<div class="card bg-base-100 shadow-sm">
|
|
93
|
-
<div class="card-body">
|
|
94
|
-
<h3 class="card-title text-sm text-success">
|
|
95
|
-
Enabled Features ({enabledFeatures.length})
|
|
96
|
-
</h3>
|
|
97
|
-
<div class="space-y-3">
|
|
98
|
-
{#each enabledFeatures as feature}
|
|
99
|
-
<div class="border-l-4 border-success pl-3">
|
|
100
|
-
<div class="flex items-center gap-2 mb-1">
|
|
101
|
-
<code class="text-sm font-semibold">{feature.featureId}</code>
|
|
102
|
-
{#if feature.winningDecision}
|
|
103
|
-
<div class="badge {getRuleBadgeClass(feature.winningDecision.rule)} badge-sm">
|
|
104
|
-
{feature.winningDecision.rule}
|
|
105
|
-
</div>
|
|
106
|
-
{/if}
|
|
107
|
-
</div>
|
|
108
|
-
|
|
109
|
-
{#if !compact}
|
|
110
|
-
<div class="text-sm text-base-content/80 whitespace-pre-wrap">
|
|
111
|
-
{feature.explanation}
|
|
112
|
-
</div>
|
|
113
|
-
{:else if feature.winningDecision}
|
|
114
|
-
<div class="text-xs text-base-content/70">
|
|
115
|
-
{feature.winningDecision.reason}
|
|
116
|
-
</div>
|
|
117
|
-
{/if}
|
|
118
|
-
|
|
119
|
-
{#if !compact && feature.allDecisions.length > 1}
|
|
120
|
-
<details class="mt-2">
|
|
121
|
-
<summary class="text-xs cursor-pointer text-base-content/60 hover:text-base-content">
|
|
122
|
-
Show all decisions ({feature.allDecisions.length})
|
|
123
|
-
</summary>
|
|
124
|
-
<div class="ml-4 mt-2 space-y-1">
|
|
125
|
-
{#each feature.allDecisions as decision}
|
|
126
|
-
<div class="text-xs flex items-center gap-2">
|
|
127
|
-
<span class="opacity-50">{decision.step}.</span>
|
|
128
|
-
<span class="badge badge-xs {getRuleBadgeClass(decision.rule)}">
|
|
129
|
-
{decision.rule}
|
|
130
|
-
</span>
|
|
131
|
-
<span>{getActionIcon(decision.action)}</span>
|
|
132
|
-
<span class="opacity-70">{decision.reason}</span>
|
|
133
|
-
</div>
|
|
134
|
-
{/each}
|
|
135
|
-
</div>
|
|
136
|
-
</details>
|
|
137
|
-
{/if}
|
|
138
|
-
</div>
|
|
139
|
-
{/each}
|
|
140
|
-
</div>
|
|
141
|
-
</div>
|
|
142
|
-
</div>
|
|
143
|
-
{/if}
|
|
144
|
-
|
|
145
|
-
<!-- Blocked Features -->
|
|
146
|
-
{#if blockedFeatures.length > 0}
|
|
147
|
-
<div class="card bg-base-100 shadow-sm">
|
|
148
|
-
<div class="card-body">
|
|
149
|
-
<h3 class="card-title text-sm text-error">
|
|
150
|
-
Blocked Features ({blockedFeatures.length})
|
|
151
|
-
</h3>
|
|
152
|
-
<div class="space-y-3">
|
|
153
|
-
{#each blockedFeatures as feature}
|
|
154
|
-
<div class="border-l-4 border-error pl-3">
|
|
155
|
-
<div class="flex items-center gap-2 mb-1">
|
|
156
|
-
<code class="text-sm font-semibold">{feature.featureId}</code>
|
|
157
|
-
{#if feature.winningDecision}
|
|
158
|
-
<div class="badge {getRuleBadgeClass(feature.winningDecision.rule)} badge-sm">
|
|
159
|
-
{feature.winningDecision.rule}
|
|
160
|
-
</div>
|
|
161
|
-
{/if}
|
|
162
|
-
</div>
|
|
163
|
-
|
|
164
|
-
{#if !compact}
|
|
165
|
-
<div class="text-sm text-base-content/80 whitespace-pre-wrap">
|
|
166
|
-
{feature.explanation}
|
|
167
|
-
</div>
|
|
168
|
-
{:else if feature.winningDecision}
|
|
169
|
-
<div class="text-xs text-base-content/70">
|
|
170
|
-
{feature.winningDecision.reason}
|
|
171
|
-
</div>
|
|
172
|
-
{/if}
|
|
173
|
-
|
|
174
|
-
{#if !compact && feature.allDecisions.length > 1}
|
|
175
|
-
<details class="mt-2">
|
|
176
|
-
<summary class="text-xs cursor-pointer text-base-content/60 hover:text-base-content">
|
|
177
|
-
Show all decisions ({feature.allDecisions.length})
|
|
178
|
-
</summary>
|
|
179
|
-
<div class="ml-4 mt-2 space-y-1">
|
|
180
|
-
{#each feature.allDecisions as decision}
|
|
181
|
-
<div class="text-xs flex items-center gap-2">
|
|
182
|
-
<span class="opacity-50">{decision.step}.</span>
|
|
183
|
-
<span class="badge badge-xs {getRuleBadgeClass(decision.rule)}">
|
|
184
|
-
{decision.rule}
|
|
185
|
-
</span>
|
|
186
|
-
<span>{getActionIcon(decision.action)}</span>
|
|
187
|
-
<span class="opacity-70">{decision.reason}</span>
|
|
188
|
-
</div>
|
|
189
|
-
{/each}
|
|
190
|
-
</div>
|
|
191
|
-
</details>
|
|
192
|
-
{/if}
|
|
193
|
-
</div>
|
|
194
|
-
{/each}
|
|
195
|
-
</div>
|
|
196
|
-
</div>
|
|
197
|
-
</div>
|
|
198
|
-
{/if}
|
|
199
|
-
</div>
|
|
200
|
-
|
|
201
|
-
<!-- Decision Log (collapsed by default) -->
|
|
202
|
-
{#if !compact && provenance.decisionLog.length > 0}
|
|
203
|
-
<details class="mt-4">
|
|
204
|
-
<summary class="cursor-pointer text-sm font-semibold text-base-content/80 hover:text-base-content">
|
|
205
|
-
Complete Decision Log ({provenance.decisionLog.length} steps)
|
|
206
|
-
</summary>
|
|
207
|
-
<div class="card bg-base-100 shadow-sm mt-2">
|
|
208
|
-
<div class="card-body">
|
|
209
|
-
<div class="space-y-2">
|
|
210
|
-
{#each provenance.decisionLog as decision}
|
|
211
|
-
<div class="flex items-start gap-3 text-xs">
|
|
212
|
-
<div class="font-mono text-base-content/50 w-8">
|
|
213
|
-
{decision.step}.
|
|
214
|
-
</div>
|
|
215
|
-
<div class="flex-1">
|
|
216
|
-
<div class="flex items-center gap-2 mb-1">
|
|
217
|
-
<span class="badge {getRuleBadgeClass(decision.rule)} badge-sm">
|
|
218
|
-
{decision.rule}
|
|
219
|
-
</span>
|
|
220
|
-
<span class="font-semibold">{decision.featureId}</span>
|
|
221
|
-
<span class={decision.action === 'enable' ? 'text-success' : decision.action === 'block' ? 'text-error' : 'text-base-content/50'}>
|
|
222
|
-
{getActionIcon(decision.action)} {decision.action}
|
|
223
|
-
</span>
|
|
224
|
-
</div>
|
|
225
|
-
<div class="text-base-content/70">
|
|
226
|
-
{decision.reason}
|
|
227
|
-
</div>
|
|
228
|
-
<div class="text-base-content/50 mt-1">
|
|
229
|
-
Source: {decision.source.name || decision.source.type}
|
|
230
|
-
</div>
|
|
231
|
-
</div>
|
|
232
|
-
</div>
|
|
233
|
-
{/each}
|
|
234
|
-
</div>
|
|
235
|
-
</div>
|
|
236
|
-
</div>
|
|
237
|
-
</details>
|
|
238
|
-
{/if}
|
|
239
|
-
</div>
|
|
240
|
-
|
|
241
|
-
<style>
|
|
242
|
-
.pnp-provenance-viewer {
|
|
243
|
-
font-family: system-ui, -apple-system, sans-serif;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
.pnp-provenance-viewer code {
|
|
247
|
-
background-color: hsl(var(--b2));
|
|
248
|
-
padding: 0.125rem 0.375rem;
|
|
249
|
-
border-radius: 0.25rem;
|
|
250
|
-
font-size: 0.875em;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
.pnp-provenance-viewer.compact {
|
|
254
|
-
font-size: 0.875rem;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
.pnp-provenance-viewer.compact .card-body {
|
|
258
|
-
padding: 1rem;
|
|
259
|
-
}
|
|
260
|
-
</style>
|