Skip to content

Commit

Permalink
Merge pull request #398 from dfpc-coe/mission-editing
Browse files Browse the repository at this point in the history
Mission Editing
  • Loading branch information
ingalls authored Oct 29, 2024
2 parents 39b7ca4 + 9ac087d commit f7ea4b4
Show file tree
Hide file tree
Showing 17 changed files with 2,031 additions and 1,790 deletions.
6 changes: 4 additions & 2 deletions api/lib/api/mission.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,10 +223,12 @@ export default class {
}
}

return await this.api.fetch(url, {
const changes = await this.api.fetch(url, {
method: 'GET',
headers: this.#headers(opts),
});

return changes;
}

/**
Expand Down Expand Up @@ -382,7 +384,7 @@ export default class {
async subscriptionRoles(
name: string,
opts?: Static<typeof MissionOptions>
): Promise<TAKList<any>> {
): Promise<TAKList<Array<Static<typeof MissionSubscriber>>>> {
const url = this.#isGUID(name)
? new URL(`/Marti/api/missions/guid/${encodeURIComponent(name)}/subscriptions/roles`, this.api.url)
: new URL(`/Marti/api/missions/${this.#encodeName(name)}/subscriptions/roles`, this.api.url);
Expand Down
25 changes: 25 additions & 0 deletions api/lib/aws/lambda.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,27 @@ export default class Lambda {
TreatMissingData: 'missing'
}
},
LambdaNoInvocationAlarm: {
Type: 'AWS::CloudWatch::Alarm',
Properties: {
AlarmName: cf.join([StackName, '-no-invocations']),
ActionsEnabled: true,
AlarmActions: [ ],
MetricName: 'Invocations',
Namespace: 'AWS/Lambda',
Statistic: 'Maximum',
Dimensions: [{
Name: 'FunctionName',
Value: StackName
}],
Period: layer.alarm_period,
EvaluationPeriods: layer.alarm_evals,
DatapointsToAlarm: layer.alarm_points,
Threshold: layer.alarm_threshold,
ComparisonOperator: 'LessThanOrEqualToThreshold',
TreatMissingData: 'missing'
}
},
ETLFunction: {
Type: 'AWS::Lambda::Function',
Properties: {
Expand Down Expand Up @@ -106,6 +127,10 @@ export default class Lambda {
stack.Resources.LambdaAlarm.Properties.AlarmActions.push(
cf.join(['arn:', cf.partition, ':sns:', cf.region, `:`, cf.accountId, `:${config.StackName}-${layer.priority}-urgency`])
)

stack.Resources.LambdaNoInvocationAlarm.Properties.AlarmActions.push(
cf.join(['arn:', cf.partition, ':sns:', cf.region, `:`, cf.accountId, `:${config.StackName}-${layer.priority}-urgency`])
)
}

if (Schedule.is_aws(layer.cron)) {
Expand Down
152 changes: 76 additions & 76 deletions api/package-lock.json

Large diffs are not rendered by default.

11 changes: 9 additions & 2 deletions api/routes/marti-mission.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import {
MissionChangesInput,
MissionListInput,
MissionDeleteInput,
MissionCreateInput
MissionCreateInput,
MissionSubscriber
} from '../lib/api/mission.js';
import TAKAPI, {
APIAuthCertificate,
Expand Down Expand Up @@ -264,7 +265,13 @@ export default async function router(schema: Schema, config: Config) {
name: Type.String(),
}),
description: 'List subscriptions associated with a mission',
res: GenericMartiResponse
res: Type.Object({
version: Type.String(),
type: Type.String(),
data: Type.Array(MissionSubscriber),
messages: Type.Optional(Type.Array(Type.String())),
nodeId: Type.Optional(Type.String())
})
}, async (req, res) => {
try {
const user = await Auth.as_user(config, req);
Expand Down
437 changes: 235 additions & 202 deletions api/web/package-lock.json

Large diffs are not rendered by default.

37 changes: 31 additions & 6 deletions api/web/src/components/Admin/AdminUser.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@
<TablerIconButton
title='Back'
@click='$router.push("/admin/user")'
><IconCircleArrowLeft :size='32' stroke='1'/></TablerIconButton>
>
<IconCircleArrowLeft
:size='32'
stroke='1'
/>
</TablerIconButton>

<h1
class='card-title mx-2'
Expand All @@ -16,28 +21,48 @@
v-if='!edit'
title='Edit User'
@click='edit = true'
><IconSettings :size='32' stroke='1' /></TablerIconButton>
>
<IconSettings
:size='32'
stroke='1'
/>
</TablerIconButton>
<TablerIconButton
title='Refresh'
@click='fetchUserLoading'
><IconRefresh :size='32' stroke='1' /></TablerIconButton>
>
<IconRefresh
:size='32'
stroke='1'
/>
</TablerIconButton>
</div>
</div>
<div class='card-body'>
<TablerLoading v-if='loading' />
<template v-else-if='edit'>
<div class='col-12 pb-4'>
<TablerToggle
label='System Administrator'
v-model='user.system_admin'
label='System Administrator'
/>
</div>

<div class='col-12 d-flex align-items-center'>
<button @click='fetchUserLoading' class='btn btn-secondary'>Cancel</button>
<button
class='btn btn-secondary'
@click='fetchUserLoading'
>
Cancel
</button>

<div class='ms-auto'>
<button @click='saveUser' class='btn btn-primary'>Save</button>
<button
class='btn btn-primary'
@click='saveUser'
>
Save
</button>
</div>
</div>
</template>
Expand Down
3 changes: 1 addition & 2 deletions api/web/src/components/CloudTAK/Map.vue
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@
v-if='selected.size'
class='position-absolute begin-0 text-white bg-dark'
style='
z-index: 1;
bottom: 40px;
width: 250px;
'
Expand Down Expand Up @@ -797,7 +796,7 @@ export default {
return mapStore.map.getZoom();
},
getLocation: function() {
if (this.live_loc) {
if (!this.live_loc) {
throw new Error('No Location Determined');
} else if (this.live_loc_denied) {
throw new Error('Cannot navigate to your position as you denied location services');
Expand Down
127 changes: 59 additions & 68 deletions api/web/src/components/CloudTAK/Menu/Mission/MissionInfo.vue
Original file line number Diff line number Diff line change
Expand Up @@ -105,84 +105,75 @@
</MenuTemplate>
</template>

<script>
import { std, stdurl } from '/src/std.ts';
<script setup lang='ts'>
import { ref, computed, onMounted } from 'vue';
import type { MissionSubscriptions } from '../../../../types.ts'
import Subscription from '../../../../stores/base/mission.ts';
import {
TablerLoading
TablerLoading,
} from '@tak-ps/vue-tabler';
import MenuTemplate from '../../util/MenuTemplate.vue';
import Overlay from '/src/stores/base/overlay.ts';
import { useMapStore } from '/src/stores/map.ts';
import Overlay from '../../../../stores/base/overlay.ts';
import { useMapStore } from '../../../../stores/map.ts';
const mapStore = useMapStore();
import { useCOTStore } from '/src/stores/cots.ts';
const cotStore = useCOTStore();
export default {
name: 'MissionInfo',
components: {
MenuTemplate,
TablerLoading
const props = defineProps({
mission: {
type: Object,
required: true
},
props: {
mission: Object,
token: String,
role: Object,
},
data: function() {
return {
createLayer: false,
loading: {
users: false,
layers: true,
subscribe: false,
},
layers: [],
subscriptions: []
}
},
computed: {
subscribed: function() {
if (this.loading.subscribe) return;
return !!mapStore.getOverlayByMode('mission', this.mission.guid);
}
},
mounted: async function() {
await this.fetchSubscriptions();
},
methods: {
fetchSubscriptions: async function() {
const url = stdurl(`/api/marti/missions/${this.mission.name}/subscriptions/roles`);
this.subscriptions = (await std(url, {
headers: {
MissionAuthorization: this.token
}
})).data;
this.loading.users = false;
},
subscribe: async function(subscribed) {
this.loading.subscribe = true;
const overlay = mapStore.getOverlayByMode('mission', this.mission.guid);
token: String,
role: {
type: Object,
required: true
}
});
onMounted(async () => {
await fetchSubscriptions();
});
if (subscribed === true && !overlay) {
const missionOverlay = await Overlay.create(mapStore.map, {
name: this.mission.name,
url: `/mission/${encodeURIComponent(this.mission.name)}`,
type: 'geojson',
mode: 'mission',
token: this.token,
mode_id: this.mission.guid,
})
const loading = ref({
users: false,
subscribe: false,
});
mapStore.overlays.push(missionOverlay);
const subscriptions = ref<MissionSubscriptions>([])
mapStore.map.getSource(String(missionOverlay.id))
.setData(await cotStore.loadMission(this.mission.guid, missionOverlay.token));
} else if (subscribed === false && overlay) {
await mapStore.removeOverlay(overlay);
}
const subscribed = computed(() => {
if (loading.value.subscribe) return;
return !!mapStore.getOverlayByMode('mission', props.mission.guid);
});
this.loading.subscribe = false;
},
async function fetchSubscriptions() {
loading.value.users = true;
subscriptions.value = await Subscription.subscriptions(props.mission.guid, props.token)
loading.value.users = false;
}
async function subscribe(subscribed: boolean) {
loading.value.subscribe = true;
const overlay = mapStore.getOverlayByMode('mission', props.mission.guid);
if (subscribed === true && !overlay) {
if (!mapStore.map) throw new Error('Cannot subscribe before map is loaded');
// @ts-expect-error Map.Style is missing properties (probably a MapLibreGL@5 issue)
const missionOverlay = await Overlay.create(mapStore.map, {
name: props.mission.name,
url: `/mission/${encodeURIComponent(props.mission.name)}`,
type: 'geojson',
mode: 'mission',
token: props.token,
mode_id: props.mission.guid,
})
mapStore.overlays.push(missionOverlay);
mapStore.updateMissionData(props.mission.guid);
} else if (subscribed === false && overlay) {
await mapStore.removeOverlay(overlay);
}
loading.value.subscribe = false;
}
</script>
21 changes: 18 additions & 3 deletions api/web/src/components/CloudTAK/Menu/Overlays.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,34 @@
v-if='isDraggable === false'
title='"Edit Order"'
@click='isDraggable = true'
><IconPencil :size='32' :stroke='1' /></TablerIconButton>
>
<IconPencil
:size='32'
:stroke='1'
/>
</TablerIconButton>

<TablerIconButton
v-else-if='isDraggable === true'
title='"Save Order"'
@click='isDraggable = false'
><IconPencilCheck :size='32' :stroke='1'/></TablerIconButton>
>
<IconPencilCheck
:size='32'
:stroke='1'
/>
</TablerIconButton>

<TablerIconButton
v-if='!isDraggable'
title='"Add Overlay"'
@click='$router.push("/menu/datas")'
><IconPlus :size='32' :stroke='1' /></TablerIconButton>
>
<IconPlus
:size='32'
:stroke='1'
/>
</TablerIconButton>
</template>
<template #default>
<TablerLoading v-if='loading || !isLoaded' />
Expand Down
Loading

0 comments on commit f7ea4b4

Please sign in to comment.