@girder/core 5.0.0-beta.1 → 5.0.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.
Files changed (238) hide show
  1. package/dist-lib/Girder_Favicon.png +0 -0
  2. package/dist-lib/Girder_Mark.png +0 -0
  3. package/dist-lib/girder-core.css +2 -0
  4. package/dist-lib/girder-core.js +60421 -0
  5. package/dist-lib/girder-core.js.map +1 -0
  6. package/dist-lib/girder-core.umd.cjs +1484 -0
  7. package/dist-lib/girder-core.umd.cjs.map +1 -0
  8. package/dist-lib/index.d.ts +1 -0
  9. package/dist-lib/src/auth.js +112 -0
  10. package/dist-lib/src/collections/ApiKeyCollection.js +9 -0
  11. package/dist-lib/src/collections/AssetstoreCollection.js +10 -0
  12. package/dist-lib/src/collections/Collection.js +295 -0
  13. package/dist-lib/src/collections/CollectionCollection.js +9 -0
  14. package/dist-lib/src/collections/FileCollection.js +11 -0
  15. package/dist-lib/src/collections/FolderCollection.js +11 -0
  16. package/dist-lib/src/collections/GroupCollection.js +9 -0
  17. package/dist-lib/src/collections/ItemCollection.js +11 -0
  18. package/dist-lib/src/collections/UserCollection.js +24 -0
  19. package/dist-lib/src/collections/index.js +21 -0
  20. package/dist-lib/src/constants.js +32 -0
  21. package/dist-lib/src/dialog.js +128 -0
  22. package/dist-lib/src/events.js +6 -0
  23. package/dist-lib/src/index.ts +80 -0
  24. package/dist-lib/src/main.ts +61 -0
  25. package/dist-lib/src/misc.js +260 -0
  26. package/dist-lib/src/models/AccessControlledModel.js +76 -0
  27. package/dist-lib/src/models/ApiKeyModel.js +31 -0
  28. package/dist-lib/src/models/AssetstoreModel.js +43 -0
  29. package/dist-lib/src/models/CollectionCreationPolicyModel.js +20 -0
  30. package/dist-lib/src/models/CollectionModel.js +12 -0
  31. package/dist-lib/src/models/FileModel.js +310 -0
  32. package/dist-lib/src/models/FolderModel.js +33 -0
  33. package/dist-lib/src/models/GroupModel.js +197 -0
  34. package/dist-lib/src/models/ItemModel.js +72 -0
  35. package/dist-lib/src/models/MetadataMixin.js +88 -0
  36. package/dist-lib/src/models/Model.js +187 -0
  37. package/dist-lib/src/models/UserModel.js +189 -0
  38. package/dist-lib/src/models/index.js +25 -0
  39. package/dist-lib/src/pluginUtils.js +11 -0
  40. package/dist-lib/src/rest.js +221 -0
  41. package/dist-lib/src/router.js +58 -0
  42. package/dist-lib/src/routes.js +229 -0
  43. package/dist-lib/src/stylesheets/apidocs/apidocs.styl +50 -0
  44. package/dist-lib/src/stylesheets/body/adminConsole.styl +21 -0
  45. package/dist-lib/src/stylesheets/body/assetstores.styl +46 -0
  46. package/dist-lib/src/stylesheets/body/collectionList.styl +39 -0
  47. package/dist-lib/src/stylesheets/body/collectionPage.styl +6 -0
  48. package/dist-lib/src/stylesheets/body/frontPage.styl +48 -0
  49. package/dist-lib/src/stylesheets/body/groupList.styl +43 -0
  50. package/dist-lib/src/stylesheets/body/groupPage.styl +116 -0
  51. package/dist-lib/src/stylesheets/body/itemPage.styl +81 -0
  52. package/dist-lib/src/stylesheets/body/plugins.styl +61 -0
  53. package/dist-lib/src/stylesheets/body/searchResultsList.styl +51 -0
  54. package/dist-lib/src/stylesheets/body/systemConfig.styl +56 -0
  55. package/dist-lib/src/stylesheets/body/userAccount.styl +57 -0
  56. package/dist-lib/src/stylesheets/body/userList.styl +79 -0
  57. package/dist-lib/src/stylesheets/body/userPage.styl +6 -0
  58. package/dist-lib/src/stylesheets/layout/footer.styl +19 -0
  59. package/dist-lib/src/stylesheets/layout/global.styl +154 -0
  60. package/dist-lib/src/stylesheets/layout/globalNav.styl +89 -0
  61. package/dist-lib/src/stylesheets/layout/header.styl +29 -0
  62. package/dist-lib/src/stylesheets/layout/headerUser.styl +33 -0
  63. package/dist-lib/src/stylesheets/layout/layout.styl +75 -0
  64. package/dist-lib/src/stylesheets/layout/layoutVars.styl +9 -0
  65. package/dist-lib/src/stylesheets/layout/loading.styl +37 -0
  66. package/dist-lib/src/stylesheets/layout/progressArea.styl +17 -0
  67. package/dist-lib/src/stylesheets/widgets/accessWidget.styl +106 -0
  68. package/dist-lib/src/stylesheets/widgets/browserWidget.styl +9 -0
  69. package/dist-lib/src/stylesheets/widgets/hierarchyWidget.styl +188 -0
  70. package/dist-lib/src/stylesheets/widgets/markdownWidget.styl +92 -0
  71. package/dist-lib/src/stylesheets/widgets/metadataWidget.styl +92 -0
  72. package/dist-lib/src/stylesheets/widgets/searchFieldWidget.styl +70 -0
  73. package/dist-lib/src/stylesheets/widgets/taskProgress.styl +41 -0
  74. package/dist-lib/src/stylesheets/widgets/timelineWidget.styl +41 -0
  75. package/dist-lib/src/stylesheets/widgets/uploadWidget.styl +43 -0
  76. package/dist-lib/src/stylesheets/widgets/userOtpManagementWidget.styl +159 -0
  77. package/dist-lib/src/templates/body/adminConsole.pug +13 -0
  78. package/dist-lib/src/templates/body/assetstores.pug +83 -0
  79. package/dist-lib/src/templates/body/collectionList.pug +40 -0
  80. package/dist-lib/src/templates/body/collectionPage.pug +36 -0
  81. package/dist-lib/src/templates/body/filesystemImport.pug +41 -0
  82. package/dist-lib/src/templates/body/frontPage.pug +83 -0
  83. package/dist-lib/src/templates/body/groupList.pug +30 -0
  84. package/dist-lib/src/templates/body/groupPage.pug +116 -0
  85. package/dist-lib/src/templates/body/itemPage.pug +61 -0
  86. package/dist-lib/src/templates/body/plugins.pug +20 -0
  87. package/dist-lib/src/templates/body/s3Import.pug +35 -0
  88. package/dist-lib/src/templates/body/searchResults.pug +15 -0
  89. package/dist-lib/src/templates/body/searchResultsType.pug +13 -0
  90. package/dist-lib/src/templates/body/systemConfiguration.pug +215 -0
  91. package/dist-lib/src/templates/body/userAccount.pug +83 -0
  92. package/dist-lib/src/templates/body/userList.pug +43 -0
  93. package/dist-lib/src/templates/body/userPage.pug +40 -0
  94. package/dist-lib/src/templates/layout/alert.pug +5 -0
  95. package/dist-lib/src/templates/layout/layout.pug +12 -0
  96. package/dist-lib/src/templates/layout/layoutFooter.pug +11 -0
  97. package/dist-lib/src/templates/layout/layoutGlobalNav.pug +7 -0
  98. package/dist-lib/src/templates/layout/layoutHeader.pug +8 -0
  99. package/dist-lib/src/templates/layout/layoutHeaderUser.pug +26 -0
  100. package/dist-lib/src/templates/layout/layoutProgressArea.pug +1 -0
  101. package/dist-lib/src/templates/layout/loginDialog.pug +30 -0
  102. package/dist-lib/src/templates/layout/registerDialog.pug +35 -0
  103. package/dist-lib/src/templates/layout/resetPasswordDialog.pug +25 -0
  104. package/dist-lib/src/templates/widgets/accessEditor.pug +23 -0
  105. package/dist-lib/src/templates/widgets/accessEditorMixins.pug +57 -0
  106. package/dist-lib/src/templates/widgets/accessEditorNonModal.pug +11 -0
  107. package/dist-lib/src/templates/widgets/accessEntry.pug +32 -0
  108. package/dist-lib/src/templates/widgets/apiKeyList.pug +50 -0
  109. package/dist-lib/src/templates/widgets/browserWidget.pug +32 -0
  110. package/dist-lib/src/templates/widgets/checkedActionsMenu.pug +46 -0
  111. package/dist-lib/src/templates/widgets/collectionInfoDialog.pug +37 -0
  112. package/dist-lib/src/templates/widgets/confirmDialog.pug +14 -0
  113. package/dist-lib/src/templates/widgets/dateTimeRangeWidget.pug +20 -0
  114. package/dist-lib/src/templates/widgets/dateTimeWidget.pug +8 -0
  115. package/dist-lib/src/templates/widgets/editApiKeyWidget.pug +43 -0
  116. package/dist-lib/src/templates/widgets/editAssetstoreWidget.pug +70 -0
  117. package/dist-lib/src/templates/widgets/editCollectionWidget.pug +27 -0
  118. package/dist-lib/src/templates/widgets/editFileWidget.pug +21 -0
  119. package/dist-lib/src/templates/widgets/editFolderWidget.pug +27 -0
  120. package/dist-lib/src/templates/widgets/editGroupWidget.pug +54 -0
  121. package/dist-lib/src/templates/widgets/editItemWidget.pug +27 -0
  122. package/dist-lib/src/templates/widgets/fileInfoDialog.pug +33 -0
  123. package/dist-lib/src/templates/widgets/fileList.pug +33 -0
  124. package/dist-lib/src/templates/widgets/folderInfoDialog.pug +42 -0
  125. package/dist-lib/src/templates/widgets/folderList.pug +21 -0
  126. package/dist-lib/src/templates/widgets/groupAdminList.pug +33 -0
  127. package/dist-lib/src/templates/widgets/groupInviteDialog.pug +76 -0
  128. package/dist-lib/src/templates/widgets/groupInviteList.pug +14 -0
  129. package/dist-lib/src/templates/widgets/groupMemberList.pug +39 -0
  130. package/dist-lib/src/templates/widgets/groupModList.pug +23 -0
  131. package/dist-lib/src/templates/widgets/hierarchyBreadcrumb.pug +37 -0
  132. package/dist-lib/src/templates/widgets/hierarchyPaginated.pug +19 -0
  133. package/dist-lib/src/templates/widgets/hierarchyWidget.pug +96 -0
  134. package/dist-lib/src/templates/widgets/itemBreadcrumb.pug +16 -0
  135. package/dist-lib/src/templates/widgets/itemList.pug +27 -0
  136. package/dist-lib/src/templates/widgets/jsonMetadatumEditWidget.pug +13 -0
  137. package/dist-lib/src/templates/widgets/jsonMetadatumView.pug +6 -0
  138. package/dist-lib/src/templates/widgets/loadingAnimation.pug +4 -0
  139. package/dist-lib/src/templates/widgets/markdownWidget.pug +34 -0
  140. package/dist-lib/src/templates/widgets/metadataWidget.pug +16 -0
  141. package/dist-lib/src/templates/widgets/metadatumEditWidget.pug +15 -0
  142. package/dist-lib/src/templates/widgets/metadatumView.pug +5 -0
  143. package/dist-lib/src/templates/widgets/newAssetstore.pug +87 -0
  144. package/dist-lib/src/templates/widgets/paginateWidget.pug +7 -0
  145. package/dist-lib/src/templates/widgets/pluginConfigBreadcrumb.pug +13 -0
  146. package/dist-lib/src/templates/widgets/rootSelectorWidget.pug +13 -0
  147. package/dist-lib/src/templates/widgets/searchField.pug +10 -0
  148. package/dist-lib/src/templates/widgets/searchHelp.pug +12 -0
  149. package/dist-lib/src/templates/widgets/searchModeSelect.pug +9 -0
  150. package/dist-lib/src/templates/widgets/searchResults.pug +14 -0
  151. package/dist-lib/src/templates/widgets/sortCollectionWidget.pug +14 -0
  152. package/dist-lib/src/templates/widgets/taskProgress.pug +16 -0
  153. package/dist-lib/src/templates/widgets/timeline.pug +15 -0
  154. package/dist-lib/src/templates/widgets/uploadWidget.pug +15 -0
  155. package/dist-lib/src/templates/widgets/uploadWidgetMixins.pug +31 -0
  156. package/dist-lib/src/templates/widgets/uploadWidgetNonModal.pug +10 -0
  157. package/dist-lib/src/templates/widgets/userOtpBegin.pug +4 -0
  158. package/dist-lib/src/templates/widgets/userOtpDisable.pug +6 -0
  159. package/dist-lib/src/templates/widgets/userOtpEnable.pug +44 -0
  160. package/dist-lib/src/utilities/EventStream.js +119 -0
  161. package/dist-lib/src/utilities/PluginUtils.js +36 -0
  162. package/dist-lib/src/utilities/S3UploadHandler.js +263 -0
  163. package/dist-lib/src/utilities/index.js +9 -0
  164. package/dist-lib/src/utilities/jquery/girderEnable.js +19 -0
  165. package/dist-lib/src/utilities/jquery/girderModal.js +48 -0
  166. package/dist-lib/src/version.js +6 -0
  167. package/dist-lib/src/views/App.js +359 -0
  168. package/dist-lib/src/views/View.js +79 -0
  169. package/dist-lib/src/views/body/AdminView.js +29 -0
  170. package/dist-lib/src/views/body/AssetstoresView.js +233 -0
  171. package/dist-lib/src/views/body/CollectionView.js +188 -0
  172. package/dist-lib/src/views/body/CollectionsView.js +120 -0
  173. package/dist-lib/src/views/body/FilesystemImportView.js +83 -0
  174. package/dist-lib/src/views/body/FolderView.js +54 -0
  175. package/dist-lib/src/views/body/FrontPageView.js +47 -0
  176. package/dist-lib/src/views/body/GroupView.js +336 -0
  177. package/dist-lib/src/views/body/GroupsView.js +106 -0
  178. package/dist-lib/src/views/body/ItemView.js +177 -0
  179. package/dist-lib/src/views/body/PluginsView.js +73 -0
  180. package/dist-lib/src/views/body/S3ImportView.js +80 -0
  181. package/dist-lib/src/views/body/SearchResultsView.js +162 -0
  182. package/dist-lib/src/views/body/SystemConfigurationView.js +177 -0
  183. package/dist-lib/src/views/body/UserAccountView.js +179 -0
  184. package/dist-lib/src/views/body/UserView.js +165 -0
  185. package/dist-lib/src/views/body/UsersView.js +124 -0
  186. package/dist-lib/src/views/body/index.js +38 -0
  187. package/dist-lib/src/views/index.js +13 -0
  188. package/dist-lib/src/views/layout/FooterView.js +29 -0
  189. package/dist-lib/src/views/layout/GlobalNavView.js +103 -0
  190. package/dist-lib/src/views/layout/HeaderUserView.js +45 -0
  191. package/dist-lib/src/views/layout/HeaderView.js +83 -0
  192. package/dist-lib/src/views/layout/LoginView.js +100 -0
  193. package/dist-lib/src/views/layout/ProgressListView.js +70 -0
  194. package/dist-lib/src/views/layout/RegisterView.js +101 -0
  195. package/dist-lib/src/views/layout/ResetPasswordView.js +70 -0
  196. package/dist-lib/src/views/layout/index.js +19 -0
  197. package/dist-lib/src/views/widgets/AccessWidget.js +427 -0
  198. package/dist-lib/src/views/widgets/ApiKeyListWidget.js +140 -0
  199. package/dist-lib/src/views/widgets/BrowserWidget.js +317 -0
  200. package/dist-lib/src/views/widgets/CheckedMenuWidget.js +68 -0
  201. package/dist-lib/src/views/widgets/CollectionInfoWidget.js +40 -0
  202. package/dist-lib/src/views/widgets/DateTimeRangeWidget.js +180 -0
  203. package/dist-lib/src/views/widgets/DateTimeWidget.js +110 -0
  204. package/dist-lib/src/views/widgets/EditApiKeyWidget.js +124 -0
  205. package/dist-lib/src/views/widgets/EditAssetstoreWidget.js +136 -0
  206. package/dist-lib/src/views/widgets/EditCollectionWidget.js +93 -0
  207. package/dist-lib/src/views/widgets/EditFileWidget.js +56 -0
  208. package/dist-lib/src/views/widgets/EditFolderWidget.js +116 -0
  209. package/dist-lib/src/views/widgets/EditGroupWidget.js +125 -0
  210. package/dist-lib/src/views/widgets/EditItemWidget.js +110 -0
  211. package/dist-lib/src/views/widgets/FileInfoWidget.js +26 -0
  212. package/dist-lib/src/views/widgets/FileListWidget.js +151 -0
  213. package/dist-lib/src/views/widgets/FolderInfoWidget.js +39 -0
  214. package/dist-lib/src/views/widgets/FolderListWidget.js +106 -0
  215. package/dist-lib/src/views/widgets/GroupAdminsWidget.js +88 -0
  216. package/dist-lib/src/views/widgets/GroupInvitesWidget.js +56 -0
  217. package/dist-lib/src/views/widgets/GroupMembersWidget.js +185 -0
  218. package/dist-lib/src/views/widgets/GroupModsWidget.js +77 -0
  219. package/dist-lib/src/views/widgets/HierarchyWidget.js +1097 -0
  220. package/dist-lib/src/views/widgets/ItemBreadcrumbWidget.js +38 -0
  221. package/dist-lib/src/views/widgets/ItemListWidget.js +345 -0
  222. package/dist-lib/src/views/widgets/LoadingAnimation.js +17 -0
  223. package/dist-lib/src/views/widgets/MarkdownWidget.js +217 -0
  224. package/dist-lib/src/views/widgets/MetadataWidget.js +508 -0
  225. package/dist-lib/src/views/widgets/NewAssetstoreWidget.js +72 -0
  226. package/dist-lib/src/views/widgets/PaginateWidget.js +37 -0
  227. package/dist-lib/src/views/widgets/PluginConfigBreadcrumbWidget.js +33 -0
  228. package/dist-lib/src/views/widgets/RootSelectorWidget.js +192 -0
  229. package/dist-lib/src/views/widgets/SearchFieldWidget.js +365 -0
  230. package/dist-lib/src/views/widgets/SearchPaginateWidget.js +149 -0
  231. package/dist-lib/src/views/widgets/SortCollectionWidget.js +53 -0
  232. package/dist-lib/src/views/widgets/TaskProgressWidget.js +91 -0
  233. package/dist-lib/src/views/widgets/TimelineWidget.js +155 -0
  234. package/dist-lib/src/views/widgets/UploadWidget.js +340 -0
  235. package/dist-lib/src/views/widgets/UserOtpManagementWidget.js +105 -0
  236. package/dist-lib/src/views/widgets/index.js +81 -0
  237. package/dist-lib/src/vite-env.d.ts +5 -0
  238. package/package.json +17 -15
@@ -0,0 +1,14 @@
1
+ each result in results
2
+ li.g-search-result
3
+ a.g-search-result-element(data-resource-id=result.id, data-resource-type=result.type, data-resource-icon=result.icon, tabindex="-1")
4
+ i(class=`icon-${result.icon}`)
5
+ | #{result.text}
6
+ if results.length === 0
7
+ li.g-no-search-results.disabled
8
+ a(tabindex="-1")
9
+ i.icon-block
10
+ | No results found
11
+ else
12
+ li.g-search-result
13
+ a.g-search-result-page-link(data-resource-type="resultPage")
14
+ | ...
@@ -0,0 +1,14 @@
1
+ .btn-group
2
+ a.g-sort-order-button.g-up.btn.btn-sm(title="Sort order")
3
+ i.icon-sort-name-up
4
+ a.g-sort-order-button.g-down.btn.btn-sm(title="Sort order")
5
+ i.icon-sort-name-down
6
+ button.g-collection-sort-actions.btn.btn-sm.btn-default.dropdown-toggle(
7
+ data-toggle="dropdown", title="Sort by Field")
8
+ | Sort by
9
+ i.icon-down-dir
10
+ ul.g-collection-sort-menu.dropdown-menu(role="menu")
11
+ each fieldName, field in fields
12
+ li(role="presentation")
13
+ a.g-collection-sort-link(role="menuitem", g-sort=field)
14
+ = fieldName
@@ -0,0 +1,16 @@
1
+ .g-task-progress-top
2
+ .g-task-progress-bar.progress(class=progressClass)
3
+ .progress-bar(class=barClass, style=`width: ${width};`)
4
+ .progress-status
5
+ .progress-percent
6
+ = percentText
7
+ .progress-left
8
+ = timeLeftText
9
+ .g-task-progress-title(title=progress.data.title)
10
+ if progress.data.resource && progress.data.resource._id && progress.data.resourceName
11
+ a(title=progress.data.title, href='#' + progress.data.resourceName + '/' + progress.data.resource._id)
12
+ = progress.data.title
13
+ else
14
+ = progress.data.title
15
+ .g-task-progress-bottom
16
+ .g-task-progress-message= progress.data.message
@@ -0,0 +1,15 @@
1
+ .g-timeline-widget-wrapper
2
+ .g-timeline-container
3
+ each segment in segments
4
+ .g-timeline-segment(
5
+ title=segment.tooltip, class=segment.class,
6
+ style=`left: ${segment.left}; width: ${segment.width}; ${segment.color}`)
7
+ each point in points
8
+ .g-timeline-point(
9
+ title=point.tooltip, class=point.class, style=`left: calc(${point.left} - 10px); ${point.color}`)
10
+ if startLabel !== undefined || endLabel !== undefined
11
+ .g-timeline-labels-container
12
+ if startLabel !== undefined
13
+ .g-timeline-start-label= startLabel
14
+ if endLabel !== undefined
15
+ .g-timeline-end-label= endLabel
@@ -0,0 +1,15 @@
1
+ include uploadWidgetMixins
2
+
3
+ .modal-dialog
4
+ .modal-content
5
+ form#g-upload-form.modal-form(role="form")
6
+ .modal-header
7
+ button.close(data-dismiss="modal", aria-hidden="true", type="button") ×
8
+ h4.modal-title= title
9
+ +g-upload-widget-subtitle
10
+ .modal-body
11
+ +g-upload-widget-browse-or-drop
12
+ +g-upload-widget-progress
13
+ .modal-footer
14
+ a.btn.btn-small.btn-default(data-dismiss="modal") Close
15
+ +g-upload-widget-start-button
@@ -0,0 +1,31 @@
1
+ mixin g-upload-widget-subtitle
2
+ if parent && parentType
3
+ .g-dialog-subtitle
4
+ if (parentType === 'folder')
5
+ i.icon-folder-open
6
+ else if (parentType === 'item')
7
+ i.icon-doc-text-inv
8
+ else if (parentType === 'file')
9
+ i.icon-doc-inv
10
+ = parent.name()
11
+
12
+ mixin g-upload-widget-browse-or-drop
13
+ .g-drop-zone
14
+ i.icon-docs
15
+ | #{browseText}
16
+ .form-group.hide
17
+ input#g-files(type="file", multiple=(multiFile ? 'multiple' : null))
18
+
19
+ mixin g-upload-widget-progress
20
+ .g-current-progress-message
21
+ .g-progress-current.progress.progress-striped.hide
22
+ .progress-bar.progress-bar-info(role="progressbar")
23
+ .g-overall-progress-message= noneSelectedText
24
+ .g-progress-overall.progress.progress-striped.hide
25
+ .progress-bar.progress-bar-info(role="progressbar")
26
+ .g-upload-error-message.g-validation-failed-message
27
+
28
+ mixin g-upload-widget-start-button
29
+ button.g-start-upload.btn.btn-small.btn-primary.disabled(type="submit", disabled)
30
+ i.icon-upload
31
+ | Start Upload
@@ -0,0 +1,10 @@
1
+ include uploadWidgetMixins
2
+
3
+ form#g-upload-form
4
+ if title
5
+ h4= title
6
+ +g-upload-widget-subtitle
7
+ +g-upload-widget-browse-or-drop
8
+ +g-upload-widget-progress
9
+ .g-nonmodal-upload-buttons-container
10
+ +g-upload-widget-start-button
@@ -0,0 +1,4 @@
1
+ h2 Enable Two-factor authentication
2
+
3
+ button#g-user-otp-initialize-enable.btn.btn-primary(type="submit")
4
+ | Begin
@@ -0,0 +1,6 @@
1
+ h2.g-user-otp-heading-enable Two-factor authentication is currently enabled
2
+
3
+ h3.g-user-otp-heading-disable Disable Two-factor authentication
4
+
5
+ button#g-user-otp-disable.btn.btn-primary(type="submit")
6
+ | Disable
@@ -0,0 +1,44 @@
1
+ h2 Enable Two-factor authentication
2
+
3
+ ol.g-account-otp-steps
4
+ li.g-account-otp-step
5
+ h3 Install an authenticator app on your mobile device.
6
+ div.
7
+ There are many compatible apps, including, but not limited to
8
+ #[a(href='https://support.google.com/accounts/answer/1066447?hl=en', target='_blank', rel='noopener') Google Authenticator],
9
+ #[a(href='https://guide.duo.com/third-party-accounts', target='_blank', rel='noopener') Duo Mobile], and
10
+ #[a(href='https://freeotp.github.io/', target='_blank', rel='noopener') FreeOTP].
11
+ li.g-account-otp-step
12
+ h3 Enter your key into the authenticator app
13
+ .g-account-otp-scan-qr
14
+ h4 Scan with your mobile device's camera:
15
+ canvas#g-user-otp-qr
16
+ .g-account-otp-enter-manual
17
+ h4 Advanced Users:
18
+ span You may enter your information manually, instead:
19
+ table
20
+ tr
21
+ th Service
22
+ td
23
+ code= totpInfo.issuer
24
+ tr
25
+ th Account
26
+ td
27
+ code= totpInfo.account
28
+ tr
29
+ th Key
30
+ td
31
+ // Split into 4-character chunks for human readability
32
+ code= totpInfo.key.match(/.{1,4}/g).join('-')
33
+ tr
34
+ th Type
35
+ td
36
+ span #[code Time-based] / #[code TOTP]
37
+ li.g-account-otp-step
38
+ h3 Enter the authentication code from your app
39
+ input#g-user-otp-token(type='text', minlength=6, maxlength=6, placeholder='Your 6-digit code')
40
+ div
41
+ span#g-account-otp-error.g-validation-failed-message
42
+ .g-user-otp-footer
43
+ a#g-user-otp-cancel-enable.btn.btn-default Cancel
44
+ button#g-user-otp-finalize-enable.btn.btn-primary.btn-success(type="submit") Enable Two-Factor
@@ -0,0 +1,119 @@
1
+ import _ from 'underscore';
2
+ import Backbone from 'backbone';
3
+
4
+ import { getCurrentToken } from '@girder/core/auth';
5
+
6
+ const appElement = document.getElementById('app');
7
+ let apiRoot = (appElement && appElement.getAttribute('root')) || '';
8
+ apiRoot += (apiRoot.endsWith('/') ? '' : '/') + 'api/v1';
9
+ if (!apiRoot.startsWith('/') && apiRoot.indexOf(':') < 0) {
10
+ apiRoot = '/' + apiRoot;
11
+ }
12
+ let notifyRoot = apiRoot.endsWith('/api/v1') ? apiRoot.slice(0, -6) : apiRoot;
13
+ notifyRoot = notifyRoot.endsWith('/') ? notifyRoot.slice(0, -1) : notifyRoot;
14
+
15
+ /**
16
+ * The EventStream is an abstraction for server-sent events / long-polling via a
17
+ * per-user event channel endpoint using a WebSocket. When events are
18
+ * received on the websocket channel, this triggers a Backbone event of the form
19
+ * 'g:event.<type>' where <type> is the value of the event type field.
20
+ * Listeners can bind to specific event types on the channel.
21
+ */
22
+ function EventStream(settings) {
23
+ // Possible states are 'closed', 'stopped', 'started'
24
+ this._state = 'closed';
25
+
26
+ // Create context bindings only once, so they can be referenced when unbinding events
27
+ this._onVisibilityStateChange = _.bind(this._onVisibilityStateChange, this);
28
+ this._onMessage = _.bind(this._onMessage, this);
29
+ this._onError = _.bind(this._onError, this);
30
+
31
+ return _.extend(this, Backbone.Events);
32
+ }
33
+
34
+ EventStream.prototype._onVisibilityStateChange = function () {
35
+ if (document.visibilityState === 'visible' && this._state === 'stopped') {
36
+ this._start();
37
+ } else if (document.visibilityState === 'hidden' && this._state === 'started') {
38
+ this._stop();
39
+ }
40
+ };
41
+
42
+ EventStream.prototype._onMessage = function (e) {
43
+ let obj;
44
+ try {
45
+ obj = window.JSON.parse(e.data);
46
+ } catch (err) {
47
+ console.error('Invalid JSON from notification stream: ' + e.data + ',' + err);
48
+ this.trigger('g:error', e);
49
+ return;
50
+ }
51
+ this.trigger('g:event.' + obj.type, obj);
52
+ };
53
+
54
+ EventStream.prototype._onError = function () {
55
+ // TODO: Handle error
56
+ };
57
+
58
+ EventStream.prototype.open = function () {
59
+ if (!window.EventSource) {
60
+ console.error('EventSource is not supported on this platform.');
61
+ this.trigger('g:eventStream.disable');
62
+ return;
63
+ }
64
+ if (this._state !== 'closed') {
65
+ console.warn('EventStream should be closed.');
66
+ return;
67
+ }
68
+
69
+ this._state = 'stopped';
70
+ this._start();
71
+
72
+ document.addEventListener('visibilitychange', this._onVisibilityStateChange);
73
+ };
74
+
75
+ EventStream.prototype._start = function () {
76
+ if (this._state !== 'stopped') {
77
+ console.warn('EventStream should be stopped');
78
+ return;
79
+ }
80
+ this._websocket = new WebSocket(`${notifyRoot}/notifications/me?token=${getCurrentToken()}`);
81
+ this._websocket.onmessage = this._onMessage;
82
+ this._websocket.onerror = this._onError;
83
+
84
+ this._state = 'started';
85
+ this.trigger('g:eventStream.start');
86
+ };
87
+
88
+ EventStream.prototype._stop = function () {
89
+ if (this._state !== 'started') {
90
+ console.warn('EventStream should be started');
91
+ return;
92
+ }
93
+
94
+ this._websocket.close();
95
+ this._websocket = null;
96
+
97
+ this._state = 'stopped';
98
+ this.trigger('g:eventStream.stop');
99
+ };
100
+
101
+ EventStream.prototype.close = function () {
102
+ if (this._state === 'closed') {
103
+ console.warn('EventStream should not be closed');
104
+ return;
105
+ }
106
+
107
+ document.removeEventListener('visibilitychange', this._onVisibilityStateChange);
108
+
109
+ if (this._state === 'started') {
110
+ this._stop();
111
+ }
112
+
113
+ this._state = 'closed';
114
+ this.trigger('g:eventStream.close');
115
+ };
116
+
117
+ const eventStream = new EventStream();
118
+
119
+ export default eventStream;
@@ -0,0 +1,36 @@
1
+ import _ from 'underscore';
2
+
3
+ /**
4
+ * Wrap the prototype method of a given object.
5
+ *
6
+ * @param obj The object whose prototype to extend, e.g. MyView
7
+ * @param funcName The name of the function to wrap, e.g. "render"
8
+ * @param wrapper The wrapper function, which should be a function taking the
9
+ * underlying wrapped function as its first argument. The wrapped function
10
+ * should be called with .call(this[, arguments]) inside of the wrapper in
11
+ * order to preserve "this" semantics.
12
+ */
13
+ function wrap(obj, funcName, wrapper) {
14
+ obj.prototype[funcName] = _.wrap(obj.prototype[funcName], wrapper);
15
+ }
16
+
17
+ var _pluginConfigRoutes = {};
18
+
19
+ /**
20
+ * Expose a plugin configuration page via the admin plugins page.
21
+ * @param pluginName The canonical plugin name, i.e. its directory name
22
+ * @param route The route to trigger that will render the plugin config.
23
+ */
24
+ function exposePluginConfig(pluginName, route) {
25
+ _pluginConfigRoutes[pluginName] = route;
26
+ }
27
+
28
+ function getPluginConfigRoute(pluginName) {
29
+ return _pluginConfigRoutes[pluginName];
30
+ }
31
+
32
+ export {
33
+ exposePluginConfig,
34
+ getPluginConfigRoute,
35
+ wrap
36
+ };
@@ -0,0 +1,263 @@
1
+ import _ from 'underscore';
2
+ import Backbone from 'backbone';
3
+
4
+ import { restRequest, uploadHandlers } from '@girder/core/rest';
5
+
6
+ /**
7
+ * This is the upload handler for the "s3" behavior, which is responsible for
8
+ * uploading data to an s3 assetstore type directly from the user agent, using
9
+ * either the single-request or multi-chunk protocol depending on the size of
10
+ * the file.
11
+ *
12
+ * The flow here is to make requests to Girder for each required chunk of
13
+ * the upload, which Girder authorizes and signs using HMAC. Those signatures
14
+ * are sent, along with the bytes, to the appropriate S3 bucket. For multi-
15
+ * chunk uploads, one final request is required after all chunks have been
16
+ * sent in order to create the final unified record in S3.
17
+ */
18
+ // Constructor
19
+ uploadHandlers.s3 = function (params) {
20
+ this.params = params;
21
+ this.startByte = 0;
22
+ return _.extend(this, Backbone.Events);
23
+ };
24
+
25
+ var prototype = uploadHandlers.s3.prototype;
26
+
27
+ prototype._xhrProgress = function (event) {
28
+ if (!event.lengthComputable) {
29
+ return;
30
+ }
31
+
32
+ // We only want to count bytes of the actual file, not the bytes of
33
+ // the request body corresponding to the other form parameters model
34
+ // we are also sending.
35
+ var loaded = this.payloadLength + event.loaded - event.total;
36
+
37
+ if (loaded >= 0) {
38
+ this.trigger('g:upload.progress', {
39
+ startByte: this.startByte,
40
+ loaded: loaded,
41
+ total: this.params.file.size,
42
+ file: this.params.file
43
+ });
44
+ }
45
+ };
46
+
47
+ prototype.execute = function () {
48
+ var s3Info = this.params.upload.s3;
49
+
50
+ var xhr = new XMLHttpRequest();
51
+ xhr.open(s3Info.request.method, s3Info.request.url);
52
+ _.each(s3Info.request.headers, (v, k) => {
53
+ xhr.setRequestHeader(k, v);
54
+ });
55
+
56
+ if (s3Info.chunked) {
57
+ this._multiChunkUpload(xhr);
58
+ } else {
59
+ this.payloadLength = this.params.file.size;
60
+ xhr.onload = () => {
61
+ if (xhr.status === 200) {
62
+ this.trigger('g:upload.chunkSent', {
63
+ bytes: this.payloadLength
64
+ });
65
+
66
+ restRequest({
67
+ url: 'file/completion',
68
+ method: 'POST',
69
+ data: {
70
+ uploadId: this.params.upload._id
71
+ },
72
+ error: null
73
+ }).done((resp) => {
74
+ this.trigger('g:upload.complete', resp);
75
+ }).fail((resp) => {
76
+ var msg;
77
+
78
+ if (resp.status === 0) {
79
+ msg = 'Could not connect to the server.';
80
+ } else {
81
+ msg = 'An error occurred when resuming upload, check console.';
82
+ }
83
+ this.trigger('g:upload.error', {
84
+ message: msg
85
+ });
86
+ });
87
+ } else {
88
+ this.trigger('g:upload.error', {
89
+ message: 'Error occurred uploading to S3 (' + xhr.status + ').'
90
+ });
91
+ }
92
+ };
93
+
94
+ xhr.upload.addEventListener('progress', (event) => {
95
+ this._xhrProgress(event);
96
+ });
97
+
98
+ xhr.addEventListener('error', (event) => {
99
+ this.trigger('g:upload.error', {
100
+ message: 'Error occurred uploading to S3.',
101
+ event: event
102
+ });
103
+ });
104
+
105
+ xhr.send(this.params.file);
106
+ }
107
+ };
108
+
109
+ prototype.resume = function () {
110
+ if (this.params.upload.s3.chunked) {
111
+ return this._sendNextChunk();
112
+ }
113
+
114
+ // If this is a single-chunk upload, we have to use the offset method
115
+ // to re-generate the initial request with a new timestamp.
116
+ restRequest({
117
+ url: 'file/offset',
118
+ method: 'GET',
119
+ data: {
120
+ uploadId: this.params.upload._id
121
+ },
122
+ error: null
123
+ }).done((resp) => {
124
+ this.params.upload.s3.request = resp;
125
+ this.execute();
126
+ }).fail((resp) => {
127
+ var msg;
128
+
129
+ if (resp.status === 0) {
130
+ msg = 'Could not connect to the Girder server.';
131
+ } else {
132
+ msg = 'An error occurred when resuming upload, check console.';
133
+ }
134
+ this.trigger('g:upload.error', {
135
+ message: msg
136
+ });
137
+ });
138
+ };
139
+
140
+ /**
141
+ * If the file being uploaded is larger than a single chunk length, it
142
+ * should be uploaded using the S3 multipart protocol.
143
+ */
144
+ prototype._multiChunkUpload = function (xhr) {
145
+ this.eTagList = {};
146
+ this.startByte = 0;
147
+ this.chunkN = 1;
148
+
149
+ xhr.onload = () => {
150
+ if (xhr.status === 200) {
151
+ this.s3UploadId = xhr.responseText.match(/<UploadId>(.*)<\/UploadId>/).pop();
152
+ this._sendNextChunk();
153
+ } else {
154
+ this.trigger('g:upload.error', {
155
+ message: 'Error while initializing multichunk S3 upload.',
156
+ event: event
157
+ });
158
+ }
159
+ };
160
+
161
+ xhr.addEventListener('error', (event) => {
162
+ this.trigger('g:upload.error', {
163
+ message: 'Error occurred uploading to S3.',
164
+ event: event
165
+ });
166
+ });
167
+
168
+ xhr.send();
169
+ };
170
+
171
+ /**
172
+ * Internal helper method used during multichunk upload protocol. This
173
+ * requests a signed chunk upload request from Girder, then uses that
174
+ * authorized request to send the chunk to S3.
175
+ */
176
+ prototype._sendNextChunk = function () {
177
+ var sliceFn = this.params.file.webkitSlice ? 'webkitSlice' : 'slice';
178
+ var data = this.params.file[sliceFn](this.startByte,
179
+ this.startByte + this.params.upload.s3.chunkLength);
180
+ this.payloadLength = data.size;
181
+
182
+ // Get the authorized request from Girder
183
+ restRequest({
184
+ url: 'file/chunk',
185
+ method: 'POST',
186
+ data: {
187
+ offset: 0,
188
+ chunk: JSON.stringify({
189
+ s3UploadId: this.s3UploadId,
190
+ partNumber: this.chunkN,
191
+ contentLength: this.payloadLength
192
+ }),
193
+ uploadId: this.params.upload._id
194
+ },
195
+ error: null
196
+ }).done((resp) => {
197
+ // Send the chunk to S3
198
+ var xhr = new XMLHttpRequest();
199
+ xhr.open(resp.s3.request.method, resp.s3.request.url);
200
+
201
+ xhr.onload = () => {
202
+ if (xhr.status === 200) {
203
+ this.trigger('g:upload.chunkSent', {
204
+ bytes: this.payloadLength
205
+ });
206
+ this.eTagList[this.chunkN] = xhr.getResponseHeader('ETag');
207
+ this.startByte += this.payloadLength;
208
+ this.chunkN += 1;
209
+
210
+ if (this.startByte < this.params.file.size) {
211
+ this._sendNextChunk();
212
+ } else {
213
+ this._finalizeMultiChunkUpload();
214
+ }
215
+ } else {
216
+ this.trigger('g:upload.error', {
217
+ message: 'Error occurred uploading to S3 (' + xhr.status + ').'
218
+ });
219
+ }
220
+ };
221
+
222
+ xhr.upload.addEventListener('progress', (event) => {
223
+ this._xhrProgress(event);
224
+ });
225
+
226
+ xhr.addEventListener('error', (event) => {
227
+ this.trigger('g:upload.error', {
228
+ message: 'Error occurred uploading to S3.',
229
+ event: event
230
+ });
231
+ });
232
+
233
+ xhr.send(data);
234
+ }).fail(() => {
235
+ this.trigger('g:upload.error', {
236
+ message: 'Error getting signed chunk request from Girder.'
237
+ });
238
+ });
239
+ };
240
+
241
+ /**
242
+ * When all chunks of a multichunk upload have been sent, this must be
243
+ * called in order to finalize the upload.
244
+ */
245
+ prototype._finalizeMultiChunkUpload = function () {
246
+ restRequest({
247
+ url: 'file/completion',
248
+ method: 'POST',
249
+ data: {
250
+ uploadId: this.params.upload._id
251
+ },
252
+ error: null
253
+ }).done((resp) => {
254
+ this.trigger('g:upload.complete', resp);
255
+ }).fail((resp) => {
256
+ const msg = resp.status === 0
257
+ ? 'Could not connect to the server.'
258
+ : 'Upload error during finalize, check console.';
259
+ this.trigger('g:upload.error', {
260
+ message: msg
261
+ });
262
+ });
263
+ };
@@ -0,0 +1,9 @@
1
+ import eventStream from './EventStream';
2
+ import * as PluginUtils from './PluginUtils';
3
+ import * as S3UploadHandler from './S3UploadHandler';
4
+
5
+ export {
6
+ eventStream,
7
+ PluginUtils,
8
+ S3UploadHandler
9
+ };
@@ -0,0 +1,19 @@
1
+ import $ from 'jquery';
2
+
3
+ /**
4
+ * Helper selector to enable/disable inputs elements
5
+ *
6
+ * @param enable Whether to enable the element or not
7
+ */
8
+ $.fn.girderEnable = function (enable) {
9
+ var selection = $(this);
10
+ if (selection.is(':input')) {
11
+ selection.prop('disabled', !enable);
12
+ }
13
+ if (!enable) {
14
+ selection.addClass('disabled');
15
+ } else {
16
+ selection.removeClass('disabled');
17
+ }
18
+ return this;
19
+ };
@@ -0,0 +1,48 @@
1
+ import $ from 'jquery';
2
+
3
+ import 'bootstrap/js/modal';
4
+
5
+ /**
6
+ * This should be used instead of calling bootstrap's modal() jQuery
7
+ * method directly. This unbinds all previous events from the dialog,
8
+ * then calls modal on it and binds the bootstrap close events.
9
+ * @param view The view object. Pass "false" for special cases where the
10
+ * dialog does not correspond to a View object. Pass 'close'
11
+ * to just close an open modal dialog.
12
+ */
13
+ $.fn.girderModal = function (view) {
14
+ /* If we have a modal dialog open, or one is in the process of closing,
15
+ * close that dialog before opening the new one. This prevents
16
+ * layering modal dialogs, but also makes sure that we don't have a
17
+ * problem switching from one modal dialog to another. */
18
+ if ($(this).is('.modal')) {
19
+ /* We have to reach into the backbone modal object a little to see
20
+ * if we need to do anything. By turning off the fade as we
21
+ * remove the old dialog, the removal is synchronous and we are
22
+ * sure it is gone before we add the new dialog. */
23
+ if ($(this).data('bs.modal') && $(this).data('bs.modal').isShown) {
24
+ var elem = $($(this).data('bs.modal').$element);
25
+ var hasFade = elem.hasClass('fade');
26
+ elem.removeClass('fade');
27
+ $(this).modal('hide');
28
+ elem.toggleClass('fade', hasFade);
29
+ }
30
+ }
31
+ if (view !== 'close') {
32
+ this.off();
33
+ // It seems as if $foo.girderModal().on('shown.bs.modal', callback)
34
+ // does not trigger the callback because the call to modal() below is showing
35
+ // the modal (and sending the 'shown.bs.modal' event) *before* we get to
36
+ // register the event in .on('shown.bs.modal', cb). Let's show
37
+ // the modal in the next animation frame to fix this behavior for now.
38
+ setTimeout(() => {
39
+ this.modal().find('[data-dismiss="modal"]').off('click').on('click', () => {
40
+ this.modal('hide');
41
+ });
42
+ }, 0);
43
+ if (view !== false) {
44
+ view.delegateEvents();
45
+ }
46
+ }
47
+ return this;
48
+ };