feat(common): click to activate environment from sidebar as primary (#4873)

Co-authored-by: jamesgeorge007 <25279263+jamesgeorge007@users.noreply.github.com>
This commit is contained in:
Anwarul Islam 2025-03-21 13:52:46 +06:00 committed by GitHub
parent d8e297f61e
commit 1a2b9516c9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 160 additions and 19 deletions

View file

@ -205,6 +205,7 @@ declare module 'vue' {
IconLucideArrowLeft: typeof import('~icons/lucide/arrow-left')['default']
IconLucideArrowUpRight: typeof import('~icons/lucide/arrow-up-right')['default']
IconLucideBrush: typeof import('~icons/lucide/brush')['default']
IconLucideCheck: typeof import('~icons/lucide/check')['default']
IconLucideCheckCircle: typeof import('~icons/lucide/check-circle')['default']
IconLucideChevronRight: typeof import('~icons/lucide/chevron-right')['default']
IconLucideCircleCheck: typeof import('~icons/lucide/circle-check')['default']
@ -215,6 +216,7 @@ declare module 'vue' {
IconLucideLayers: typeof import('~icons/lucide/layers')['default']
IconLucideListEnd: typeof import('~icons/lucide/list-end')['default']
IconLucideMinus: typeof import('~icons/lucide/minus')['default']
IconLucidePlus: typeof import('~icons/lucide/plus')['default']
IconLucidePlusCircle: typeof import('~icons/lucide/plus-circle')['default']
IconLucideRss: typeof import('~icons/lucide/rss')['default']
IconLucideSearch: typeof import('~icons/lucide/search')['default']

View file

@ -16,13 +16,17 @@
@edit-environment="editEnvironment('Global')"
/>
</div>
<EnvironmentsMy v-show="isPersonalEnvironmentType" />
<EnvironmentsMy
v-show="isPersonalEnvironmentType"
@select-environment="handleEnvironmentChange"
/>
<EnvironmentsTeams
v-show="environmentType.type === 'team-environments'"
:team="environmentType.selectedTeam"
:team-environments="teamEnvironmentList"
:loading="loading"
:adapter-error="adapterError"
@select-environment="handleEnvironmentChange"
/>
<EnvironmentsMyDetails
:show="showModalDetails"
@ -67,6 +71,7 @@ import {
deleteTeamEnvironment,
} from "~/helpers/backend/mutations/TeamEnvironment"
import { getEnvActionErrorMessage } from "~/helpers/error-messages"
import { TeamEnvironment } from "~/helpers/teams/TeamEnvironment"
import TeamEnvironmentAdapter from "~/helpers/teams/TeamEnvironmentAdapter"
import {
createEnvironment,
@ -214,6 +219,38 @@ const displayModalEdit = (shouldDisplay: boolean) => {
if (!shouldDisplay) resetSelectedData()
}
export type HandleEnvChangeProp = {
index: number
env?:
| {
type: "my-environment"
environment: Environment
}
| {
type: "team-environment"
environment: TeamEnvironment
}
}
const handleEnvironmentChange = ({ index, env }: HandleEnvChangeProp) => {
if (env?.type === "my-environment") {
selectedEnvironmentIndex.value = {
type: "MY_ENV",
index,
}
return
}
if (env?.type === "team-environment") {
selectedEnvironmentIndex.value = {
type: "TEAM_ENV",
teamEnvID: env.environment.id,
teamID: env.environment.teamID,
environment: env.environment.environment,
}
}
}
const editEnvironment = (environmentIndex: "Global") => {
editingEnvironmentIndex.value = environmentIndex
action.value = "edit"

View file

@ -4,27 +4,42 @@
@contextmenu.prevent="options!.tippy?.show()"
>
<span
v-if="environmentIndex === 'Global'"
class="flex cursor-pointer items-center justify-center px-4"
@click="emit('edit-environment')"
@click="emit('select-environment')"
>
<icon-lucide-globe class="svg-icons" />
</span>
<span
v-else
class="flex cursor-pointer items-center justify-center px-4"
@click="emit('edit-environment')"
>
<icon-lucide-layers class="svg-icons" />
<icon-lucide-globe
v-if="environmentIndex === 'Global'"
class="svg-icons"
/>
<icon-lucide-check-circle
v-else-if="selected"
class="svg-icons text-green-500"
/>
<icon-lucide-layers v-else class="svg-icons" />
</span>
<span
class="flex min-w-0 flex-1 cursor-pointer py-2 pr-2 transition group-hover:text-secondaryDark"
@click="emit('edit-environment')"
@click="emit('select-environment')"
>
<span class="truncate">
{{ environment.name }}
</span>
<span class="truncate"> {{ environment.name }} </span>
</span>
<div class="flex">
<HoppButtonSecondary
v-tippy="{ theme: 'tooltip' }"
:icon="IconEdit"
:title="`${t('action.edit')}`"
class="hidden group-hover:inline-flex"
@click="emit('edit-environment')"
/>
<HoppButtonSecondary
v-tippy="{ theme: 'tooltip' }"
:icon="IconCopy"
:title="`${t('action.duplicate')}`"
class="hidden group-hover:inline-flex"
@click="duplicateEnvironments"
/>
</div>
<span>
<tippy
ref="options"
@ -150,16 +165,19 @@ const props = withDefaults(
environmentIndex: number | "Global" | null
duplicateGlobalEnvironmentLoading?: boolean
showContextMenuLoadingState?: boolean
selected?: boolean
}>(),
{
duplicateGlobalEnvironmentLoading: false,
showContextMenuLoadingState: false,
selected: false,
}
)
const emit = defineEmits<{
(e: "edit-environment"): void
(e: "duplicate-global-environment"): void
(e: "select-environment"): void
}>()
const confirmRemove = ref(false)

View file

@ -30,7 +30,9 @@
:key="`environment-${index}`"
:environment-index="index"
:environment="env"
:selected="isEnvironmentSelected(index)"
@edit-environment="editEnvironment(index)"
@select-environment="selectEnvironment(index, env)"
/>
<HoppSmartPlaceholder
v-if="!alphabeticallySortedPersonalEnvironments.length"
@ -80,7 +82,10 @@
<script setup lang="ts">
import { ref, computed } from "vue"
import { environments$ } from "~/newstore/environments"
import {
environments$,
selectedEnvironmentIndex$,
} from "~/newstore/environments"
import { useColorMode } from "~/composables/theming"
import { useReadonlyStream } from "@composables/stream"
import { useI18n } from "~/composables/i18n"
@ -89,10 +94,16 @@ import IconImport from "~icons/lucide/folder-down"
import IconHelpCircle from "~icons/lucide/help-circle"
import { defineActionHandler } from "~/helpers/actions"
import { sortPersonalEnvironmentsAlphabetically } from "~/helpers/utils/sortEnvironmentsAlphabetically"
import { HandleEnvChangeProp } from "../index.vue"
import { Environment } from "@hoppscotch/data"
const t = useI18n()
const colorMode = useColorMode()
const emit = defineEmits<{
(e: "select-environment", data: HandleEnvChangeProp): void
}>()
const environments = useReadonlyStream(environments$, [])
// Sort environments alphabetically by default
@ -120,6 +131,15 @@ const displayModalEdit = (shouldDisplay: boolean) => {
const displayModalImportExport = (shouldDisplay: boolean) => {
showModalImportExport.value = shouldDisplay
}
const selectEnvironment = (index: number, environment: Environment) => {
emit("select-environment", {
index,
env: {
type: "my-environment",
environment,
},
})
}
const editEnvironment = (environmentIndex: number) => {
editingEnvironmentIndex.value = environmentIndex
action.value = "edit"
@ -131,6 +151,17 @@ const resetSelectedData = () => {
secretOptionSelected.value = false
}
const selectedEnvironmentIndex = useReadonlyStream(selectedEnvironmentIndex$, {
type: "NO_ENV_SELECTED",
})
const isEnvironmentSelected = (index: number) => {
return (
selectedEnvironmentIndex.value.type === "MY_ENV" &&
selectedEnvironmentIndex.value.index === index
)
}
defineActionHandler(
"modals.my.environment.edit",
({ envName, variableName, isSecret }) => {

View file

@ -5,18 +5,39 @@
>
<span
class="flex cursor-pointer items-center justify-center px-4"
@click="emit('edit-environment')"
@click="emit('select-environment')"
>
<icon-lucide-layers class="svg-icons" />
<icon-lucide-check-circle
v-if="selected"
class="svg-icons text-green-500"
/>
<icon-lucide-layers v-else class="svg-icons" />
</span>
<span
class="flex min-w-0 flex-1 cursor-pointer py-2 pr-2 transition group-hover:text-secondaryDark"
@click="emit('edit-environment')"
@click="emit('select-environment')"
>
<span class="truncate">
{{ environment.environment.name }}
</span>
</span>
<div class="flex">
<HoppButtonSecondary
v-tippy="{ theme: 'tooltip' }"
:icon="IconEdit"
:title="`${t('action.edit')}`"
class="hidden group-hover:inline-flex"
@click="emit('edit-environment')"
/>
<HoppButtonSecondary
v-tippy="{ theme: 'tooltip' }"
:icon="IconCopy"
:title="`${t('action.duplicate')}`"
class="hidden group-hover:inline-flex"
@click="duplicateEnvironment"
/>
</div>
<span>
<tippy
ref="options"
@ -152,11 +173,13 @@ const toast = useToast()
const props = defineProps<{
environment: TeamEnvironment
isViewer: boolean
selected?: boolean
}>()
const emit = defineEmits<{
(e: "edit-environment"): void
(e: "show-environment-properties"): void
(e: "select-environment"): void
}>()
const secretEnvironmentService = useService(SecretEnvironmentService)

View file

@ -89,7 +89,9 @@
:key="`environment-${index}`"
:environment="env"
:is-viewer="team?.role === 'VIEWER'"
:selected="isEnvironmentSelected(env.id)"
@edit-environment="editEnvironment(env)"
@select-environment="selectEnvironment(env)"
@show-environment-properties="
showEnvironmentProperties(env.environment.id)
"
@ -147,6 +149,9 @@ import { defineActionHandler } from "~/helpers/actions"
import { TeamWorkspace } from "~/services/workspace.service"
import { sortTeamEnvironmentsAlphabetically } from "~/helpers/utils/sortEnvironmentsAlphabetically"
import { getEnvActionErrorMessage } from "~/helpers/error-messages"
import { HandleEnvChangeProp } from "../index.vue"
import { selectedEnvironmentIndex$ } from "~/newstore/environments"
import { useReadonlyStream } from "~/composables/stream"
const t = useI18n()
@ -159,6 +164,10 @@ const props = defineProps<{
loading: boolean
}>()
const emit = defineEmits<{
(e: "select-environment", data: HandleEnvChangeProp): void
}>()
// Sort environments alphabetically by default
const alphabeticallySortedTeamEnvironments = computed(() =>
@ -207,6 +216,27 @@ const showEnvironmentProperties = (environmentID: string) => {
selectedEnvironmentID.value = environmentID
}
const selectEnvironment = (environment: TeamEnvironment) => {
emit("select-environment", {
index: 1,
env: {
type: "team-environment",
environment,
},
})
}
const selectedEnvironmentIndex = useReadonlyStream(selectedEnvironmentIndex$, {
type: "NO_ENV_SELECTED",
})
const isEnvironmentSelected = (id: string) => {
return (
selectedEnvironmentIndex.value.type === "TEAM_ENV" &&
selectedEnvironmentIndex.value.teamEnvID === id
)
}
defineActionHandler(
"modals.team.environment.edit",
({ envName, variableName, isSecret }) => {