|
1 | 1 | <svelte:options immutable={true} /> |
2 | 2 |
|
3 | 3 | <script lang="ts"> |
4 | | - import { resourceTypes } from '../stores/simulation'; |
| 4 | + import CloseIcon from '@nasa-jpl/stellar/icons/close.svg?component'; |
| 5 | + import UploadIcon from '@nasa-jpl/stellar/icons/upload.svg?component'; |
| 6 | + import { plan } from '../stores/plan'; |
| 7 | + import { allResourceTypes, simulationDatasetId } from '../stores/simulation'; |
| 8 | + import type { User } from '../types/app'; |
5 | 9 | import type { ResourceType } from '../types/simulation'; |
6 | 10 | import type { TimelineItemType } from '../types/timeline'; |
| 11 | + import effects from '../utilities/effects'; |
| 12 | + import { permissionHandler } from '../utilities/permissionHandler'; |
| 13 | + import { featurePermissions } from '../utilities/permissions'; |
| 14 | + import { tooltip } from '../utilities/tooltip'; |
7 | 15 | import ResourceListPrefix from './ResourceListPrefix.svelte'; |
8 | 16 | import TimelineItemList from './TimelineItemList.svelte'; |
| 17 | + import Input from './form/Input.svelte'; |
| 18 | +
|
| 19 | + export let user: User | null; |
| 20 | +
|
| 21 | + const uploadPermissionError: string = `You do not have permission to upload resources.`; |
9 | 22 |
|
10 | 23 | let resourceDataTypes: string[] = []; |
| 24 | + let hasUploadPermission: boolean = false; |
| 25 | + let isUploadVisible: boolean = false; |
| 26 | + let useSelectedSimulation: boolean = false; |
| 27 | + let uploadFiles: FileList | undefined; |
| 28 | + let uploadFileInput: HTMLInputElement; |
11 | 29 |
|
12 | | - $: resourceDataTypes = [...new Set($resourceTypes.map(t => t.schema.type))]; |
| 30 | + $: resourceDataTypes = [...new Set($allResourceTypes.map(t => t.schema.type))]; |
| 31 | + $: if (user !== null && $plan !== null) { |
| 32 | + hasUploadPermission = featurePermissions.externalResources.canCreate(user, $plan); |
| 33 | + } |
13 | 34 |
|
14 | 35 | function getFilterValueFromItem(item: TimelineItemType) { |
15 | 36 | return (item as ResourceType).schema.type; |
16 | 37 | } |
| 38 | +
|
| 39 | + function onShowUpload() { |
| 40 | + isUploadVisible = true; |
| 41 | + } |
| 42 | +
|
| 43 | + function onHideUpload() { |
| 44 | + isUploadVisible = false; |
| 45 | + } |
| 46 | +
|
| 47 | + async function onUpload() { |
| 48 | + if (uploadFiles !== undefined) { |
| 49 | + if ($plan && uploadFiles?.length) { |
| 50 | + await effects.uploadExternalDataset( |
| 51 | + $plan, |
| 52 | + uploadFiles, |
| 53 | + user, |
| 54 | + useSelectedSimulation ? $simulationDatasetId : undefined, |
| 55 | + ); |
| 56 | + } |
| 57 | + uploadFileInput.value = ''; |
| 58 | + uploadFiles = undefined; |
| 59 | + } |
| 60 | + } |
17 | 61 | </script> |
18 | 62 |
|
19 | 63 | <TimelineItemList |
20 | | - items={$resourceTypes} |
| 64 | + items={$allResourceTypes} |
21 | 65 | chartType="line" |
22 | 66 | typeName="resource" |
23 | 67 | typeNamePlural="Resources" |
|
26 | 70 | {getFilterValueFromItem} |
27 | 71 | let:prop={item} |
28 | 72 | > |
| 73 | + <div slot="header" class="upload-container" hidden={!isUploadVisible}> |
| 74 | + <button class="close-upload" type="button" on:click={onHideUpload}> |
| 75 | + <CloseIcon /> |
| 76 | + </button> |
| 77 | + <Input layout="stacked"> |
| 78 | + <label class="st-typography-body" for="file">Resource File</label> |
| 79 | + <input |
| 80 | + class="w-100" |
| 81 | + name="file" |
| 82 | + type="file" |
| 83 | + accept="application/json,.csv,.txt" |
| 84 | + bind:files={uploadFiles} |
| 85 | + bind:this={uploadFileInput} |
| 86 | + use:permissionHandler={{ |
| 87 | + hasPermission: hasUploadPermission, |
| 88 | + permissionError: uploadPermissionError, |
| 89 | + }} |
| 90 | + /> |
| 91 | + </Input> |
| 92 | + <div class="use-simulation"> |
| 93 | + <label class="st-typography-body timeline-item-list-filter-option-label" for="simulation-association"> |
| 94 | + Use selected simulation |
| 95 | + </label> |
| 96 | + <input |
| 97 | + bind:checked={useSelectedSimulation} |
| 98 | + class="simulation-checkbox" |
| 99 | + type="checkbox" |
| 100 | + name="simulation-association" |
| 101 | + /> |
| 102 | + </div> |
| 103 | + <div class="upload-button-container"> |
| 104 | + <button |
| 105 | + class="st-button secondary" |
| 106 | + disabled={!uploadFiles?.length} |
| 107 | + on:click={onUpload} |
| 108 | + use:permissionHandler={{ |
| 109 | + hasPermission: hasUploadPermission, |
| 110 | + permissionError: uploadPermissionError, |
| 111 | + }} |
| 112 | + > |
| 113 | + Upload |
| 114 | + </button> |
| 115 | + </div> |
| 116 | + </div> |
| 117 | + <div slot="button"> |
| 118 | + <button |
| 119 | + class="st-button secondary" |
| 120 | + on:click={onShowUpload} |
| 121 | + use:permissionHandler={{ |
| 122 | + hasPermission: hasUploadPermission, |
| 123 | + permissionError: uploadPermissionError, |
| 124 | + }} |
| 125 | + use:tooltip={{ content: 'Upload Resources' }} |
| 126 | + > |
| 127 | + <UploadIcon /> |
| 128 | + </button> |
| 129 | + </div> |
29 | 130 | <ResourceListPrefix {item} /> |
30 | 131 | </TimelineItemList> |
| 132 | + |
| 133 | +<style> |
| 134 | + .upload-container { |
| 135 | + background: var(--st-gray-15); |
| 136 | + border-radius: 5px; |
| 137 | + margin: 5px; |
| 138 | + padding: 8px 11px 8px; |
| 139 | + position: relative; |
| 140 | + } |
| 141 | +
|
| 142 | + .upload-container[hidden] { |
| 143 | + display: none; |
| 144 | + } |
| 145 | +
|
| 146 | + .upload-container { |
| 147 | + display: grid; |
| 148 | + row-gap: 8px; |
| 149 | + } |
| 150 | +
|
| 151 | + .upload-container .use-simulation { |
| 152 | + column-gap: 8px; |
| 153 | + display: grid; |
| 154 | + grid-template-columns: max-content auto; |
| 155 | + justify-content: space-between; |
| 156 | + justify-self: left; |
| 157 | + margin: 0; |
| 158 | + width: 100%; |
| 159 | + } |
| 160 | +
|
| 161 | + .upload-container :global(.upload-button-container) { |
| 162 | + display: flex; |
| 163 | + flex-flow: row-reverse; |
| 164 | + } |
| 165 | +
|
| 166 | + .upload-container :global(.close-upload) { |
| 167 | + background: none; |
| 168 | + border: 0; |
| 169 | + cursor: pointer; |
| 170 | + height: 1.3rem; |
| 171 | + padding: 0; |
| 172 | + position: absolute; |
| 173 | + right: 3px; |
| 174 | + top: 3px; |
| 175 | + } |
| 176 | +</style> |
0 commit comments