Skip to content
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

Searching workspaces and change sets, minimum app width, and more! #5109

Merged
merged 1 commit into from
Dec 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion app/auth-portal/src/pages/WorkspaceDetailsPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,12 @@
:requestStatus="
createMode ? createWorkspaceReqStatus : editWorkspaceReqStatus
"
class="basis-[calc(75%-0.5rem)] flex-grow-0"
:class="
clsx(
'basis-[calc(75%-0.5rem)]',
createMode ? 'flex-grow' : 'flex-grow-0',
)
"
iconRight="chevron--right"
tone="action"
variant="solid"
Expand Down
25 changes: 23 additions & 2 deletions app/web/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
</template>

<script lang="ts" setup>
import { computed } from "vue";
import { computed, onBeforeUnmount, onMounted, ref } from "vue";
import "floating-vue/dist/style.css";

import { tw } from "@si/vue-lib";
Expand All @@ -42,6 +42,7 @@ import { useAuthStore } from "./store/auth.store";
import { useWorkspacesStore } from "./store/workspaces.store";
import { useRealtimeStore } from "./store/realtime/realtime.store";
import CachedAppNotification from "./components/CachedAppNotification.vue";
import { APP_MINIMUM_WIDTH } from "./main";

// this TS magic means that when you call Object.entries
// the "key" will retain its type and will not just be defaulted to "string"
Expand All @@ -60,12 +61,32 @@ useCustomFontsLoadedProvider();
// provides the root theme value to all children, and returns that root theme to use below
const { theme: rootTheme } = useThemeContainer();

// watch the window size to enforce minimum window width
const windowWidth = ref(window.innerWidth);
const windowSizeClasses = computed(() =>
windowWidth.value < APP_MINIMUM_WIDTH
? `min-w-[${APP_MINIMUM_WIDTH}px] overflow-x-auto`
: "",
);

const windowResizeHandler = () => {
windowWidth.value = window.innerWidth;
};

onMounted(() => {
windowResizeHandler();
window.addEventListener("resize", windowResizeHandler);
});
onBeforeUnmount(() => {
window.removeEventListener("resize", windowResizeHandler);
});

useHead(
computed(() => ({
bodyAttrs: {
// add some base classes we need these type classes set for capsize plugin to work throughout
// and add dark mode style/class
class: tw`font-sans text-base leading-none ${rootTheme.value}`,
class: tw`font-sans text-base leading-none ${rootTheme.value} ${windowSizeClasses.value}`,
},
htmlAttrs: {
style: `color-scheme: ${rootTheme.value};`,
Expand Down
5 changes: 4 additions & 1 deletion app/web/src/components/AssetCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,10 @@
<p>
Thanks for contributing! We will review your contribution, and reach out
via email or on our
<a class="text-action-500" href="https://discord.com/invite/system-init"
<a
class="text-action-500"
href="https://discord.com/invite/system-init"
target="_blank"
>Discord Server</a
>
if you have any questions.
Expand Down
114 changes: 37 additions & 77 deletions app/web/src/components/AttributesPanel/TreeFormItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -303,76 +303,39 @@
:style="{ paddingLeft: indentPx }"
class="flex flex-col gap-xs"
>
<button
<DropdownMenuButton
v-if="socketDropDownShouldBeShown"
ref="socketConnectionDropdownButtonRef"
:class="
clsx(
'flex-grow p-2xs mb-[-1px] h-7 relative border mr-xs',
'font-mono text-[13px] text-left',
widgetOptions.length > 0
? 'cursor-pointer'
: [
'cursor-not-allowed',
themeClasses(
'text-neutral-500 bg-caution-lines-light',
'text-neutral-400 bg-caution-lines-dark',
),
],
isFocus
? themeClasses(
'border-action-500 bg-shade-0',
'border-action-300 bg-shade-100',
)
: themeClasses(
'border-neutral-400 bg-neutral-100',
'border-neutral-600 bg-neutral-900',
),
)
"
:placeholder="socketDropdownPlaceholder"
search
:searchFilters="socketSearchFilters"
:disabled="widgetOptions.length < 1"
class="mr-xs flex-grow"
@blur="onBlur"
@focus="widgetOptions.length > 0 ? onFocus() : null"
@click="openSocketWidgetDropdownMenu"
>
{{ socketDropdownPlaceholder }}
<Icon
class="absolute right-1 top-1 text-neutral-400 dark:text-neutral-600"
name="input-type-select"
size="sm"
<DropdownMenuItem
v-if="filteredSocketOptions.length === 0"
header
label="No sockets match your filter/search criteria."
/>
<DropdownMenu
ref="socketConnectionDropdownMenuRef"
:anchorTo="{ $el: socketConnectionDropdownButtonRef }"
overlapAnchorOnAnchorTo
matchWidthToAnchor
:overlapAnchorOffset="4"
search
:searchFilters="socketSearchFilters"
@search="onSearch"
@onClose="clearSearch"
<DropdownMenuItem
v-for="option in filteredSocketOptions"
:key="option.value"
@select="updateValue(option.value)"
>
<DropdownMenuItem
v-if="filteredSocketOptions.length === 0"
header
label="No sockets match your filter/search criteria."
/>
<DropdownMenuItem
v-for="option in filteredSocketOptions"
:key="option.value"
@select="updateValue(option.value)"
>
<div class="flex flex-row">
<TruncateWithTooltip class="basis-0 grow max-w-fit">{{
option.label
}}</TruncateWithTooltip>
<div class="flex-none">/</div>
<TruncateWithTooltip class="basis-0 grow max-w-fit">{{
option.label2
}}</TruncateWithTooltip>
</div>
</DropdownMenuItem>
</DropdownMenu>
</button>
<div class="flex flex-row">
<TruncateWithTooltip class="basis-0 grow max-w-fit">{{
option.label
}}</TruncateWithTooltip>
<div class="flex-none">/</div>
<TruncateWithTooltip class="basis-0 grow max-w-fit">{{
option.label2
}}</TruncateWithTooltip>
</div>
</DropdownMenuItem>
</DropdownMenuButton>
<div
v-for="connection in socketConnectionsList"
:key="connection.value"
Expand All @@ -393,15 +356,16 @@
<IconButton
v-if="!connection.isInferred"
icon="trash"
iconTone="destructive"
size="sm"
class="flex-none"
class="flex-none ml-auto"
@click="unsetHandler(connection.value)"
/>
<IconButton
v-else
icon="question-circle"
iconTone="neutral"
class="flex-none"
class="flex-none ml-auto"
tooltip="Connection can't be unmade because it's inferred from a parent. You can override it above."
/>
</div>
Expand Down Expand Up @@ -944,6 +908,7 @@ import {
IconButton,
Filter,
TruncateWithTooltip,
DropdownMenuButton,
} from "@si/vue-lib/design-system";
import {
AttributeTreeItem,
Expand Down Expand Up @@ -1625,30 +1590,25 @@ const socketDropDownShouldBeShown = computed(
!(socketIsSingleArity.value && socketConnectionsList.value.length !== 0),
);

const socketConnectionDropdownButtonRef = ref();
const socketConnectionDropdownMenuRef =
ref<InstanceType<typeof DropdownMenu>>();
const socketConnectionDropdownButtonRef =
ref<InstanceType<typeof DropdownMenuButton>>();

const openSocketWidgetDropdownMenu = () => {
if (widgetOptions.value.length > 0) {
socketConnectionDropdownMenuRef.value?.open();
socketConnectionDropdownButtonRef.value?.open();
}
};

// SOCKET WIDGET SEARCHING AND FILTERING
const socketSearchString = ref("");
const onSearch = (search: string) => {
socketSearchString.value = search.trim().toLocaleLowerCase();
};
const clearSearch = () => {
socketSearchString.value = "";
};
const socketSearchString = computed(
() => socketConnectionDropdownButtonRef.value?.searchString || "",
);

const filteredSocketOptions = computed(() => {
const filteringActive =
socketConnectionDropdownMenuRef.value?.searchFilteringActive;
socketConnectionDropdownButtonRef.value?.searchFilteringActive;
const activeFilters =
socketConnectionDropdownMenuRef.value?.searchActiveFilters;
socketConnectionDropdownButtonRef.value?.searchActiveFilters;

if (socketSearchString.value === "" && !filteringActive) {
return widgetOptions.value as DoubleLabelList<string>;
Expand Down
35 changes: 22 additions & 13 deletions app/web/src/components/FuncEditor/FuncTestSelector.vue
Original file line number Diff line number Diff line change
@@ -1,26 +1,25 @@
<template>
<div class="flex flex-row items-center gap-sm">
<VormInput
<div class="flex flex-col items-center gap-xs">
<DropdownMenuButton
v-model="selectedComponentId"
class="flex-grow"
type="dropdown"
class="w-full"
placeholder="no component selected"
noLabel
:options="componentAttributeOptions"
@update:model-value="loadInputIfNotAttributeFunc"
checkable
@select="setSelectedComponentId"
/>
<VormInput
<DropdownMenuButton
v-if="isAttributeFunc"
v-model="selectedPrototypeId"
class="flex-grow"
type="dropdown"
class="w-full"
placeholder="no binding selected"
noLabel
:disabled="!selectedComponentId"
:options="prototypeAttributeOptions"
@update:model-value="emit('loadInput')"
:disabled="!selectedComponentId"
checkable
@select="setSelectedBinding"
/>
<VButton
class="w-full"
label="Run Test"
size="sm"
:loading="testStatus === 'running'"
Expand All @@ -34,7 +33,7 @@
</template>

<script lang="ts" setup>
import { VButton, VormInput } from "@si/vue-lib/design-system";
import { DropdownMenuButton, VButton } from "@si/vue-lib/design-system";
import { PropType, computed, ref } from "vue";
import { useComponentsStore } from "@/store/components.store";
import { useAssetStore } from "@/store/asset.store";
Expand Down Expand Up @@ -117,6 +116,16 @@ const prototypeAttributeOptions = computed(() => {
}
});

const setSelectedComponentId = (id: string) => {
selectedComponentId.value = id;
loadInputIfNotAttributeFunc();
};

const setSelectedBinding = (id: string) => {
selectedPrototypeId.value = id;
emit("loadInput");
};

// We need the user to select a prototype after selecting a component if its an attribute func.
const loadInputIfNotAttributeFunc = () => {
if (props.isAttributeFunc) {
Expand Down
49 changes: 18 additions & 31 deletions app/web/src/components/FuncEditor/ManagementDetails.vue
Original file line number Diff line number Diff line change
@@ -1,37 +1,22 @@
<template>
<div class="p-xs flex flex-col gap-xs w-full">
<div class="flex flex-row gap-2xs">
<VormInput
:modelValue="selectedManagedSchemaId"
placeholder="Pick an asset to manage"
size="sm"
noLabel
placeholderSelectable
type="dropdown"
:disabled="props.disabled"
:options="schemaOptions"
@update:model-value="(newVal: string) => (selectedManagedSchemaId = newVal)"
/>

<IconButton
icon="plus"
class="mt-2xs"
size="sm"
iconTone="action"
:disabled="props.disabled"
@click="addSchema"
/>
</div>

<ul v-if="binding?.managedSchemas">
<DropdownMenuButton
placeholder="Pick an asset to manage"
:disabled="props.disabled"
:options="schemaOptions"
@select="addSchema"
/>
<ul v-if="binding?.managedSchemas && binding.managedSchemas.length > 0">
<li
v-for="schemaId in binding.managedSchemas"
:key="schemaId"
class="flex flex-row items-center content-center gap-2xs mt-1"
>
<p class="grow text-neutral-700 type-bold-sm dark:text-neutral-50 ml-2">
<TruncateWithTooltip
class="grow text-neutral-700 type-bold-sm dark:text-neutral-50 ml-2"
>
{{ schemaNameMap[schemaId] ?? schemaId }}
</p>
</TruncateWithTooltip>
<IconButton
icon="trash"
size="sm"
Expand All @@ -48,7 +33,11 @@
import * as _ from "lodash-es";
import { ref, watch, computed, toRaw } from "vue";
import { storeToRefs } from "pinia";
import { IconButton, VormInput } from "@si/vue-lib/design-system";
import {
DropdownMenuButton,
IconButton,
TruncateWithTooltip,
} from "@si/vue-lib/design-system";
import { Option } from "@/components/SelectMenu.vue";
import { toOptionValues } from "@/components/FuncEditor/utils";
import { useFuncStore } from "@/store/func/funcs.store";
Expand All @@ -67,8 +56,6 @@ const props = defineProps<{
disabled?: boolean;
}>();

const selectedManagedSchemaId = ref("");

const schemaNameMap = ref<{ [key: string]: string }>({});

const managerSchemaId = computed(
Expand Down Expand Up @@ -120,13 +107,13 @@ const schemaOptions = computed(() => {
return filteredOptions;
});

const addSchema = async () => {
const addSchema = async (selectedManagedSchemaId: string) => {
if (binding.value) {
const updated_binding = structuredClone(toRaw(binding.value));
if (!updated_binding.managedSchemas) {
updated_binding.managedSchemas = [];
}
updated_binding.managedSchemas.push(selectedManagedSchemaId.value);
updated_binding.managedSchemas.push(selectedManagedSchemaId);
await funcStore.UPDATE_BINDING(props.funcId, [updated_binding]);
}
};
Expand Down
Loading
Loading