@studious-lms/server 1.2.44 → 1.2.46

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.
Files changed (234) hide show
  1. package/.env.example +45 -0
  2. package/.env.test.example +37 -0
  3. package/README.md +34 -7
  4. package/coverage/base.css +224 -0
  5. package/coverage/block-navigation.js +87 -0
  6. package/coverage/clover.xml +12110 -0
  7. package/coverage/coverage-final.json +44 -0
  8. package/coverage/favicon.png +0 -0
  9. package/coverage/index.html +221 -0
  10. package/coverage/prettify.css +1 -0
  11. package/coverage/prettify.js +2 -0
  12. package/coverage/server/index.html +116 -0
  13. package/coverage/server/src/exportType.ts.html +109 -0
  14. package/coverage/server/src/index.html +161 -0
  15. package/coverage/server/src/index.ts.html +1702 -0
  16. package/coverage/server/src/instrument.ts.html +130 -0
  17. package/coverage/server/src/lib/config/env.ts.html +448 -0
  18. package/coverage/server/src/lib/config/index.html +116 -0
  19. package/coverage/server/src/lib/fileUpload.ts.html +1138 -0
  20. package/coverage/server/src/lib/googleCloudStorage.ts.html +334 -0
  21. package/coverage/server/src/lib/index.html +206 -0
  22. package/coverage/server/src/lib/jsonConversion.ts.html +2323 -0
  23. package/coverage/server/src/lib/jsonStyles.ts.html +193 -0
  24. package/coverage/server/src/lib/notificationHandler.ts.html +193 -0
  25. package/coverage/server/src/lib/pusher.ts.html +121 -0
  26. package/coverage/server/src/lib/thumbnailGenerator.ts.html +592 -0
  27. package/coverage/server/src/middleware/auth.ts.html +646 -0
  28. package/coverage/server/src/middleware/index.html +146 -0
  29. package/coverage/server/src/middleware/logging.ts.html +244 -0
  30. package/coverage/server/src/middleware/security.ts.html +271 -0
  31. package/coverage/server/src/routers/_app.ts.html +232 -0
  32. package/coverage/server/src/routers/agenda.ts.html +319 -0
  33. package/coverage/server/src/routers/announcement.ts.html +3481 -0
  34. package/coverage/server/src/routers/assignment.ts.html +7633 -0
  35. package/coverage/server/src/routers/attendance.ts.html +1030 -0
  36. package/coverage/server/src/routers/auth.ts.html +1081 -0
  37. package/coverage/server/src/routers/class.ts.html +3535 -0
  38. package/coverage/server/src/routers/comment.ts.html +991 -0
  39. package/coverage/server/src/routers/conversation.ts.html +982 -0
  40. package/coverage/server/src/routers/event.ts.html +1609 -0
  41. package/coverage/server/src/routers/file.ts.html +1144 -0
  42. package/coverage/server/src/routers/folder.ts.html +2797 -0
  43. package/coverage/server/src/routers/index.html +386 -0
  44. package/coverage/server/src/routers/labChat.ts.html +3073 -0
  45. package/coverage/server/src/routers/marketing.ts.html +340 -0
  46. package/coverage/server/src/routers/message.ts.html +1912 -0
  47. package/coverage/server/src/routers/notifications.ts.html +364 -0
  48. package/coverage/server/src/routers/section.ts.html +1120 -0
  49. package/coverage/server/src/routers/user.ts.html +862 -0
  50. package/coverage/server/src/routers/worksheet.ts.html +1729 -0
  51. package/coverage/server/src/trpc.ts.html +397 -0
  52. package/coverage/server/src/types/index.html +116 -0
  53. package/coverage/server/src/types/trpc.ts.html +127 -0
  54. package/coverage/server/src/utils/aiUser.ts.html +280 -0
  55. package/coverage/server/src/utils/email.ts.html +121 -0
  56. package/coverage/server/src/utils/generateInviteCode.ts.html +106 -0
  57. package/coverage/server/src/utils/index.html +206 -0
  58. package/coverage/server/src/utils/inference.ts.html +709 -0
  59. package/coverage/server/src/utils/logger.ts.html +664 -0
  60. package/coverage/server/src/utils/prismaErrorHandler.ts.html +907 -0
  61. package/coverage/server/src/utils/prismaWrapper.ts.html +355 -0
  62. package/coverage/server/vitest.config.ts.html +196 -0
  63. package/coverage/sort-arrow-sprite.png +0 -0
  64. package/coverage/sorter.js +210 -0
  65. package/dist/index.d.ts.map +1 -1
  66. package/dist/index.js +83 -52
  67. package/dist/index.js.map +1 -1
  68. package/dist/instrument.js +15 -8
  69. package/dist/instrument.js.map +1 -1
  70. package/dist/lib/config/env.d.ts +169 -0
  71. package/dist/lib/config/env.d.ts.map +1 -0
  72. package/dist/lib/config/env.js +115 -0
  73. package/dist/lib/config/env.js.map +1 -0
  74. package/dist/lib/fileUpload.d.ts.map +1 -1
  75. package/dist/lib/fileUpload.js +5 -4
  76. package/dist/lib/fileUpload.js.map +1 -1
  77. package/dist/lib/googleCloudStorage.d.ts.map +1 -1
  78. package/dist/lib/googleCloudStorage.js +7 -8
  79. package/dist/lib/googleCloudStorage.js.map +1 -1
  80. package/dist/lib/jsonConversion.d.ts.map +1 -1
  81. package/dist/lib/jsonConversion.js +14 -16
  82. package/dist/lib/jsonConversion.js.map +1 -1
  83. package/dist/lib/notificationHandler.d.ts +2 -2
  84. package/dist/lib/prisma.d.ts +2 -2
  85. package/dist/lib/prisma.d.ts.map +1 -1
  86. package/dist/lib/prisma.js +22 -3
  87. package/dist/lib/prisma.js.map +1 -1
  88. package/dist/lib/pusher.d.ts.map +1 -1
  89. package/dist/lib/pusher.js +8 -7
  90. package/dist/lib/pusher.js.map +1 -1
  91. package/dist/middleware/auth.d.ts.map +1 -1
  92. package/dist/middleware/auth.js +6 -5
  93. package/dist/middleware/auth.js.map +1 -1
  94. package/dist/middleware/security.d.ts +5 -0
  95. package/dist/middleware/security.d.ts.map +1 -0
  96. package/dist/middleware/security.js +77 -0
  97. package/dist/middleware/security.js.map +1 -0
  98. package/dist/routers/_app.d.ts +304 -98
  99. package/dist/routers/_app.d.ts.map +1 -1
  100. package/dist/routers/_app.js +4 -2
  101. package/dist/routers/_app.js.map +1 -1
  102. package/dist/routers/agenda.d.ts.map +1 -1
  103. package/dist/routers/agenda.js +12 -9
  104. package/dist/routers/agenda.js.map +1 -1
  105. package/dist/routers/announcement.d.ts +8 -0
  106. package/dist/routers/announcement.d.ts.map +1 -1
  107. package/dist/routers/announcement.js +6 -4
  108. package/dist/routers/announcement.js.map +1 -1
  109. package/dist/routers/assignment.d.ts +7 -4
  110. package/dist/routers/assignment.d.ts.map +1 -1
  111. package/dist/routers/assignment.js +35 -18
  112. package/dist/routers/assignment.js.map +1 -1
  113. package/dist/routers/attendance.d.ts +1 -0
  114. package/dist/routers/attendance.d.ts.map +1 -1
  115. package/dist/routers/attendance.js +4 -4
  116. package/dist/routers/attendance.js.map +1 -1
  117. package/dist/routers/auth.d.ts +20 -0
  118. package/dist/routers/auth.d.ts.map +1 -1
  119. package/dist/routers/auth.js +132 -15
  120. package/dist/routers/auth.js.map +1 -1
  121. package/dist/routers/class.d.ts +10 -0
  122. package/dist/routers/class.d.ts.map +1 -1
  123. package/dist/routers/class.js +49 -5
  124. package/dist/routers/class.js.map +1 -1
  125. package/dist/routers/comment.d.ts +7 -0
  126. package/dist/routers/comment.d.ts.map +1 -1
  127. package/dist/routers/comment.js +9 -2
  128. package/dist/routers/comment.js.map +1 -1
  129. package/dist/routers/conversation.d.ts +1 -0
  130. package/dist/routers/conversation.d.ts.map +1 -1
  131. package/dist/routers/conversation.js +46 -31
  132. package/dist/routers/conversation.js.map +1 -1
  133. package/dist/routers/file.d.ts.map +1 -1
  134. package/dist/routers/file.js +30 -7
  135. package/dist/routers/file.js.map +1 -1
  136. package/dist/routers/labChat.d.ts +1 -0
  137. package/dist/routers/labChat.d.ts.map +1 -1
  138. package/dist/routers/labChat.js +2 -3
  139. package/dist/routers/labChat.js.map +1 -1
  140. package/dist/routers/marketing.d.ts +1 -1
  141. package/dist/routers/newtonChat.d.ts +55 -0
  142. package/dist/routers/newtonChat.d.ts.map +1 -0
  143. package/dist/routers/newtonChat.js +438 -0
  144. package/dist/routers/newtonChat.js.map +1 -0
  145. package/dist/routers/notifications.d.ts +4 -4
  146. package/dist/routers/section.d.ts +9 -4
  147. package/dist/routers/section.d.ts.map +1 -1
  148. package/dist/routers/section.js +8 -8
  149. package/dist/routers/section.js.map +1 -1
  150. package/dist/routers/user.d.ts.map +1 -1
  151. package/dist/routers/user.js +5 -4
  152. package/dist/routers/user.js.map +1 -1
  153. package/dist/routers/worksheet.d.ts +30 -36
  154. package/dist/routers/worksheet.d.ts.map +1 -1
  155. package/dist/routers/worksheet.js +11 -33
  156. package/dist/routers/worksheet.js.map +1 -1
  157. package/dist/seedDatabase.d.ts +1 -1
  158. package/dist/seedDatabase.js +275 -284
  159. package/dist/seedDatabase.js.map +1 -1
  160. package/dist/server/pipelines/aiLabChat.d.ts +10 -0
  161. package/dist/server/pipelines/aiLabChat.d.ts.map +1 -0
  162. package/dist/server/pipelines/aiLabChat.js +83 -0
  163. package/dist/server/pipelines/aiLabChat.js.map +1 -0
  164. package/dist/server/pipelines/gradeWorksheet.d.ts +2 -0
  165. package/dist/server/pipelines/gradeWorksheet.d.ts.map +1 -0
  166. package/dist/server/pipelines/gradeWorksheet.js +138 -0
  167. package/dist/server/pipelines/gradeWorksheet.js.map +1 -0
  168. package/dist/trpc.d.ts.map +1 -1
  169. package/dist/trpc.js +2 -2
  170. package/dist/trpc.js.map +1 -1
  171. package/dist/utils/email.d.ts +9 -1
  172. package/dist/utils/email.d.ts.map +1 -1
  173. package/dist/utils/email.js +20 -5
  174. package/dist/utils/email.js.map +1 -1
  175. package/dist/utils/inference.d.ts +3 -0
  176. package/dist/utils/inference.d.ts.map +1 -1
  177. package/dist/utils/inference.js +41 -7
  178. package/dist/utils/inference.js.map +1 -1
  179. package/dist/utils/logger.d.ts.map +1 -1
  180. package/dist/utils/logger.js +3 -3
  181. package/dist/utils/logger.js.map +1 -1
  182. package/docker-compose.yml +14 -0
  183. package/package.json +13 -4
  184. package/prisma/schema.prisma +32 -5
  185. package/scripts/test-pre-push.ts +14 -0
  186. package/src/index.ts +98 -54
  187. package/src/instrument.ts +13 -6
  188. package/src/lib/config/env.ts +126 -0
  189. package/src/lib/fileUpload.ts +3 -2
  190. package/src/lib/googleCloudStorage.ts +6 -6
  191. package/src/lib/jsonConversion.ts +12 -14
  192. package/src/lib/prisma.ts +23 -2
  193. package/src/lib/pusher.ts +6 -5
  194. package/src/middleware/auth.ts +4 -3
  195. package/src/middleware/security.ts +80 -0
  196. package/src/routers/_app.ts +2 -0
  197. package/src/routers/agenda.ts +10 -7
  198. package/src/routers/announcement.ts +4 -2
  199. package/src/routers/assignment.ts +58 -40
  200. package/src/routers/attendance.ts +2 -2
  201. package/src/routers/auth.ts +143 -14
  202. package/src/routers/class.ts +52 -3
  203. package/src/routers/comment.ts +7 -0
  204. package/src/routers/conversation.ts +49 -29
  205. package/src/routers/file.ts +29 -5
  206. package/src/routers/labChat.ts +0 -1
  207. package/src/routers/newtonChat.ts +520 -0
  208. package/src/routers/section.ts +6 -6
  209. package/src/routers/user.ts +3 -2
  210. package/src/routers/worksheet.ts +9 -37
  211. package/src/seedDatabase.ts +290 -283
  212. package/src/server/pipelines/aiLabChat.ts +92 -0
  213. package/src/server/pipelines/gradeWorksheet.ts +152 -0
  214. package/src/trpc.ts +2 -0
  215. package/src/utils/email.ts +30 -3
  216. package/src/utils/inference.ts +50 -5
  217. package/src/utils/logger.ts +2 -1
  218. package/tests/announcement.test.ts +164 -0
  219. package/tests/assignment.test.ts +296 -0
  220. package/tests/attendance.test.ts +168 -0
  221. package/tests/auth.test.ts +33 -10
  222. package/tests/class.test.ts +34 -9
  223. package/tests/event.test.ts +228 -0
  224. package/tests/section.test.ts +216 -0
  225. package/tests/setup.ts +70 -16
  226. package/tests/user.test.ts +158 -0
  227. package/vitest.config.ts +26 -0
  228. package/API_SPECIFICATION.md +0 -1597
  229. package/BASE64_REMOVAL_SUMMARY.md +0 -164
  230. package/CHAT_API_SPEC.md +0 -579
  231. package/LAB_CHAT_API_SPEC.md +0 -518
  232. package/dist/routers/school.d.ts +0 -208
  233. package/dist/routers/school.d.ts.map +0 -1
  234. package/dist/routers/school.js +0 -483
package/.env.example ADDED
@@ -0,0 +1,45 @@
1
+ # Environment Configuration
2
+ # Copy this file to .env and fill in your values
3
+
4
+ # Database Configuration
5
+ # PostgreSQL connection string
6
+ DATABASE_URL="postgresql://postgres:password@localhost:5432/postgres"
7
+ DIRECT_URL="postgresql://postgres:password@localhost:5432/postgres"
8
+
9
+ # Application Configuration
10
+ # Frontend URL for CORS configuration
11
+ NEXT_PUBLIC_APP_URL="http://localhost:3000"
12
+ # Server port
13
+ PORT=3001
14
+ # Environment: development, test, production
15
+ NODE_ENV=development
16
+
17
+ # Logging Configuration
18
+ # Options: debug, info, warn, error
19
+ LOG_MODE=info
20
+
21
+ # Google Cloud Storage Configuration
22
+ # Required for file uploads and storage
23
+ GOOGLE_CLOUD_PROJECT_ID="your-project-id"
24
+ GOOGLE_CLOUD_CLIENT_EMAIL="your-service-account@your-project.iam.gserviceaccount.com"
25
+ GOOGLE_CLOUD_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----
26
+ YOUR_PRIVATE_KEY
27
+ -----END PRIVATE KEY-----"
28
+ GOOGLE_CLOUD_BUCKET_NAME="your-bucket-name"
29
+
30
+ # Pusher Configuration
31
+ # Required for real-time notifications
32
+ PUSHER_APP_ID="your-app-id"
33
+ PUSHER_KEY="your-key"
34
+ PUSHER_SECRET="your-secret"
35
+ PUSHER_CLUSTER="your-cluster"
36
+
37
+ # AI/Inference Configuration
38
+ # Required for AI features (lab chat, etc.)
39
+ INFERENCE_API_KEY="your-api-key"
40
+ INFERENCE_API_BASE_URL="https://api.openai.com/v1"
41
+
42
+ # Sentry Configuration
43
+ # Required for error tracking and monitoring
44
+ SENTRY_AUTH_TOKEN="your-auth-token"
45
+ SENTRY_DSN="https://your-key@your-org.ingest.sentry.io/your-project"
@@ -0,0 +1,37 @@
1
+ # Test Environment Configuration
2
+ # Copy this file to .env.test and fill in your test values
3
+
4
+ # Database Configuration (use a separate test database)
5
+ DATABASE_URL="postgresql://postgres:password@localhost:5434/postgres"
6
+ DIRECT_URL="postgresql://postgres:password@localhost:5434/postgres"
7
+
8
+ # Application Configuration
9
+ NEXT_PUBLIC_APP_URL="http://localhost:3000"
10
+ PORT=3002
11
+ NODE_ENV=test
12
+
13
+ # Logging Configuration
14
+ # Options: debug, info, warn, error
15
+ LOG_MODE=error
16
+
17
+ # Google Cloud Storage (optional for tests - can use mock/local storage)
18
+ GOOGLE_CLOUD_PROJECT_ID="your-test-project-id"
19
+ GOOGLE_CLOUD_CLIENT_EMAIL="test@test-project.iam.gserviceaccount.com"
20
+ GOOGLE_CLOUD_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----
21
+ YOUR_TEST_PRIVATE_KEY
22
+ -----END PRIVATE KEY-----"
23
+ GOOGLE_CLOUD_BUCKET_NAME="test-bucket-name"
24
+
25
+ # Pusher Configuration (optional for tests - can be mocked)
26
+ PUSHER_APP_ID="test-app-id"
27
+ PUSHER_KEY="test-key"
28
+ PUSHER_SECRET="test-secret"
29
+ PUSHER_CLUSTER="us2"
30
+
31
+ # AI/Inference Configuration (optional for tests - should be mocked)
32
+ INFERENCE_API_KEY="test-api-key"
33
+ INFERENCE_API_BASE_URL="http://localhost:11434/v1"
34
+
35
+ # Sentry Configuration (disabled for tests)
36
+ SENTRY_AUTH_TOKEN="test-auth-token"
37
+ SENTRY_DSN="https://test@test.ingest.sentry.io/test"
package/README.md CHANGED
@@ -34,14 +34,11 @@ This is the backend server for the Studious application. It provides a RESTful a
34
34
  ```
35
35
 
36
36
  3. **Set up environment variables:**
37
- Create a `.env` file in the root directory with the following variables:
38
- ```env
39
- DATABASE_URL="postgresql://username:password@localhost:5432/easy_lms"
40
- PORT=3001
41
- NEXT_PUBLIC_APP_URL=http://localhost:3000
42
- NODE_ENV=development
43
- LOG_MODE=info
37
+ Copy the example environment file and update with your values:
38
+ ```bash
39
+ cp .env.example .env
44
40
  ```
41
+ Then edit `.env` with your configuration. See `.env.example` for all required variables.
45
42
 
46
43
  4. **Set up the database:**
47
44
  - Create a PostgreSQL database named `easy_lms`
@@ -119,6 +116,10 @@ npx prisma studio
119
116
  - `npm run dev` — Start in development mode with hot reload
120
117
  - `npm run build` — Compile TypeScript to JavaScript
121
118
  - `npm start` — Start the compiled server
119
+ - `npm test` — Run tests with Vitest
120
+ - `npm run test:run` — Run tests once
121
+ - `npm run test:watch` — Run tests in watch mode
122
+ - `npm run test:coverage` — Run tests with coverage report
122
123
 
123
124
  ## Environment Variables
124
125
 
@@ -138,6 +139,32 @@ The server uses TypeScript and includes:
138
139
  - **Prisma** for database operations
139
140
  - **Express** middleware for CORS and logging
140
141
 
142
+ ### Testing
143
+
144
+ Tests use a separate environment configuration:
145
+
146
+ 1. **Set up test environment:**
147
+ ```bash
148
+ cp .env.test.example .env.test
149
+ ```
150
+ Update `.env.test` with your test database configuration.
151
+
152
+ 2. **Create test database:**
153
+ ```bash
154
+ createdb easy_lms_test
155
+ ```
156
+
157
+ 3. **Run tests:**
158
+ ```bash
159
+ npm test
160
+ ```
161
+
162
+ The test environment:
163
+ - Uses a separate database (`easy_lms_test`)
164
+ - Runs on a different port (3002)
165
+ - Has minimal logging (error level only)
166
+ - Mocks external services (Google Cloud, Pusher, etc.)
167
+
141
168
  ## License
142
169
 
143
170
  [MIT](LICENSE.txt)
@@ -0,0 +1,224 @@
1
+ body, html {
2
+ margin:0; padding: 0;
3
+ height: 100%;
4
+ }
5
+ body {
6
+ font-family: Helvetica Neue, Helvetica, Arial;
7
+ font-size: 14px;
8
+ color:#333;
9
+ }
10
+ .small { font-size: 12px; }
11
+ *, *:after, *:before {
12
+ -webkit-box-sizing:border-box;
13
+ -moz-box-sizing:border-box;
14
+ box-sizing:border-box;
15
+ }
16
+ h1 { font-size: 20px; margin: 0;}
17
+ h2 { font-size: 14px; }
18
+ pre {
19
+ font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace;
20
+ margin: 0;
21
+ padding: 0;
22
+ -moz-tab-size: 2;
23
+ -o-tab-size: 2;
24
+ tab-size: 2;
25
+ }
26
+ a { color:#0074D9; text-decoration:none; }
27
+ a:hover { text-decoration:underline; }
28
+ .strong { font-weight: bold; }
29
+ .space-top1 { padding: 10px 0 0 0; }
30
+ .pad2y { padding: 20px 0; }
31
+ .pad1y { padding: 10px 0; }
32
+ .pad2x { padding: 0 20px; }
33
+ .pad2 { padding: 20px; }
34
+ .pad1 { padding: 10px; }
35
+ .space-left2 { padding-left:55px; }
36
+ .space-right2 { padding-right:20px; }
37
+ .center { text-align:center; }
38
+ .clearfix { display:block; }
39
+ .clearfix:after {
40
+ content:'';
41
+ display:block;
42
+ height:0;
43
+ clear:both;
44
+ visibility:hidden;
45
+ }
46
+ .fl { float: left; }
47
+ @media only screen and (max-width:640px) {
48
+ .col3 { width:100%; max-width:100%; }
49
+ .hide-mobile { display:none!important; }
50
+ }
51
+
52
+ .quiet {
53
+ color: #7f7f7f;
54
+ color: rgba(0,0,0,0.5);
55
+ }
56
+ .quiet a { opacity: 0.7; }
57
+
58
+ .fraction {
59
+ font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace;
60
+ font-size: 10px;
61
+ color: #555;
62
+ background: #E8E8E8;
63
+ padding: 4px 5px;
64
+ border-radius: 3px;
65
+ vertical-align: middle;
66
+ }
67
+
68
+ div.path a:link, div.path a:visited { color: #333; }
69
+ table.coverage {
70
+ border-collapse: collapse;
71
+ margin: 10px 0 0 0;
72
+ padding: 0;
73
+ }
74
+
75
+ table.coverage td {
76
+ margin: 0;
77
+ padding: 0;
78
+ vertical-align: top;
79
+ }
80
+ table.coverage td.line-count {
81
+ text-align: right;
82
+ padding: 0 5px 0 20px;
83
+ }
84
+ table.coverage td.line-coverage {
85
+ text-align: right;
86
+ padding-right: 10px;
87
+ min-width:20px;
88
+ }
89
+
90
+ table.coverage td span.cline-any {
91
+ display: inline-block;
92
+ padding: 0 5px;
93
+ width: 100%;
94
+ }
95
+ .missing-if-branch {
96
+ display: inline-block;
97
+ margin-right: 5px;
98
+ border-radius: 3px;
99
+ position: relative;
100
+ padding: 0 4px;
101
+ background: #333;
102
+ color: yellow;
103
+ }
104
+
105
+ .skip-if-branch {
106
+ display: none;
107
+ margin-right: 10px;
108
+ position: relative;
109
+ padding: 0 4px;
110
+ background: #ccc;
111
+ color: white;
112
+ }
113
+ .missing-if-branch .typ, .skip-if-branch .typ {
114
+ color: inherit !important;
115
+ }
116
+ .coverage-summary {
117
+ border-collapse: collapse;
118
+ width: 100%;
119
+ }
120
+ .coverage-summary tr { border-bottom: 1px solid #bbb; }
121
+ .keyline-all { border: 1px solid #ddd; }
122
+ .coverage-summary td, .coverage-summary th { padding: 10px; }
123
+ .coverage-summary tbody { border: 1px solid #bbb; }
124
+ .coverage-summary td { border-right: 1px solid #bbb; }
125
+ .coverage-summary td:last-child { border-right: none; }
126
+ .coverage-summary th {
127
+ text-align: left;
128
+ font-weight: normal;
129
+ white-space: nowrap;
130
+ }
131
+ .coverage-summary th.file { border-right: none !important; }
132
+ .coverage-summary th.pct { }
133
+ .coverage-summary th.pic,
134
+ .coverage-summary th.abs,
135
+ .coverage-summary td.pct,
136
+ .coverage-summary td.abs { text-align: right; }
137
+ .coverage-summary td.file { white-space: nowrap; }
138
+ .coverage-summary td.pic { min-width: 120px !important; }
139
+ .coverage-summary tfoot td { }
140
+
141
+ .coverage-summary .sorter {
142
+ height: 10px;
143
+ width: 7px;
144
+ display: inline-block;
145
+ margin-left: 0.5em;
146
+ background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent;
147
+ }
148
+ .coverage-summary .sorted .sorter {
149
+ background-position: 0 -20px;
150
+ }
151
+ .coverage-summary .sorted-desc .sorter {
152
+ background-position: 0 -10px;
153
+ }
154
+ .status-line { height: 10px; }
155
+ /* yellow */
156
+ .cbranch-no { background: yellow !important; color: #111; }
157
+ /* dark red */
158
+ .red.solid, .status-line.low, .low .cover-fill { background:#C21F39 }
159
+ .low .chart { border:1px solid #C21F39 }
160
+ .highlighted,
161
+ .highlighted .cstat-no, .highlighted .fstat-no, .highlighted .cbranch-no{
162
+ background: #C21F39 !important;
163
+ }
164
+ /* medium red */
165
+ .cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE }
166
+ /* light red */
167
+ .low, .cline-no { background:#FCE1E5 }
168
+ /* light green */
169
+ .high, .cline-yes { background:rgb(230,245,208) }
170
+ /* medium green */
171
+ .cstat-yes { background:rgb(161,215,106) }
172
+ /* dark green */
173
+ .status-line.high, .high .cover-fill { background:rgb(77,146,33) }
174
+ .high .chart { border:1px solid rgb(77,146,33) }
175
+ /* dark yellow (gold) */
176
+ .status-line.medium, .medium .cover-fill { background: #f9cd0b; }
177
+ .medium .chart { border:1px solid #f9cd0b; }
178
+ /* light yellow */
179
+ .medium { background: #fff4c2; }
180
+
181
+ .cstat-skip { background: #ddd; color: #111; }
182
+ .fstat-skip { background: #ddd; color: #111 !important; }
183
+ .cbranch-skip { background: #ddd !important; color: #111; }
184
+
185
+ span.cline-neutral { background: #eaeaea; }
186
+
187
+ .coverage-summary td.empty {
188
+ opacity: .5;
189
+ padding-top: 4px;
190
+ padding-bottom: 4px;
191
+ line-height: 1;
192
+ color: #888;
193
+ }
194
+
195
+ .cover-fill, .cover-empty {
196
+ display:inline-block;
197
+ height: 12px;
198
+ }
199
+ .chart {
200
+ line-height: 0;
201
+ }
202
+ .cover-empty {
203
+ background: white;
204
+ }
205
+ .cover-full {
206
+ border-right: none !important;
207
+ }
208
+ pre.prettyprint {
209
+ border: none !important;
210
+ padding: 0 !important;
211
+ margin: 0 !important;
212
+ }
213
+ .com { color: #999 !important; }
214
+ .ignore-none { color: #999; font-weight: normal; }
215
+
216
+ .wrapper {
217
+ min-height: 100%;
218
+ height: auto !important;
219
+ height: 100%;
220
+ margin: 0 auto -48px;
221
+ }
222
+ .footer, .push {
223
+ height: 48px;
224
+ }
@@ -0,0 +1,87 @@
1
+ /* eslint-disable */
2
+ var jumpToCode = (function init() {
3
+ // Classes of code we would like to highlight in the file view
4
+ var missingCoverageClasses = ['.cbranch-no', '.cstat-no', '.fstat-no'];
5
+
6
+ // Elements to highlight in the file listing view
7
+ var fileListingElements = ['td.pct.low'];
8
+
9
+ // We don't want to select elements that are direct descendants of another match
10
+ var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > `
11
+
12
+ // Selector that finds elements on the page to which we can jump
13
+ var selector =
14
+ fileListingElements.join(', ') +
15
+ ', ' +
16
+ notSelector +
17
+ missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b`
18
+
19
+ // The NodeList of matching elements
20
+ var missingCoverageElements = document.querySelectorAll(selector);
21
+
22
+ var currentIndex;
23
+
24
+ function toggleClass(index) {
25
+ missingCoverageElements
26
+ .item(currentIndex)
27
+ .classList.remove('highlighted');
28
+ missingCoverageElements.item(index).classList.add('highlighted');
29
+ }
30
+
31
+ function makeCurrent(index) {
32
+ toggleClass(index);
33
+ currentIndex = index;
34
+ missingCoverageElements.item(index).scrollIntoView({
35
+ behavior: 'smooth',
36
+ block: 'center',
37
+ inline: 'center'
38
+ });
39
+ }
40
+
41
+ function goToPrevious() {
42
+ var nextIndex = 0;
43
+ if (typeof currentIndex !== 'number' || currentIndex === 0) {
44
+ nextIndex = missingCoverageElements.length - 1;
45
+ } else if (missingCoverageElements.length > 1) {
46
+ nextIndex = currentIndex - 1;
47
+ }
48
+
49
+ makeCurrent(nextIndex);
50
+ }
51
+
52
+ function goToNext() {
53
+ var nextIndex = 0;
54
+
55
+ if (
56
+ typeof currentIndex === 'number' &&
57
+ currentIndex < missingCoverageElements.length - 1
58
+ ) {
59
+ nextIndex = currentIndex + 1;
60
+ }
61
+
62
+ makeCurrent(nextIndex);
63
+ }
64
+
65
+ return function jump(event) {
66
+ if (
67
+ document.getElementById('fileSearch') === document.activeElement &&
68
+ document.activeElement != null
69
+ ) {
70
+ // if we're currently focused on the search input, we don't want to navigate
71
+ return;
72
+ }
73
+
74
+ switch (event.which) {
75
+ case 78: // n
76
+ case 74: // j
77
+ goToNext();
78
+ break;
79
+ case 66: // b
80
+ case 75: // k
81
+ case 80: // p
82
+ goToPrevious();
83
+ break;
84
+ }
85
+ };
86
+ })();
87
+ window.addEventListener('keydown', jumpToCode);