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

Renaming project in GUI #10243

Merged
merged 14 commits into from
Jun 21, 2024
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@
- [Copy-pasting multiple nodes][10194].
- The documentation editor has [formatting toolbars][10064].
- The documentation editor supports [rendering images][10205].
- [Project may be renamed in Project View][10243]

[10064]: https://github.com/enso-org/enso/pull/10064
[10179]: https://github.com/enso-org/enso/pull/10179
[10194]: https://github.com/enso-org/enso/pull/10194
[10198]: https://github.com/enso-org/enso/pull/10198
[10205]: https://github.com/enso-org/enso/pull/10205
[10243]: https://github.com/enso-org/enso/pull/10243

#### Enso Standard Library

Expand Down
5 changes: 5 additions & 0 deletions app/gui2/shared/languageServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,11 @@ export class LanguageServer extends ObservableV2<Notifications & TransportEvents
return this.request('refactoring/renameSymbol', { module, expressionId, newName })
}

/** [Documentation](https://github.com/enso-org/enso/blob/develop/docs/language-server/protocol-language-server.md#refactoringrenameproject) */
renameProject(namespace: string, oldName: string, newName: string): Promise<LsRpcResult<void>> {
return this.request('refactoring/renameProject', { namespace, oldName, newName })
}

/** [Documentation](https://github.com/enso-org/enso/blob/develop/docs/language-server/protocol-language-server.md#profilingstart) */
profilingStart(memorySnapshot?: boolean): Promise<LsRpcResult<void>> {
return this.request('profiling/start', { memorySnapshot })
Expand Down
6 changes: 5 additions & 1 deletion app/gui2/shared/languageServerTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,11 @@ export type Notifications = {
'file/event': (param: { path: Path; kind: FileEventKind }) => void
'file/rootAdded': (param: {}) => void
'file/rootRemoved': (param: {}) => void
'refactoring/projectRenamed': (param: {}) => void
'refactoring/projectRenamed': (param: {
oldNormalizedName: string
newNormalizedName: string
newName: string
}) => void
}

export type Event<T extends keyof Notifications> = Parameters<Notifications[T]>[0]
Expand Down
9 changes: 8 additions & 1 deletion app/gui2/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const props = defineProps<{
logEvent: LogEvent
hidden: boolean
ignoreParamsRegex?: RegExp
renameProject: (newName: string) => void
}>()

const classSet = provideAppClassSet()
Expand Down Expand Up @@ -71,7 +72,13 @@ registerAutoBlurHandler()
:unrecognizedOptions="appConfig.unrecognizedOptions"
:config="appConfig.config"
/>
<ProjectView v-else v-show="!props.hidden" class="App" :class="[...classSet.keys()]" />
<ProjectView
v-else
v-show="!props.hidden"
class="App"
:class="[...classSet.keys()]"
:renameProject="renameProject"
/>
<Teleport to="body">
<TooltipDisplayer :registry="appTooltips" />
</Teleport>
Expand Down
14 changes: 4 additions & 10 deletions app/gui2/src/components/GraphEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,18 @@ import { useDoubleClick } from '@/composables/doubleClick'
import { keyboardBusy, keyboardBusyExceptIn, unrefElement, useEvent } from '@/composables/events'
import { groupColorVar } from '@/composables/nodeColors'
import type { PlacementStrategy } from '@/composables/nodeCreation'
import { useStackNavigator } from '@/composables/stackNavigator'
import { useSyncLocalStorage } from '@/composables/syncLocalStorage'
import { provideGraphNavigator, type GraphNavigator } from '@/providers/graphNavigator'
import { provideNodeColors } from '@/providers/graphNodeColors'
import { provideNodeCreation } from '@/providers/graphNodeCreation'
import { provideGraphSelection } from '@/providers/graphSelection'
import { provideStackNavigator } from '@/providers/graphStackNavigator'
import { provideInteractionHandler } from '@/providers/interactionHandler'
import { provideKeyboard } from '@/providers/keyboard'
import { provideWidgetRegistry } from '@/providers/widgetRegistry'
import { provideGraphStore, type NodeId } from '@/stores/graph'
import type { RequiredImport } from '@/stores/graph/imports'
import { provideProjectStore } from '@/stores/project'
import { useProjectStore } from '@/stores/project'
import { provideSuggestionDbStore } from '@/stores/suggestionDatabase'
import type { Typename } from '@/stores/suggestionDatabase/entry'
import { provideVisualizationStore } from '@/stores/visualization'
Expand Down Expand Up @@ -69,7 +69,7 @@ import {
} from 'vue'

const keyboard = provideKeyboard()
const projectStore = provideProjectStore()
const projectStore = useProjectStore()
const suggestionDb = provideSuggestionDbStore(projectStore)
const graphStore = provideGraphStore(projectStore, suggestionDb)
const widgetRegistry = provideWidgetRegistry(graphStore.db)
Expand Down Expand Up @@ -193,7 +193,7 @@ function panToSelected() {

// == Breadcrumbs ==

const stackNavigator = useStackNavigator(projectStore, graphStore)
const stackNavigator = provideStackNavigator(projectStore, graphStore)

// === Toasts ===

Expand Down Expand Up @@ -703,14 +703,8 @@ const groupColors = computed(() => {
v-model:showColorPicker="showColorPicker"
v-model:showCodeEditor="showCodeEditor"
v-model:showDocumentationEditor="showDocumentationEditor"
:breadcrumbs="stackNavigator.breadcrumbLabels.value"
:allowNavigationLeft="stackNavigator.allowNavigationLeft.value"
:allowNavigationRight="stackNavigator.allowNavigationRight.value"
:zoomLevel="100.0 * graphNavigator.targetScale"
:componentsSelected="nodeSelection.selected.size"
@breadcrumbClick="stackNavigator.handleBreadcrumbClick"
@back="stackNavigator.exitNode"
@forward="stackNavigator.enterNextNodeFromHistory"
@recordOnce="onRecordOnceButtonPress()"
@fitToAllClicked="zoomToSelected"
@zoomIn="graphNavigator.stepZoom(+1)"
Expand Down
20 changes: 8 additions & 12 deletions app/gui2/src/components/NavBar.vue
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
<script setup lang="ts">
import NavBreadcrumbs, { type BreadcrumbItem } from '@/components/NavBreadcrumbs.vue'
import NavBreadcrumbs from '@/components/NavBreadcrumbs.vue'
import SvgIcon from '@/components/SvgIcon.vue'
import { injectStackNavigator } from '@/providers/graphStackNavigator'
import SvgButton from './SvgButton.vue'

const props = defineProps<{
breadcrumbs: BreadcrumbItem[]
allowNavigationLeft: boolean
allowNavigationRight: boolean
}>()
const emit = defineEmits<{ back: []; forward: []; breadcrumbClick: [index: number] }>()
const stackNavigator = injectStackNavigator()
</script>

<template>
Expand All @@ -17,18 +13,18 @@ const emit = defineEmits<{ back: []; forward: []; breadcrumbClick: [index: numbe
<div class="breadcrumbs-controls">
<SvgButton
name="arrow_left"
:disabled="!props.allowNavigationLeft"
:disabled="!stackNavigator.allowNavigationLeft"
title="Back"
@click.stop="emit('back')"
@click.stop="stackNavigator.exitNode"
/>
<SvgButton
name="arrow_right"
:disabled="!props.allowNavigationRight"
:disabled="!stackNavigator.allowNavigationRight"
title="Forward"
@click.stop="emit('forward')"
@click.stop="stackNavigator.enterNextNodeFromHistory"
/>
</div>
<NavBreadcrumbs :breadcrumbs="props.breadcrumbs" @selected="emit('breadcrumbClick', $event)" />
<NavBreadcrumbs />
</div>
</template>

Expand Down
23 changes: 20 additions & 3 deletions app/gui2/src/components/NavBreadcrumb.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,27 @@
<script setup lang="ts">
const props = defineProps<{ text: string; active: boolean }>()
import { ref, watch, type ComponentInstance } from 'vue'
import AutoSizedInput from './widgets/AutoSizedInput.vue'

const model = defineModel<string>({ required: true })
const _props = defineProps<{ active: boolean; editing: boolean }>()
const emit = defineEmits<{ renamed: [newName: string] }>()

const input = ref<ComponentInstance<typeof AutoSizedInput>>()
watch(input, (input, old) => {
if (old == null && input != null) input.focus()
})
</script>

<template>
<div :class="['NavBreadcrumb', { inactive: !props.active }]">
<span v-text="props.text"></span>
<div :class="['NavBreadcrumb', { inactive: !active }]">
<AutoSizedInput
v-if="editing"
ref="input"
v-model.lazy="model"
:autoSelect="true"
@change="emit('renamed', $event ?? '')"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the AutoSizedInput changes, this component emits both update:modelValue and renamed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the renamed event is redundant, removed.

/>
<span v-else v-text="model"></span>
</div>
</template>

Expand Down
31 changes: 25 additions & 6 deletions app/gui2/src/components/NavBreadcrumbs.vue
Original file line number Diff line number Diff line change
@@ -1,31 +1,50 @@
<script setup lang="ts">
import NavBreadcrumb from '@/components/NavBreadcrumb.vue'
import SvgButton from '@/components/SvgButton.vue'
import { injectStackNavigator } from '@/providers/graphStackNavigator'
import { useProjectStore } from '@/stores/project'
import { useToast } from '@/util/toast'
import { ref } from 'vue'

export interface BreadcrumbItem {
label: string
active: boolean
}
const renameError = useToast.error()
const projectNameEdited = ref(false)

const props = defineProps<{ breadcrumbs: BreadcrumbItem[] }>()
const emit = defineEmits<{ selected: [index: number] }>()
const stackNavigator = injectStackNavigator()
const project = useProjectStore()

async function renameBreadcrumb(index: number, newName: string) {
if (index === 0) {
const result = await project.renameProject(newName)
if (!result.ok) {
renameError.reportError(result.error)
}
projectNameEdited.value = false
}
}
</script>

<template>
<div class="NavBreadcrumbs">
<template v-for="(breadcrumb, index) in props.breadcrumbs" :key="index">
<SvgButton name="edit" title="Edit Project Name" @click.stop="projectNameEdited = true" />
<template v-for="(breadcrumb, index) in stackNavigator.breadcrumbLabels.value" :key="index">
<SvgButton
v-if="index > 0"
name="arrow_right_head_only"
:disabled="breadcrumb.active"
:disabled="!breadcrumb.active"
class="arrow"
/>
<NavBreadcrumb
:text="breadcrumb.label"
:modelValue="breadcrumb.label"
:active="breadcrumb.active"
:editing="index === 0 && projectNameEdited"
:title="index === 0 ? 'Project Name' : ''"
class="clickable"
@click.stop="emit('selected', index)"
@click.stop="stackNavigator.handleBreadcrumbClick(index)"
@renamed="renameBreadcrumb(index, $event)"
/>
</template>
</div>
Expand Down
16 changes: 1 addition & 15 deletions app/gui2/src/components/TopBar.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<script setup lang="ts">
import ExtendedMenu from '@/components/ExtendedMenu.vue'
import NavBar from '@/components/NavBar.vue'
import type { BreadcrumbItem } from '@/components/NavBreadcrumbs.vue'
import RecordControl from '@/components/RecordControl.vue'
import SelectionMenu from '@/components/SelectionMenu.vue'
import { injectGuiConfig } from '@/providers/guiConfig'
Expand All @@ -11,18 +10,12 @@ const showColorPicker = defineModel<boolean>('showColorPicker', { required: true
const showCodeEditor = defineModel<boolean>('showCodeEditor', { required: true })
const showDocumentationEditor = defineModel<boolean>('showDocumentationEditor', { required: true })
const props = defineProps<{
breadcrumbs: BreadcrumbItem[]
recordMode: boolean
allowNavigationLeft: boolean
allowNavigationRight: boolean
zoomLevel: number
componentsSelected: number
}>()
const emit = defineEmits<{
recordOnce: []
back: []
forward: []
breadcrumbClick: [index: number]
'update:recordMode': [enabled: boolean]
fitToAllClicked: []
zoomIn: []
Expand Down Expand Up @@ -50,14 +43,7 @@ const barStyle = computed(() => {
@update:recordMode="emit('update:recordMode', $event)"
@recordOnce="emit('recordOnce')"
/>
<NavBar
:breadcrumbs="props.breadcrumbs"
:allowNavigationLeft="props.allowNavigationLeft"
:allowNavigationRight="props.allowNavigationRight"
@back="emit('back')"
@forward="emit('forward')"
@breadcrumbClick="emit('breadcrumbClick', $event)"
/>
<NavBar />
<Transition name="selection-menu">
<SelectionMenu
v-if="componentsSelected > 1"
Expand Down
5 changes: 5 additions & 0 deletions app/gui2/src/providers/graphStackNavigator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { useStackNavigator } from '@/composables/stackNavigator'
import { createContextStore } from '@/providers'

export { injectFn as injectStackNavigator, provideFn as provideStackNavigator }
const { provideFn, injectFn } = createContextStore('graph stack navigator', useStackNavigator)
Loading
Loading