@instructure/platform-widget-dashboard 0.1.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 +365 -0
- package/dist/components/CoursesTab.canvas.d.ts +5 -0
- package/dist/components/CoursesTab.canvas.d.ts.map +1 -0
- package/dist/components/CoursesTabWrapper.d.ts +5 -0
- package/dist/components/CoursesTabWrapper.d.ts.map +1 -0
- package/dist/components/DashboardNotifications.d.ts +5 -0
- package/dist/components/DashboardNotifications.d.ts.map +1 -0
- package/dist/components/DashboardTab.d.ts +5 -0
- package/dist/components/DashboardTab.d.ts.map +1 -0
- package/dist/components/DashboardTabs.d.ts +5 -0
- package/dist/components/DashboardTabs.d.ts.map +1 -0
- package/dist/components/EnrollmentInvitation.d.ts +22 -0
- package/dist/components/EnrollmentInvitation.d.ts.map +1 -0
- package/dist/components/FeedbackQuestionTile.d.ts +5 -0
- package/dist/components/FeedbackQuestionTile.d.ts.map +1 -0
- package/dist/components/NotificationAlert.d.ts +19 -0
- package/dist/components/NotificationAlert.d.ts.map +1 -0
- package/dist/components/WidgetDashboardContainer.d.ts +5 -0
- package/dist/components/WidgetDashboardContainer.d.ts.map +1 -0
- package/dist/components/WidgetGrid.d.ts +10 -0
- package/dist/components/WidgetGrid.d.ts.map +1 -0
- package/dist/components/WidgetRenderer.d.ts +8 -0
- package/dist/components/WidgetRenderer.d.ts.map +1 -0
- package/dist/components/shared/CourseCode.d.ts +18 -0
- package/dist/components/shared/CourseCode.d.ts.map +1 -0
- package/dist/components/shared/CourseFilterSelect.d.ts +14 -0
- package/dist/components/shared/CourseFilterSelect.d.ts.map +1 -0
- package/dist/components/shared/CourseName.d.ts +9 -0
- package/dist/components/shared/CourseName.d.ts.map +1 -0
- package/dist/components/shared/CourseWorkFilters.d.ts +23 -0
- package/dist/components/shared/CourseWorkFilters.d.ts.map +1 -0
- package/dist/components/shared/StatisticsCard.d.ts +10 -0
- package/dist/components/shared/StatisticsCard.d.ts.map +1 -0
- package/dist/components/shared/StatisticsCardsGrid.d.ts +14 -0
- package/dist/components/shared/StatisticsCardsGrid.d.ts.map +1 -0
- package/dist/components/shared/WidgetContextMenu.d.ts +12 -0
- package/dist/components/shared/WidgetContextMenu.d.ts.map +1 -0
- package/dist/components/widgets/AnnouncementsWidget/AnnouncementItem.d.ts +11 -0
- package/dist/components/widgets/AnnouncementsWidget/AnnouncementItem.d.ts.map +1 -0
- package/dist/components/widgets/AnnouncementsWidget/AnnouncementsWidget.d.ts +6 -0
- package/dist/components/widgets/AnnouncementsWidget/AnnouncementsWidget.d.ts.map +1 -0
- package/dist/components/widgets/AnnouncementsWidget/utils.d.ts +2 -0
- package/dist/components/widgets/AnnouncementsWidget/utils.d.ts.map +1 -0
- package/dist/components/widgets/CourseGradesWidget/CourseGradeCard.d.ts +6 -0
- package/dist/components/widgets/CourseGradesWidget/CourseGradeCard.d.ts.map +1 -0
- package/dist/components/widgets/CourseGradesWidget/CourseGradesWidget.d.ts +6 -0
- package/dist/components/widgets/CourseGradesWidget/CourseGradesWidget.d.ts.map +1 -0
- package/dist/components/widgets/CourseWorkSummaryWidget/CourseWorkSummaryWidget.d.ts +6 -0
- package/dist/components/widgets/CourseWorkSummaryWidget/CourseWorkSummaryWidget.d.ts.map +1 -0
- package/dist/components/widgets/CourseWorkSummaryWidget/index.d.ts +2 -0
- package/dist/components/widgets/CourseWorkSummaryWidget/index.d.ts.map +1 -0
- package/dist/components/widgets/CourseWorkWidget/CourseWorkWidget.d.ts +6 -0
- package/dist/components/widgets/CourseWorkWidget/CourseWorkWidget.d.ts.map +1 -0
- package/dist/components/widgets/CourseWorkWidget/utils.d.ts +15 -0
- package/dist/components/widgets/CourseWorkWidget/utils.d.ts.map +1 -0
- package/dist/components/widgets/InboxWidget/InboxWidget.d.ts +6 -0
- package/dist/components/widgets/InboxWidget/InboxWidget.d.ts.map +1 -0
- package/dist/components/widgets/InboxWidget/MessageItem.d.ts +9 -0
- package/dist/components/widgets/InboxWidget/MessageItem.d.ts.map +1 -0
- package/dist/components/widgets/PeopleWidget/PeopleWidget.d.ts +6 -0
- package/dist/components/widgets/PeopleWidget/PeopleWidget.d.ts.map +1 -0
- package/dist/components/widgets/PeopleWidget/index.d.ts +2 -0
- package/dist/components/widgets/PeopleWidget/index.d.ts.map +1 -0
- package/dist/components/widgets/ProgressOverviewWidget/CourseProgressBar.d.ts +19 -0
- package/dist/components/widgets/ProgressOverviewWidget/CourseProgressBar.d.ts.map +1 -0
- package/dist/components/widgets/ProgressOverviewWidget/CourseProgressItem.d.ts +9 -0
- package/dist/components/widgets/ProgressOverviewWidget/CourseProgressItem.d.ts.map +1 -0
- package/dist/components/widgets/ProgressOverviewWidget/ProgressOverviewWidget.d.ts +6 -0
- package/dist/components/widgets/ProgressOverviewWidget/ProgressOverviewWidget.d.ts.map +1 -0
- package/dist/components/widgets/ProgressOverviewWidget/index.d.ts +2 -0
- package/dist/components/widgets/ProgressOverviewWidget/index.d.ts.map +1 -0
- package/dist/components/widgets/RecentGradesWidget/GradeItem.d.ts +6 -0
- package/dist/components/widgets/RecentGradesWidget/GradeItem.d.ts.map +1 -0
- package/dist/components/widgets/RecentGradesWidget/RecentGradesWidget.d.ts +6 -0
- package/dist/components/widgets/RecentGradesWidget/RecentGradesWidget.d.ts.map +1 -0
- package/dist/components/widgets/TemplateWidget/TemplateWidget.d.ts +25 -0
- package/dist/components/widgets/TemplateWidget/TemplateWidget.d.ts.map +1 -0
- package/dist/components/widgets/TemplateWidget/index.d.ts +3 -0
- package/dist/components/widgets/TemplateWidget/index.d.ts.map +1 -0
- package/dist/components/widgets/TodoListWidget/CreateTodoModal.d.ts +26 -0
- package/dist/components/widgets/TodoListWidget/CreateTodoModal.d.ts.map +1 -0
- package/dist/components/widgets/TodoListWidget/TodoItem.d.ts +9 -0
- package/dist/components/widgets/TodoListWidget/TodoItem.d.ts.map +1 -0
- package/dist/components/widgets/TodoListWidget/TodoListWidget.d.ts +6 -0
- package/dist/components/widgets/TodoListWidget/TodoListWidget.d.ts.map +1 -0
- package/dist/components/widgets/TodoListWidget/api.d.ts +43 -0
- package/dist/components/widgets/TodoListWidget/api.d.ts.map +1 -0
- package/dist/components/widgets/TodoListWidget/hooks/usePlannerItems.d.ts +23 -0
- package/dist/components/widgets/TodoListWidget/hooks/usePlannerItems.d.ts.map +1 -0
- package/dist/components/widgets/TodoListWidget/types.d.ts +63 -0
- package/dist/components/widgets/TodoListWidget/types.d.ts.map +1 -0
- package/dist/components/widgets/TodoListWidget/utils.d.ts +8 -0
- package/dist/components/widgets/TodoListWidget/utils.d.ts.map +1 -0
- package/dist/constants/pagination.d.ts +10 -0
- package/dist/constants/pagination.d.ts.map +1 -0
- package/dist/hooks/useProgressOverview.d.ts +26 -0
- package/dist/hooks/useProgressOverview.d.ts.map +1 -0
- package/dist/hooks/useResponsiveContext.d.ts +16 -0
- package/dist/hooks/useResponsiveContext.d.ts.map +1 -0
- package/dist/hooks/useSharedCourses.d.ts +20 -0
- package/dist/hooks/useSharedCourses.d.ts.map +1 -0
- package/dist/hooks/useWidgetConfig.d.ts +13 -0
- package/dist/hooks/useWidgetConfig.d.ts.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13387 -0
- package/dist/types/env.d.ts +54 -0
- package/dist/types/env.d.ts.map +1 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/widget.d.ts +141 -0
- package/dist/types/widget.d.ts.map +1 -0
- package/dist/utils/graphql.d.ts +20 -0
- package/dist/utils/graphql.d.ts.map +1 -0
- package/dist/widgetRegistry.d.ts +4 -0
- package/dist/widgetRegistry.d.ts.map +1 -0
- package/package.json +86 -0
package/README.md
ADDED
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
# Widget Dashboard
|
|
2
|
+
|
|
3
|
+
A flexible, extensible dashboard system for Canvas LMS that allows students to customize their learning experience with various widgets.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The widget dashboard provides a 3-column grid layout where different widgets can be positioned and sized according to configuration. The system is designed to be extensible, with a template-based architecture that makes creating new widgets straightforward.
|
|
8
|
+
|
|
9
|
+
## Architecture
|
|
10
|
+
|
|
11
|
+
### Core Components
|
|
12
|
+
|
|
13
|
+
- **TemplateWidget**: Base template providing consistent styling, loading states, and error handling
|
|
14
|
+
- **WidgetRegistry**: Central registry system that maps widget types to their React components
|
|
15
|
+
- **WidgetGrid**: Renders widgets in a CSS Grid layout based on configuration
|
|
16
|
+
- **Widget Types**: Defined constants and TypeScript interfaces for type safety
|
|
17
|
+
|
|
18
|
+
### Current Widgets
|
|
19
|
+
|
|
20
|
+
- **CourseWorkSummaryWidget**: Displays upcoming assignments, missing work, and submitted assignments with filtering options
|
|
21
|
+
|
|
22
|
+
## Creating a New Widget
|
|
23
|
+
|
|
24
|
+
### Step 1: Create the Widget Component Structure
|
|
25
|
+
|
|
26
|
+
Create the directory structure for your new widget:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
mkdir -p ui/features/widget_dashboard/react/components/widgets/MyWidget/__tests__
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Create the main widget component:
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
// ui/features/widget_dashboard/react/components/widgets/MyWidget/MyWidget.tsx
|
|
36
|
+
import React, {useState, useEffect} from 'react'
|
|
37
|
+
import {useScope as createI18nScope} from '@canvas/i18n'
|
|
38
|
+
import {Button} from '@instructure/ui-buttons'
|
|
39
|
+
import {Text} from '@instructure/ui-text'
|
|
40
|
+
import TemplateWidget from '../TemplateWidget'
|
|
41
|
+
import type {BaseWidgetProps} from '../../../types'
|
|
42
|
+
|
|
43
|
+
const I18n = createI18nScope('widget_dashboard')
|
|
44
|
+
|
|
45
|
+
const MyWidget: React.FC<BaseWidgetProps> = ({widget, isLoading, error, onRetry}) => {
|
|
46
|
+
const [data, setData] = useState<string>('Loading...')
|
|
47
|
+
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
// Your data fetching logic here
|
|
50
|
+
setTimeout(() => {
|
|
51
|
+
setData('Widget data loaded!')
|
|
52
|
+
}, 1000)
|
|
53
|
+
}, [])
|
|
54
|
+
|
|
55
|
+
const handleAction = () => {
|
|
56
|
+
console.log('Widget action clicked')
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<TemplateWidget
|
|
61
|
+
widget={widget}
|
|
62
|
+
title="Custom Widget Title" // Optional: Override widget.title
|
|
63
|
+
isLoading={isLoading}
|
|
64
|
+
error={error}
|
|
65
|
+
onRetry={onRetry}
|
|
66
|
+
showHeader={true} // Optional: Show/hide header (default: true)
|
|
67
|
+
headerActions={
|
|
68
|
+
<Button size="small" variant="ghost">
|
|
69
|
+
{I18n.t('Settings')}
|
|
70
|
+
</Button>
|
|
71
|
+
}
|
|
72
|
+
actions={
|
|
73
|
+
<Button onClick={handleAction} size="small">
|
|
74
|
+
{I18n.t('Widget Action')}
|
|
75
|
+
</Button>
|
|
76
|
+
}
|
|
77
|
+
>
|
|
78
|
+
<div>
|
|
79
|
+
<Text size="medium">{data}</Text>
|
|
80
|
+
<Text size="small" color="secondary">
|
|
81
|
+
{I18n.t('This is my custom widget content')}
|
|
82
|
+
</Text>
|
|
83
|
+
</div>
|
|
84
|
+
</TemplateWidget>
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export default MyWidget
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Create an index file for clean exports:
|
|
92
|
+
|
|
93
|
+
```tsx
|
|
94
|
+
// ui/features/widget_dashboard/react/components/widgets/MyWidget/index.ts
|
|
95
|
+
export {default} from './MyWidget'
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
#### TemplateWidget Props Breakdown
|
|
99
|
+
|
|
100
|
+
The `TemplateWidget` component accepts the following props to provide a consistent widget experience:
|
|
101
|
+
|
|
102
|
+
| Prop | Type | Required | Default | Description |
|
|
103
|
+
|------|------|----------|---------|-------------|
|
|
104
|
+
| `widget` | `Widget` | ✅ Yes | - | Widget configuration object containing id, type, position, size, and title |
|
|
105
|
+
| `children` | `React.ReactNode` | ✅ Yes | - | The main content of your widget |
|
|
106
|
+
| `title` | `string` | ❌ No | `widget.title` | Override the widget title. If not provided, uses `widget.title` |
|
|
107
|
+
| `isLoading` | `boolean` | ❌ No | `false` | Shows loading spinner when true, hides children content |
|
|
108
|
+
| `error` | `string \| null` | ❌ No | `null` | Error message to display. When set, shows error state and hides children |
|
|
109
|
+
| `onRetry` | `() => void` | ❌ No | `undefined` | Callback for retry button. Only shows retry button if provided and error exists |
|
|
110
|
+
| `showHeader` | `boolean` | ❌ No | `true` | Whether to show the widget header with title |
|
|
111
|
+
| `headerActions` | `React.ReactNode` | ❌ No | `undefined` | Additional actions to display in the header (e.g., settings, info buttons) |
|
|
112
|
+
| `actions` | `React.ReactNode` | ❌ No | `undefined` | Action buttons to display at the bottom of the widget |
|
|
113
|
+
|
|
114
|
+
**State Priority**: The TemplateWidget renders content based on this priority:
|
|
115
|
+
1. **Loading state** (when `isLoading={true}`) - Shows spinner, hides everything else
|
|
116
|
+
2. **Error state** (when `error` is provided) - Shows error message and optional retry button
|
|
117
|
+
3. **Normal state** - Shows `children` content and optional `actions`
|
|
118
|
+
|
|
119
|
+
**Layout Structure**:
|
|
120
|
+
```
|
|
121
|
+
┌─────────────────────────────────────┐
|
|
122
|
+
│ Header (if showHeader=true) │
|
|
123
|
+
│ ┌─────────────┐ ┌─────────────────┐ │
|
|
124
|
+
│ │ Title │ │ Header Actions │ │
|
|
125
|
+
│ └─────────────┘ └─────────────────┘ │
|
|
126
|
+
├─────────────────────────────────────┤
|
|
127
|
+
│ │
|
|
128
|
+
│ Content Area │
|
|
129
|
+
│ (children | loading | error) │
|
|
130
|
+
│ │
|
|
131
|
+
├─────────────────────────────────────┤
|
|
132
|
+
│ Actions (if provided) │
|
|
133
|
+
└─────────────────────────────────────┘
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Step 2: Define Widget Type Constants
|
|
137
|
+
|
|
138
|
+
Add your widget type to the constants file:
|
|
139
|
+
|
|
140
|
+
```tsx
|
|
141
|
+
// ui/features/widget_dashboard/react/constants.ts
|
|
142
|
+
export const WIDGET_TYPES = {
|
|
143
|
+
COURSE_WORK_SUMMARY: 'course_work_summary',
|
|
144
|
+
MY_WIDGET: 'my_widget', // Add your new widget type here
|
|
145
|
+
} as const
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Step 3: Register Your Widget in the Registry
|
|
149
|
+
|
|
150
|
+
Update the widget registry to include your new widget:
|
|
151
|
+
|
|
152
|
+
```tsx
|
|
153
|
+
// ui/features/widget_dashboard/react/components/WidgetRegistry.ts
|
|
154
|
+
import MyWidget from './widgets/MyWidget' // Import your widget
|
|
155
|
+
|
|
156
|
+
const widgetRegistry: WidgetRegistry = {
|
|
157
|
+
[WIDGET_TYPES.COURSE_WORK_SUMMARY]: {
|
|
158
|
+
component: CourseWorkSummaryWidget,
|
|
159
|
+
displayName: "Today's course work",
|
|
160
|
+
description: 'Shows summary of upcoming assignments and course work',
|
|
161
|
+
},
|
|
162
|
+
[WIDGET_TYPES.MY_WIDGET]: {
|
|
163
|
+
component: MyWidget,
|
|
164
|
+
displayName: 'My Custom Widget',
|
|
165
|
+
description: 'A custom widget that demonstrates the widget system',
|
|
166
|
+
},
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
The registry entry includes:
|
|
171
|
+
- `component`: Your React component
|
|
172
|
+
- `displayName`: Human-readable name for the widget
|
|
173
|
+
- `description`: What the widget does (useful for admin interfaces later)
|
|
174
|
+
|
|
175
|
+
### Step 4: Add Widget to Dashboard Configuration
|
|
176
|
+
|
|
177
|
+
Add your widget to the default configuration:
|
|
178
|
+
|
|
179
|
+
```tsx
|
|
180
|
+
// ui/features/widget_dashboard/react/constants.ts
|
|
181
|
+
export const DEFAULT_WIDGET_CONFIG = {
|
|
182
|
+
columns: 3, // 3-column grid layout
|
|
183
|
+
widgets: [
|
|
184
|
+
{
|
|
185
|
+
id: 'course-work-widget',
|
|
186
|
+
type: WIDGET_TYPES.COURSE_WORK_SUMMARY,
|
|
187
|
+
position: {col: 1, row: 1}, // Column 1, Row 1
|
|
188
|
+
size: {width: 2, height: 1}, // Spans 2 columns, 1 row
|
|
189
|
+
title: "Today's course work",
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
id: 'my-custom-widget', // Unique identifier
|
|
193
|
+
type: WIDGET_TYPES.MY_WIDGET, // References your widget type
|
|
194
|
+
position: {col: 3, row: 1}, // Column 3, Row 1 (right side)
|
|
195
|
+
size: {width: 1, height: 1}, // Single column, single row
|
|
196
|
+
title: 'My Widget Title', // Will be displayed in header
|
|
197
|
+
},
|
|
198
|
+
],
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Step 5: Create Tests for Your Widget
|
|
203
|
+
|
|
204
|
+
Create comprehensive tests following existing patterns:
|
|
205
|
+
|
|
206
|
+
```tsx
|
|
207
|
+
// ui/features/widget_dashboard/react/components/widgets/MyWidget/__tests__/MyWidget.test.tsx
|
|
208
|
+
import React from 'react'
|
|
209
|
+
import {render, screen, fireEvent} from '@testing-library/react'
|
|
210
|
+
import MyWidget from '../MyWidget'
|
|
211
|
+
import type {BaseWidgetProps} from '../../../../types'
|
|
212
|
+
import type {Widget} from '../../../../types'
|
|
213
|
+
|
|
214
|
+
const mockWidget: Widget = {
|
|
215
|
+
id: 'test-my-widget',
|
|
216
|
+
type: 'my_widget',
|
|
217
|
+
position: {col: 1, row: 1},
|
|
218
|
+
size: {width: 1, height: 1},
|
|
219
|
+
title: 'Test My Widget',
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const buildDefaultProps = (overrides: Partial<BaseWidgetProps> = {}): BaseWidgetProps => {
|
|
223
|
+
return {
|
|
224
|
+
widget: mockWidget,
|
|
225
|
+
...overrides,
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
describe('MyWidget', () => {
|
|
230
|
+
it('renders widget content', () => {
|
|
231
|
+
render(<MyWidget {...buildDefaultProps()} />)
|
|
232
|
+
expect(screen.getByText('This is my custom widget content')).toBeInTheDocument()
|
|
233
|
+
expect(screen.getByRole('button', {name: 'Widget Action'})).toBeInTheDocument()
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
it('handles loading state', () => {
|
|
237
|
+
render(<MyWidget {...buildDefaultProps({isLoading: true})} />)
|
|
238
|
+
|
|
239
|
+
expect(screen.getByText('Loading widget data...')).toBeInTheDocument()
|
|
240
|
+
})
|
|
241
|
+
|
|
242
|
+
it('handles error state', () => {
|
|
243
|
+
const onRetry = vi.fn()
|
|
244
|
+
render(<MyWidget {...buildDefaultProps({error: 'Failed to load', onRetry})} />)
|
|
245
|
+
|
|
246
|
+
expect(screen.getByText('Failed to load')).toBeInTheDocument()
|
|
247
|
+
expect(screen.getByRole('button', {name: 'Retry'})).toBeInTheDocument()
|
|
248
|
+
})
|
|
249
|
+
})
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### Step 6: Run Tests and Verify
|
|
253
|
+
|
|
254
|
+
After creating your widget, run the tests to ensure everything works:
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
# Run your specific widget tests
|
|
258
|
+
npm test -- ui/features/widget_dashboard/react/components/widgets/MyWidget/__tests__/MyWidget.test.tsx
|
|
259
|
+
|
|
260
|
+
# Run all widget dashboard tests
|
|
261
|
+
npm test -- ui/features/widget_dashboard/
|
|
262
|
+
|
|
263
|
+
# Check TypeScript compilation
|
|
264
|
+
yarn check:ts
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## Grid System
|
|
268
|
+
|
|
269
|
+
The dashboard uses CSS Grid with the following concepts:
|
|
270
|
+
|
|
271
|
+
- **Position**: `{col: 3, row: 1}` means column 3, row 1
|
|
272
|
+
- **Size**: `{width: 2, height: 1}` means spans 2 columns, 1 row height
|
|
273
|
+
- **Grid**: Currently 3 columns wide, unlimited rows
|
|
274
|
+
|
|
275
|
+
### Positioning Examples
|
|
276
|
+
|
|
277
|
+
```tsx
|
|
278
|
+
// Full width widget at top
|
|
279
|
+
position: {col: 1, row: 1}, size: {width: 3, height: 1}
|
|
280
|
+
|
|
281
|
+
// Left side widget
|
|
282
|
+
position: {col: 1, row: 2}, size: {width: 1, height: 1}
|
|
283
|
+
|
|
284
|
+
// Right side widget (spans 2 columns)
|
|
285
|
+
position: {col: 2, row: 2}, size: {width: 2, height: 1}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
## Benefits of the Template System
|
|
289
|
+
|
|
290
|
+
### What You Get for Free
|
|
291
|
+
|
|
292
|
+
By extending TemplateWidget, your widget automatically gets:
|
|
293
|
+
- Consistent padding, shadows, and border radius
|
|
294
|
+
- Loading spinner during data fetching
|
|
295
|
+
- Error states with retry buttons
|
|
296
|
+
- Header with title and optional actions
|
|
297
|
+
- Responsive design
|
|
298
|
+
- Accessibility features
|
|
299
|
+
- Test utilities and patterns
|
|
300
|
+
|
|
301
|
+
### System Benefits
|
|
302
|
+
|
|
303
|
+
1. **Consistent UI**: All widgets use the same TemplateWidget base for consistent styling
|
|
304
|
+
2. **Built-in States**: Loading, error, and retry functionality comes free
|
|
305
|
+
3. **Type Safety**: TypeScript ensures proper widget configuration
|
|
306
|
+
4. **Testability**: Clear patterns for testing widgets
|
|
307
|
+
5. **Scalability**: Easy to add new widgets without modifying core code
|
|
308
|
+
6. **Future-Ready**: Designed to work with database-driven configuration
|
|
309
|
+
|
|
310
|
+
## TypeScript Interfaces
|
|
311
|
+
|
|
312
|
+
### BaseWidgetProps
|
|
313
|
+
```tsx
|
|
314
|
+
interface BaseWidgetProps {
|
|
315
|
+
widget: Widget
|
|
316
|
+
isLoading?: boolean
|
|
317
|
+
error?: string | null
|
|
318
|
+
onRetry?: () => void
|
|
319
|
+
}
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### Widget
|
|
323
|
+
```tsx
|
|
324
|
+
interface Widget {
|
|
325
|
+
id: string
|
|
326
|
+
type: string
|
|
327
|
+
position: WidgetPosition
|
|
328
|
+
size: WidgetSize
|
|
329
|
+
title: string
|
|
330
|
+
}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
### WidgetRenderer
|
|
334
|
+
```tsx
|
|
335
|
+
interface WidgetRenderer {
|
|
336
|
+
component: React.ComponentType<BaseWidgetProps>
|
|
337
|
+
displayName: string
|
|
338
|
+
description: string
|
|
339
|
+
}
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
## Future Enhancements
|
|
343
|
+
|
|
344
|
+
- Database-driven widget configuration
|
|
345
|
+
- User customization of widget layout
|
|
346
|
+
- Widget-specific settings and preferences
|
|
347
|
+
- Drag-and-drop widget positioning
|
|
348
|
+
- Additional widget types for various Canvas features
|
|
349
|
+
|
|
350
|
+
## Testing
|
|
351
|
+
|
|
352
|
+
The widget dashboard includes comprehensive test coverage:
|
|
353
|
+
- Unit tests for all components
|
|
354
|
+
- Integration tests for the widget registry
|
|
355
|
+
- Test utilities for creating new widget tests
|
|
356
|
+
|
|
357
|
+
Run the test suite with:
|
|
358
|
+
|
|
359
|
+
```bash
|
|
360
|
+
npm test -- ui/features/widget_dashboard/
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
## Development
|
|
364
|
+
|
|
365
|
+
When developing widgets, your component only needs to focus on its core functionality. The TemplateWidget base handles all common UI patterns, state management, and user interactions, allowing you to concentrate on delivering value-specific features.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CoursesTab.canvas.d.ts","sourceRoot":"","sources":["../../src/components/CoursesTab.canvas.tsx"],"names":[],"mappings":"AAuBA,OAAO,KAAsC,MAAM,OAAO,CAAA;AAO1D,QAAA,MAAM,UAAU,EAAE,KAAK,CAAC,EAuFvB,CAAA;AAED,eAAe,UAAU,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CoursesTabWrapper.d.ts","sourceRoot":"","sources":["../../src/components/CoursesTabWrapper.tsx"],"names":[],"mappings":"AAmBA,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,QAAA,MAAM,cAAc,EAAE,KAAK,CAAC,EAM3B,CAAA;AAED,eAAe,cAAc,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DashboardNotifications.d.ts","sourceRoot":"","sources":["../../src/components/DashboardNotifications.tsx"],"names":[],"mappings":"AAuBA,OAAO,KAAmB,MAAM,OAAO,CAAA;AAuDvC,QAAA,MAAM,sBAAsB,EAAE,KAAK,CAAC,EA0FnC,CAAA;AAED,eAAe,sBAAsB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DashboardTab.d.ts","sourceRoot":"","sources":["../../src/components/DashboardTab.tsx"],"names":[],"mappings":"AAmBA,OAAO,KAAK,MAAM,OAAO,CAAA;AAKzB,QAAA,MAAM,YAAY,EAAE,KAAK,CAAC,EASzB,CAAA;AAED,eAAe,YAAY,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DashboardTabs.d.ts","sourceRoot":"","sources":["../../src/components/DashboardTabs.tsx"],"names":[],"mappings":"AAoBA,OAAO,KAAK,MAAM,OAAO,CAAA;AAYzB,QAAA,MAAM,aAAa,EAAE,KAAK,CAAC,EA6D1B,CAAA;AAED,eAAe,aAAa,CAAA"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
|
|
3
|
+
export interface EnrollmentInvitationData {
|
|
4
|
+
id: string;
|
|
5
|
+
uuid: string;
|
|
6
|
+
course: {
|
|
7
|
+
id: string;
|
|
8
|
+
name: string;
|
|
9
|
+
};
|
|
10
|
+
role: {
|
|
11
|
+
name: string;
|
|
12
|
+
};
|
|
13
|
+
roleLabel: string;
|
|
14
|
+
}
|
|
15
|
+
interface EnrollmentInvitationProps {
|
|
16
|
+
invitation: EnrollmentInvitationData;
|
|
17
|
+
onAccept?: (invitationId: string) => void;
|
|
18
|
+
onReject?: (invitationId: string) => void;
|
|
19
|
+
}
|
|
20
|
+
declare const EnrollmentInvitation: React.FC<EnrollmentInvitationProps>;
|
|
21
|
+
export default EnrollmentInvitation;
|
|
22
|
+
//# sourceMappingURL=EnrollmentInvitation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EnrollmentInvitation.d.ts","sourceRoot":"","sources":["../../src/components/EnrollmentInvitation.tsx"],"names":[],"mappings":"AAyBA,OAAO,KAAsB,MAAM,OAAO,CAAA;AAgC1C,MAAM,WAAW,wBAAwB;IACvC,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE;QACN,EAAE,EAAE,MAAM,CAAA;QACV,IAAI,EAAE,MAAM,CAAA;KACb,CAAA;IACD,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM,CAAA;KACb,CAAA;IACD,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,UAAU,yBAAyB;IACjC,UAAU,EAAE,wBAAwB,CAAA;IACpC,QAAQ,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAA;IACzC,QAAQ,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAA;CAC1C;AAED,QAAA,MAAM,oBAAoB,EAAE,KAAK,CAAC,EAAE,CAAC,yBAAyB,CA6I7D,CAAA;AAED,eAAe,oBAAoB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FeedbackQuestionTile.d.ts","sourceRoot":"","sources":["../../src/components/FeedbackQuestionTile.tsx"],"names":[],"mappings":"AAsBA,OAAO,KAAkB,MAAM,OAAO,CAAA;AAMtC,QAAA,MAAM,oBAAoB,EAAE,KAAK,CAAC,EAiEjC,CAAA;AAED,eAAe,oBAAoB,CAAA"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
|
|
3
|
+
export interface AccountNotificationData {
|
|
4
|
+
id: string;
|
|
5
|
+
subject: string;
|
|
6
|
+
message: string;
|
|
7
|
+
startAt: string;
|
|
8
|
+
endAt: string;
|
|
9
|
+
accountName?: string;
|
|
10
|
+
siteAdmin: boolean;
|
|
11
|
+
notificationType?: string;
|
|
12
|
+
}
|
|
13
|
+
interface NotificationAlertProps {
|
|
14
|
+
notification: AccountNotificationData;
|
|
15
|
+
onDismiss: (id: string) => void;
|
|
16
|
+
}
|
|
17
|
+
declare const NotificationAlert: React.FC<NotificationAlertProps>;
|
|
18
|
+
export default NotificationAlert;
|
|
19
|
+
//# sourceMappingURL=NotificationAlert.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NotificationAlert.d.ts","sourceRoot":"","sources":["../../src/components/NotificationAlert.tsx"],"names":[],"mappings":"AA2BA,OAAO,KAAK,MAAM,OAAO,CAAA;AAIzB,MAAM,WAAW,uBAAuB;IACtC,EAAE,EAAE,MAAM,CAAA;IACV,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,OAAO,CAAA;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B;AAED,UAAU,sBAAsB;IAC9B,YAAY,EAAE,uBAAuB,CAAA;IACrC,SAAS,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;CAChC;AA2BD,QAAA,MAAM,iBAAiB,EAAE,KAAK,CAAC,EAAE,CAAC,sBAAsB,CA+CvD,CAAA;AAED,eAAe,iBAAiB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WidgetDashboardContainer.d.ts","sourceRoot":"","sources":["../../src/components/WidgetDashboardContainer.tsx"],"names":[],"mappings":"AAwBA,OAAO,KAAoB,MAAM,OAAO,CAAA;AAUxC,QAAA,MAAM,wBAAwB,EAAE,KAAK,CAAC,EAyGrC,CAAA;AAED,eAAe,wBAAwB,CAAA"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { WidgetConfig } from '../types';
|
|
3
|
+
|
|
4
|
+
interface WidgetGridProps {
|
|
5
|
+
config?: WidgetConfig;
|
|
6
|
+
isEditMode?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare const WidgetGrid: React.FC<WidgetGridProps>;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=WidgetGrid.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WidgetGrid.d.ts","sourceRoot":"","sources":["../../src/components/WidgetGrid.tsx"],"names":[],"mappings":"AAoBA,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,OAAO,KAAK,EAAU,YAAY,EAAE,MAAM,UAAU,CAAA;AAGpD,UAAU,eAAe;IACvB,MAAM,CAAC,EAAE,YAAY,CAAA;IACrB,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAED,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CAwChD,CAAA"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { BaseWidgetProps } from '../types';
|
|
3
|
+
|
|
4
|
+
interface WidgetRendererProps extends BaseWidgetProps {
|
|
5
|
+
}
|
|
6
|
+
export declare const WidgetRenderer: React.FC<WidgetRendererProps>;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=WidgetRenderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WidgetRenderer.d.ts","sourceRoot":"","sources":["../../src/components/WidgetRenderer.tsx"],"names":[],"mappings":"AAkBA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAG/C,UAAU,mBAAoB,SAAQ,eAAe;CAEpD;AAED,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CAWxD,CAAA"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
|
|
3
|
+
export interface CourseCodeProps {
|
|
4
|
+
courseId: string;
|
|
5
|
+
gridIndex?: number;
|
|
6
|
+
size?: 'x-small' | 'small' | 'medium';
|
|
7
|
+
className?: string;
|
|
8
|
+
overrideCode?: string;
|
|
9
|
+
overrideColor?: {
|
|
10
|
+
background: string;
|
|
11
|
+
textColor: string;
|
|
12
|
+
};
|
|
13
|
+
useCustomColors?: boolean;
|
|
14
|
+
maxWidth?: string;
|
|
15
|
+
}
|
|
16
|
+
export declare const CourseCode: React.FC<CourseCodeProps>;
|
|
17
|
+
export default CourseCode;
|
|
18
|
+
//# sourceMappingURL=CourseCode.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CourseCode.d.ts","sourceRoot":"","sources":["../../../src/components/shared/CourseCode.tsx"],"names":[],"mappings":"AAsBA,OAAO,KAA4B,MAAM,OAAO,CAAA;AAgChD,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,IAAI,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,QAAQ,CAAA;IACrC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,aAAa,CAAC,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAA;IACzD,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CAoEhD,CAAA;AAED,eAAe,UAAU,CAAA"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
|
|
3
|
+
export interface CourseFilterSelectProps {
|
|
4
|
+
selectedCourse: string;
|
|
5
|
+
onChange: (event: React.SyntheticEvent, data: {
|
|
6
|
+
value?: string | number;
|
|
7
|
+
id?: string;
|
|
8
|
+
}) => void;
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
renderLabel?: string;
|
|
11
|
+
}
|
|
12
|
+
declare const CourseFilterSelect: React.FC<CourseFilterSelectProps>;
|
|
13
|
+
export default CourseFilterSelect;
|
|
14
|
+
//# sourceMappingURL=CourseFilterSelect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CourseFilterSelect.d.ts","sourceRoot":"","sources":["../../../src/components/shared/CourseFilterSelect.tsx"],"names":[],"mappings":"AAmBA,OAAO,KAAkB,MAAM,OAAO,CAAA;AAKtC,MAAM,WAAW,uBAAuB;IACtC,cAAc,EAAE,MAAM,CAAA;IACtB,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,cAAc,EAAE,IAAI,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;QAAC,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAA;IAC/F,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,QAAA,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC,uBAAuB,CAkCzD,CAAA;AAED,eAAe,kBAAkB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CourseName.d.ts","sourceRoot":"","sources":["../../../src/components/shared/CourseName.tsx"],"names":[],"mappings":"AAsBA,OAAO,KAAmB,MAAM,OAAO,CAAA;AAEvC,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CA+BhD,CAAA;AAED,eAAe,UAAU,CAAA"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
|
|
3
|
+
export type DateFilterOption = 'not_submitted' | 'missing' | 'submitted';
|
|
4
|
+
export interface DateFilterConfig {
|
|
5
|
+
id: DateFilterOption;
|
|
6
|
+
label: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function isValidDateFilterOption(value: unknown): value is DateFilterOption;
|
|
9
|
+
export interface CourseWorkFiltersProps {
|
|
10
|
+
selectedCourse: string;
|
|
11
|
+
selectedDateFilter: DateFilterOption;
|
|
12
|
+
onCourseChange: (event: React.SyntheticEvent, data: {
|
|
13
|
+
value?: string | number;
|
|
14
|
+
id?: string;
|
|
15
|
+
}) => void;
|
|
16
|
+
onDateFilterChange: (event: React.SyntheticEvent, data: {
|
|
17
|
+
value?: string | number;
|
|
18
|
+
id?: string;
|
|
19
|
+
}) => void;
|
|
20
|
+
}
|
|
21
|
+
declare const CourseWorkFilters: React.FC<CourseWorkFiltersProps>;
|
|
22
|
+
export default CourseWorkFilters;
|
|
23
|
+
//# sourceMappingURL=CourseWorkFilters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CourseWorkFilters.d.ts","sourceRoot":"","sources":["../../../src/components/shared/CourseWorkFilters.tsx"],"names":[],"mappings":"AAoBA,OAAO,KAAkB,MAAM,OAAO,CAAA;AAKtC,MAAM,MAAM,gBAAgB,GAAG,eAAe,GAAG,SAAS,GAAG,WAAW,CAAA;AAExE,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,gBAAgB,CAAA;IACpB,KAAK,EAAE,MAAM,CAAA;CACd;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,gBAAgB,CAKjF;AAED,MAAM,WAAW,sBAAsB;IACrC,cAAc,EAAE,MAAM,CAAA;IACtB,kBAAkB,EAAE,gBAAgB,CAAA;IACpC,cAAc,EAAE,CACd,KAAK,EAAE,KAAK,CAAC,cAAc,EAC3B,IAAI,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;QAAC,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,KAC3C,IAAI,CAAA;IACT,kBAAkB,EAAE,CAClB,KAAK,EAAE,KAAK,CAAC,cAAc,EAC3B,IAAI,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;QAAC,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,KAC3C,IAAI,CAAA;CACV;AAED,QAAA,MAAM,iBAAiB,EAAE,KAAK,CAAC,EAAE,CAAC,sBAAsB,CAuCvD,CAAA;AAED,eAAe,iBAAiB,CAAA"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
|
|
3
|
+
interface StatisticsCardProps {
|
|
4
|
+
count: number;
|
|
5
|
+
label: string;
|
|
6
|
+
backgroundColor: string;
|
|
7
|
+
}
|
|
8
|
+
declare const StatisticsCard: React.FC<StatisticsCardProps>;
|
|
9
|
+
export default StatisticsCard;
|
|
10
|
+
//# sourceMappingURL=StatisticsCard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StatisticsCard.d.ts","sourceRoot":"","sources":["../../../src/components/shared/StatisticsCard.tsx"],"names":[],"mappings":"AAoBA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,UAAU,mBAAmB;IAC3B,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,eAAe,EAAE,MAAM,CAAA;CACxB;AAED,QAAA,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CA4BjD,CAAA;AAED,eAAe,cAAc,CAAA"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
|
|
3
|
+
export interface StatisticsData {
|
|
4
|
+
due: number;
|
|
5
|
+
missing: number;
|
|
6
|
+
submitted: number;
|
|
7
|
+
}
|
|
8
|
+
export interface StatisticsCardsGridProps {
|
|
9
|
+
summary: StatisticsData;
|
|
10
|
+
margin?: string;
|
|
11
|
+
}
|
|
12
|
+
declare const StatisticsCardsGrid: React.FC<StatisticsCardsGridProps>;
|
|
13
|
+
export default StatisticsCardsGrid;
|
|
14
|
+
//# sourceMappingURL=StatisticsCardsGrid.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StatisticsCardsGrid.d.ts","sourceRoot":"","sources":["../../../src/components/shared/StatisticsCardsGrid.tsx"],"names":[],"mappings":"AAmBA,OAAO,KAAkB,MAAM,OAAO,CAAA;AAKtC,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,cAAc,CAAA;IACvB,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,QAAA,MAAM,mBAAmB,EAAE,KAAK,CAAC,EAAE,CAAC,wBAAwB,CA2C3D,CAAA;AAED,eAAe,mBAAmB,CAAA"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { Widget, WidgetConfig } from '../../types';
|
|
3
|
+
|
|
4
|
+
interface WidgetContextMenuProps {
|
|
5
|
+
trigger: React.ReactElement;
|
|
6
|
+
widget: Widget;
|
|
7
|
+
config: WidgetConfig;
|
|
8
|
+
onSelect?: (action: string) => void;
|
|
9
|
+
}
|
|
10
|
+
declare const WidgetContextMenu: React.FC<WidgetContextMenuProps>;
|
|
11
|
+
export default WidgetContextMenu;
|
|
12
|
+
//# sourceMappingURL=WidgetContextMenu.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WidgetContextMenu.d.ts","sourceRoot":"","sources":["../../../src/components/shared/WidgetContextMenu.tsx"],"names":[],"mappings":"AA2BA,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAEvD,UAAU,sBAAsB;IAC9B,OAAO,EAAE,KAAK,CAAC,YAAY,CAAA;IAC3B,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,YAAY,CAAA;IACpB,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;CACpC;AAeD,QAAA,MAAM,iBAAiB,EAAE,KAAK,CAAC,EAAE,CAAC,sBAAsB,CAsDvD,CAAA;AAED,eAAe,iBAAiB,CAAA"}
|