-
Notifications
You must be signed in to change notification settings - Fork 11
Activity Directive Builder #1900
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
f40cdc4
5e56681
1a8351b
5527ef5
eff85d5
d67c3f5
0456b15
cb284a8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,17 +1,20 @@ | ||
| <svelte:options immutable={true} /> | ||
|
|
||
| <script lang="ts"> | ||
| import { Button } from '@nasa-jpl/stellar-svelte'; | ||
| import CloseIcon from '@nasa-jpl/stellar/icons/close.svg?component'; | ||
| import UploadIcon from '@nasa-jpl/stellar/icons/upload.svg?component'; | ||
| import { CirclePlus } from 'lucide-svelte'; | ||
| import { plan, planModelActivityTypes, subsystemTags } from '../stores/plan'; | ||
| import type { ActivityType } from '../types/activity'; | ||
| import type { ActivityDirectiveInsertInput, ActivityType } from '../types/activity'; | ||
| import type { User } from '../types/app'; | ||
| import type { TimelineItemType } from '../types/timeline'; | ||
| import effects from '../utilities/effects'; | ||
| import { permissionHandler } from '../utilities/permissionHandler'; | ||
| import { featurePermissions } from '../utilities/permissions'; | ||
| import { tooltip } from '../utilities/tooltip'; | ||
| import TimelineItemList from './TimelineItemList.svelte'; | ||
| import ActivityDirectiveBuilder from './activity/ActivityDirectiveBuilder.svelte'; | ||
| import Input from './form/Input.svelte'; | ||
|
|
||
| export let user: User | null; | ||
|
|
@@ -22,6 +25,8 @@ | |
| let isUploadVisible: boolean = false; | ||
| let uploadFiles: FileList | undefined; | ||
| let uploadFileInput: HTMLInputElement; | ||
| let directiveBuilder: ActivityDirectiveBuilder; | ||
| let activeDirectiveName: string = ''; | ||
|
|
||
| $: if (user !== null && $plan !== null) { | ||
| hasUploadPermission = featurePermissions.activityDirective.canCreate(user, $plan); | ||
|
|
@@ -49,8 +54,33 @@ | |
| onHideUpload(); | ||
| } | ||
| } | ||
|
|
||
| function onCreateActivityDirective(directive: ActivityDirectiveInsertInput) { | ||
| if ($plan !== null && $plan.model) { | ||
| effects.createActivityDirectivePredefined(directive, $plan, user); | ||
| directiveBuilder.toggle(); | ||
| } | ||
| } | ||
|
|
||
| function onShowDirectiveBuilder() { | ||
| directiveBuilder.toggle(); | ||
| } | ||
| </script> | ||
|
|
||
| <ActivityDirectiveBuilder | ||
| bind:this={directiveBuilder} | ||
| directiveName={activeDirectiveName} | ||
| directiveWidth={200} | ||
| on:visibilityChange={visibility => { | ||
| if (!visibility.detail.isShown) { | ||
| activeDirectiveName = ''; | ||
| } | ||
| }} | ||
| on:createActivityDirective={directive => { | ||
| onCreateActivityDirective(directive.detail.directive); | ||
| }} | ||
| {user} | ||
| /> | ||
| <TimelineItemList | ||
| items={$planModelActivityTypes} | ||
| chartType="activity" | ||
|
|
@@ -59,6 +89,7 @@ | |
| {getFilterValueFromItem} | ||
| filterOptions={$subsystemTags.map(s => ({ color: s.color || '', label: s.name, value: s.id }))} | ||
| filterName="Subsystem" | ||
| {user} | ||
| > | ||
| <div slot="header" class="upload-container" hidden={!isUploadVisible}> | ||
| <button class="close-upload" type="button" on:click={onHideUpload}> | ||
|
|
@@ -105,6 +136,9 @@ | |
| > | ||
| <UploadIcon /> | ||
| </button> | ||
| <Button variant="ghost" size="icon-sm" aria-label="Add Activity" on:click={onShowDirectiveBuilder}> | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Button needs permission gating.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could this be an outline button that matches the height of the neighboring buttons? |
||
| <CirclePlus size={16} /> | ||
| </Button> | ||
| </svelte:fragment> | ||
| </TimelineItemList> | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,8 +4,11 @@ | |
| import { Button } from '@nasa-jpl/stellar-svelte'; | ||
| import ChevronDownIcon from '@nasa-jpl/stellar/icons/chevron_down.svg?component'; | ||
| import { capitalize } from 'lodash-es'; | ||
| import { CirclePlus, GripVertical } from 'lucide-svelte'; | ||
| import { CirclePlus, Filter, GripVertical } from 'lucide-svelte'; | ||
| import { plan } from '../stores/plan'; | ||
| import { view, viewAddFilterToRow } from '../stores/views'; | ||
| import type { ActivityDirectiveInsertInput } from '../types/activity'; | ||
| import type { User } from '../types/app'; | ||
| import type { | ||
| ChartType, | ||
| Layer, | ||
|
|
@@ -14,7 +17,9 @@ | |
| TimelineItemListFilterOption, | ||
| TimelineItemType, | ||
| } from '../types/timeline'; | ||
| import effects from '../utilities/effects'; | ||
| import { tooltip } from '../utilities/tooltip'; | ||
| import ActivityDirectiveBuilder from './activity/ActivityDirectiveBuilder.svelte'; | ||
| import Input from './form/Input.svelte'; | ||
| import LayerPicker from './LayerPicker.svelte'; | ||
| import Loading from './Loading.svelte'; | ||
|
|
@@ -31,6 +36,7 @@ | |
| export let filterName: string = 'Filter'; | ||
| export let getFilterValueFromItem: (item: TimelineItemType) => string | number; | ||
| export let loading: boolean = false; | ||
| export let user: User | null; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. missing a default for all of these |
||
|
|
||
| let activeItemIndex: number = -1; | ||
| let menu: Menu; | ||
|
|
@@ -41,6 +47,8 @@ | |
| let layerPicker: LayerPicker; | ||
| let layerPickerIndividual: LayerPicker; | ||
| let timelines: Timeline[] = []; | ||
| let directiveBuilder: ActivityDirectiveBuilder; | ||
| let activeDirectiveName: string = ''; | ||
|
|
||
| $: filteredItems = filterItems(items, filterText ? textFilters.concat(filterText) : textFilters, selectedFilters); | ||
| $: timelines = $view?.definition.plan.timelines || []; | ||
|
|
@@ -138,8 +146,34 @@ | |
| } | ||
| return undefined; | ||
| } | ||
|
|
||
| function onCreateActivityDirective(directive: ActivityDirectiveInsertInput) { | ||
| if ($plan !== null && $plan.model) { | ||
| effects.createActivityDirectivePredefined(directive, $plan, user); | ||
| directiveBuilder.toggle(); | ||
| } | ||
| } | ||
|
|
||
| function onShowDirectiveBuilder(activityType: string) { | ||
| directiveBuilder.setCurrentActivityType(activityType); | ||
| directiveBuilder.toggle(); | ||
| } | ||
| </script> | ||
|
|
||
| <ActivityDirectiveBuilder | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Two builder windows can be simultaneously opened - one from a specific type and one from the general circle plus button. Any way to consolidate to a single builder instance since the builder is copied in 3 places? |
||
| bind:this={directiveBuilder} | ||
| directiveName={activeDirectiveName} | ||
| directiveWidth={200} | ||
| on:visibilityChange={visibility => { | ||
| if (!visibility.detail.isShown) { | ||
| activeDirectiveName = ''; | ||
| } | ||
| }} | ||
| on:createActivityDirective={directive => { | ||
| onCreateActivityDirective(directive.detail.directive); | ||
| }} | ||
| {user} | ||
| /> | ||
| <div class="timeline-item-list"> | ||
| <div class="timeline-item-list-filters"> | ||
| <input | ||
|
|
@@ -299,10 +333,20 @@ | |
| let:builders | ||
| > | ||
| <Button {builders} variant="ghost" size="icon-sm" aria-label="Add{capitalize(typeName)}-{item.name}"> | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this be "Filter" instead of "Add" for aria-label? |
||
| <CirclePlus size={16} /> | ||
| <Filter size={16} /> | ||
| </Button> | ||
| </LayerPicker> | ||
| </div> | ||
| <div use:tooltip={{ content: 'Add New Directive', placement: 'top' }} class="flex items-center"> | ||
| <Button | ||
| variant="ghost" | ||
| size="icon-sm" | ||
| aria-label="Add{capitalize(typeName)}-{item.name}" | ||
| on:click={() => onShowDirectiveBuilder(item.name)} | ||
| > | ||
| <CirclePlus size={16} /> | ||
| </Button> | ||
| </div> | ||
| <div class="drag"> | ||
| <GripVertical size={16} /> | ||
| </div> | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we await creation of the directive first in case it fails to create? I know a failure toast will appear, just means that if any sort of hiccup happens (unlikely) that user input from builder will be lost. Not sure if it is necessary though.