Skip to content

Commit

Permalink
merge: #2942
Browse files Browse the repository at this point in the history
2942: feat(web) - multiplayer apply flow r=wendybujalski a=wendybujalski

<img src="https://media1.giphy.com/media/5K7ngCtszoxxbaBieC/giphy-downsized-medium.gif"/>

Co-authored-by: wendybujalski <[email protected]>
  • Loading branch information
si-bors-ng[bot] and wendybujalski authored Nov 9, 2023
2 parents c18a66a + 1798c90 commit 01d1da6
Show file tree
Hide file tree
Showing 14 changed files with 576 additions and 49 deletions.
7 changes: 5 additions & 2 deletions app/web/src/api/sdf/dal/change_set.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
// TODO: remove
import { ActionInstance } from "@/store/actions.store";
import { UserId } from "@/store/auth.store";

export enum ChangeSetStatus {
Open = "Open",
Closed = "Closed",
Abandoned = "Abandoned",
Applied = "Applied",
Failed = "Failed",
Closed = "Closed",
Abandoned = "Abandoned",
}

export type ChangeSetId = string;
Expand All @@ -16,6 +17,8 @@ export interface ChangeSet {
name: string;
actions: ActionInstance[];
status: ChangeSetStatus;
appliedByUserId?: UserId;
appliedAt?: IsoDateString;
}

export type ChangeStatus = "added" | "deleted" | "modified" | "unmodified";
Expand Down
19 changes: 19 additions & 0 deletions app/web/src/components/ApplyChangeSetButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@
@click="applyChangeSet"
/>
</Modal>
<ChangeSetApplyVotingPopover
ref="changeSetApplyVotingPopoverRef"
appliedByYou
/>
</VButton>
</template>

Expand All @@ -55,17 +59,32 @@ import ActionSprite from "@/components/ActionSprite.vue";
import { useChangeSetsStore } from "@/store/change_sets.store";
import { useStatusStore } from "@/store/status.store";
import { useActionsStore } from "@/store/actions.store";
import ChangeSetApplyVotingPopover from "./layout/navbar/ChangeSetApplyVotingPopover.vue";
const createModalRef = ref<InstanceType<typeof Modal> | null>(null);
const changeSetApplyVotingPopoverRef = ref();
const maybeOpenModal = () => {
// TODO(Wendy) - voting Popover needs to be put into this flow
if (!changeSetsStore.selectedChangeSet?.actions?.length) {
applyChangeSet();
} else {
createModalRef.value?.open();
}
};
// TODO(Wendy) - implement the code that invokes this Popover when appropriate
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const openVotingPopover = () => {
const applyButtonRect = applyButtonRef.value.$el.getBoundingClientRect();
changeSetApplyVotingPopoverRef.value.openAt({
x: applyButtonRect.x + applyButtonRect.width / 2 - 16,
y: applyButtonRect.bottom,
});
};
const changeSetsStore = useChangeSetsStore();
const actionsStore = useActionsStore();
const router = useRouter();
Expand Down
30 changes: 26 additions & 4 deletions app/web/src/components/Popover.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@
<div
ref="internalRef"
:style="computedStyle"
:class="clsx('absolute ml-sm', onTopOfEverything ? 'z-100' : 'z-50')"
:class="
clsx(
'absolute ml-sm',
onTopOfEverything ? 'z-100' : 'z-50',
isRepositioning && 'invisible',
)
"
>
<slot />
</div>
Expand Down Expand Up @@ -42,6 +48,9 @@ const props = defineProps({
// go on top of all elements, including the navbar and statusbar
onTopOfEverything: { type: Boolean },
// act like a Modal that cannot be closed
noExit: { type: Boolean },
});
const internalRef = ref<HTMLElement>();
Expand All @@ -52,8 +61,11 @@ const anchorPos = ref<{ x: number; y: number }>();
function onWindowMousedown(e: MouseEvent) {
requestAnimationFrame(() => {
if (e.target instanceof Element && internalRef.value?.contains(e.target)) {
return; // Don't close on click inside popover
if (
(e.target instanceof Element && internalRef.value?.contains(e.target)) ||
props.noExit
) {
return; // Don't close on click inside popover or if noExit is set
}
close();
Expand All @@ -62,6 +74,7 @@ function onWindowMousedown(e: MouseEvent) {
function onKeyboardEvent(e: KeyboardEvent) {
if (e.key === "Escape") {
if (props.noExit) return;
close();
}
}
Expand Down Expand Up @@ -107,6 +120,15 @@ function open(e?: MouseEvent, anchorToMouse?: boolean) {
nextFrame(finishOpening);
}
function openAt(pos: { x: number; y: number }) {
anchorPos.value = pos;
isRepositioning.value = true;
isOpen.value = true;
nextFrame(finishOpening);
}
function finishOpening() {
startListening();
readjustPosition();
Expand Down Expand Up @@ -198,5 +220,5 @@ onUnmounted(() => {
window.removeEventListener("resize", closeOnResize);
});
defineExpose({ open, close, isOpen });
defineExpose({ open, openAt, close, isOpen });
</script>
68 changes: 68 additions & 0 deletions app/web/src/components/layout/navbar/ChangeSetAppliedPopover.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<template>
<Popover ref="internalRef" popDown onTopOfEverything :anchorTo="anchorTo">
<div
class="absolute top-0 left-[50%] translate-x-[-50%] translate-y-[-100%] w-0 h-0 border-transparent border-b-white dark:border-b-neutral-700 border-[16px] border-b-[12px]"
/>
<div
class="bg-white dark:bg-neutral-700 rounded-lg flex flex-col items-center w-96 max-h-[90vh] shadow-md overflow-hidden pb-xs"
>
<div class="px-sm pt-sm pb-xs w-full">
The change set you were in was merged.
</div>

<!-- TODO(Wendy) - Eventually we should display who merged it! -->
<!-- <div v-if="applyUser" class="pr-xs">
<UserCard :user="applyUser" hideChangesetInfo />
</div> -->
<div class="px-sm pb-sm pt-xs w-full">
You are now on Head. You can continue your work by creating a new change
set or joining another existing change set.
</div>
<VButton
label="Dismiss"
variant="ghost"
size="sm"
@click="internalRef.close"
/>
</div>
</Popover>
</template>

<script lang="ts" setup>
import { computed, ref } from "vue";
import { VButton } from "@si/vue-lib/design-system";
import Popover from "@/components/Popover.vue";
import { useChangeSetsStore } from "@/store/change_sets.store";
// import UserCard from "./UserCard.vue";
const changeSetsStore = useChangeSetsStore();
const internalRef = ref();
defineProps({
anchorTo: { type: Object },
});
// TODO(Wendy) - currently this comes through as an email address, should be a UserInfo or ActorView!
// const applyUser = computed(() => {
// return changeSetsStore.postApplyActor;
// });
const openAt = (pos: { x: number; y: number }) => {
internalRef.value.openAt(pos);
// This Popover automatically closes after 10 seconds
setTimeout(close, 10000);
};
const close = () => {
internalRef.value.close();
changeSetsStore.postApplyActor = null;
};
const isOpen = computed(() => internalRef.value.isOpen);
defineExpose({
openAt,
close,
isOpen,
});
</script>
Loading

0 comments on commit 01d1da6

Please sign in to comment.