Allow Sidebar to be Disabled (#2343)

* WIP: based on Issue-1562

* Add changes to swap focus.

* Swap some function names.

Also enforce swapping to the previous split on hide.
This commit is contained in:
Ryan C 2018-06-23 20:44:01 +01:00 committed by GitHub
parent 081be2ddf0
commit f8d4528174
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 113 additions and 60 deletions

View File

@ -6,11 +6,11 @@ First, thank you for considering contributing to oni! It's people like you that
We welcome any type of contribution, not only code. You can help with
* **QA**: file bug reports, the more details you can give the better (e.g. screenshots with the console open)
* **Marketing**: writing blog posts, howto's, printing stickers, ...
* **Community**: presenting the project at meetups, organizing a dedicated meetup for the local community, ...
* **Code**: take a look at the [open issues](issues). Even if you can't write code, commenting on them, showing that you care about a given issue matters. It helps us triage them.
* **Money**: we welcome financial contributions in full transparency on our [open collective](https://opencollective.com/oni).
* **QA**: file bug reports, the more details you can give the better (e.g. screenshots with the console open)
* **Marketing**: writing blog posts, howto's, printing stickers, ...
* **Community**: presenting the project at meetups, organizing a dedicated meetup for the local community, ...
* **Code**: take a look at the [open issues](issues). Even if you can't write code, commenting on them, showing that you care about a given issue matters. It helps us triage them.
* **Money**: we welcome financial contributions in full transparency on our [open collective](https://opencollective.com/oni).
## Your First Contribution
@ -22,11 +22,11 @@ Any code change should be submitted as a pull request. The description should ex
## Code review guidelines
* Keep PRs **small and scoped**. The bigger the pull request, the longer it will take to review and merge. Break down large pull requests into smaller incremental chunks - this will help catch issues earlier and be easier on both you and the maintainer.
* Following from the previous bullet point, **do not include unrelated changes in a PR**. It can be tempting to include extra styling changes or additional functionality, but these should be added as separate PRs.
* Think of each PR as **improving the quality of the codebase**. Codebases tend towards entropy and disorder unless actively managed - make sure that your change moves the quality needle in the right direction. This can take a variety of forms, including adding test coverage, reducing coupling, etc. _As we are a small team moving fast, we cannot afford to accumulate technical debt._
* If there is ambiguity in terms of design, architecture, or implementation, it's best to get **feedback before implementing**, to save both you and the maintainer time. If you're not sure, feel free to ask!
* For your first few PRs, **don't try and change the world** - pick some small issues and get familiar with the codebase. Then, work your way up to bigger issues - this will set you up for success.
* Keep PRs **small and scoped**. The bigger the pull request, the longer it will take to review and merge. Break down large pull requests into smaller incremental chunks - this will help catch issues earlier and be easier on both you and the maintainer.
* Following from the previous bullet point, **do not include unrelated changes in a PR**. It can be tempting to include extra styling changes or additional functionality, but these should be added as separate PRs.
* Think of each PR as **improving the quality of the codebase**. Codebases tend towards entropy and disorder unless actively managed - make sure that your change moves the quality needle in the right direction. This can take a variety of forms, including adding test coverage, reducing coupling, etc. _As we are a small team moving fast, we cannot afford to accumulate technical debt._
* If there is ambiguity in terms of design, architecture, or implementation, it's best to get **feedback before implementing**, to save both you and the maintainer time. If you're not sure, feel free to ask!
* For your first few PRs, **don't try and change the world** - pick some small issues and get familiar with the codebase. Then, work your way up to bigger issues - this will set you up for success.
PRs require approval from one other person, either a maintainer or a contributor. Keep in mind that when you approve code, you are accountable for it, too! Reviewers are the gatekeepers of quality and ensuring adherence to the guidelines above.
@ -39,15 +39,15 @@ Anyone can file an expense. If the expense makes sense for the development of th
The primary allotment of our [open collective](https://opencollective.com/oni) budget is dedicated to bounties. Developing features and fixing bugs is a lot of work, and those go directly to the developers doing this work via bounties. It is the role of the _maintainer_ to set bounties and clear completion criteria. Issues that have a bounty associated with them will have a `bounty` label as well as an amount, ie, `bounty-50` means a $50 bounty.
* Guidelines:
* The fix for the bug/feature/issue _MUST_ be complete and _MUST_ be covered by tests to be eligible for a bounty.
* Any associated documentation relevant to the bug/feature _MUST_ be updated.
* If you begin working on an issue with an associated bounty, open a PR with "WIP" and the bug number in the title, as well as reference the issue #. This is important to reduce duplicate work.
* Guidelines:
* The fix for the bug/feature/issue _MUST_ be complete and _MUST_ be covered by tests to be eligible for a bounty.
* Any associated documentation relevant to the bug/feature _MUST_ be updated.
* If you begin working on an issue with an associated bounty, open a PR with "WIP" and the bug number in the title, as well as reference the issue #. This is important to reduce duplicate work.
#### Claiming a bounty
* Upon completion of an issue with an associated bounty, bounties are payable by [Submitting an Expense](https://opencollective.com/oni/expenses/new) on our [OpenCollective](https://opencollective.com/oni). Note that OpenCollective requires a PDF or Photo of an expense form for an expense claim to be accepted - more information, including an example expense form can be found [here](https://opencollective.com/faq#expense). Check out our [expenses](https://opencollective.com/oni/expenses#) page for an example.
* A collaborator will approve the expense once we have verified it meets the criteria outlined above (complete fix, covered by tests, associated documentation updated)
* Upon completion of an issue with an associated bounty, bounties are payable by [Submitting an Expense](https://opencollective.com/oni/expenses/new) on our [OpenCollective](https://opencollective.com/oni). Note that OpenCollective requires a PDF or Photo of an expense form for an expense claim to be accepted - more information, including an example expense form can be found [here](https://opencollective.com/faq#expense). Check out our [expenses](https://opencollective.com/oni/expenses#) page for an example.
* A collaborator will approve the expense once we have verified it meets the criteria outlined above (complete fix, covered by tests, associated documentation updated)
If you questions about the guidelines, please don't hesitate to contact the maintainer.
@ -55,17 +55,17 @@ If you questions about the guidelines, please don't hesitate to contact the main
There are various roles and responsibilities in managing an open-source project. Users that are active and have a positive impact on the project and community will be recognized and have the option of assuming additional responsibilities.
* **Maintainer** - A maintainer communicates goals and drives the vision for the project. The maintainer is responsible for breaking down hurdles and supporting contributors. In addition, the maintainer triages issues, produces releases, assigns bounties, and establishes completion criteria. Today, there is one maintainer, but that isn't a strict requirement.
* **Collaborator** - A collaborator is an established member of the project that is recognized for their impact and contributions. They can triage and close issues, approve PRs from other contributors / collaborators, and can approve expenses on our [open collective](https://opencollective.com/oni)
* **Contributor** - A contributor is a developer that has submitted a successful PR for the project.
* **Maintainer** - A maintainer communicates goals and drives the vision for the project. The maintainer is responsible for breaking down hurdles and supporting contributors. In addition, the maintainer triages issues, produces releases, assigns bounties, and establishes completion criteria. Today, there is one maintainer, but that isn't a strict requirement.
* **Collaborator** - A collaborator is an established member of the project that is recognized for their impact and contributions. They can triage and close issues, approve PRs from other contributors / collaborators, and can approve expenses on our [open collective](https://opencollective.com/oni)
* **Contributor** - A contributor is a developer that has submitted a successful PR for the project.
### Becoming a collaborator
A collaborator is a contributor who has been recognized for the impact they've had on the project, over a sustained period of time. In general, this means the following:
* **Supporting the community** - helping others in issues and chat, supporting new developers, creating a positive and supportive environment.
* **Technical impact** - involvement in a core technical piece of the editor, or a broad impact on the ecosystem.
* **Positive and collaborative mindset** - creating good vibes, willingness to give and receive constructive feedback, being a team player.
* **Supporting the community** - helping others in issues and chat, supporting new developers, creating a positive and supportive environment.
* **Technical impact** - involvement in a core technical piece of the editor, or a broad impact on the ecosystem.
* **Positive and collaborative mindset** - creating good vibes, willingness to give and receive constructive feedback, being a team player.
## Questions

View File

@ -47,6 +47,7 @@ export const applyDefaultKeyBindings = (oni: Oni.Plugin.Api, config: Configurati
input.bind("<m-h>", "oni.editor.hide")
input.bind("<c-tab>", "buffer.toggle")
input.bind("<m-s-f>", "search.searchAllFiles")
input.bind("<m-s-e>", "explorer.toggle")
input.bind("<m-s-_>", "sidebar.decreaseWidth")
input.bind("<m-s-+>", "sidebar.increaseWidth")
input.bind("<m-,>", "oni.config.openConfigJs")
@ -71,6 +72,7 @@ export const applyDefaultKeyBindings = (oni: Oni.Plugin.Api, config: Configurati
input.bind("<s-c-t>", "language.symbols.document")
input.bind("<c-tab>", "buffer.toggle")
input.bind("<s-c-f>", "search.searchAllFiles")
input.bind("<s-c-e>", "explorer.toggle")
input.bind("<c-,>", "oni.config.openConfigJs")
if (config.getValue("editor.clipboard.enabled")) {

View File

@ -332,7 +332,9 @@ const mapStateToProps = (
containerProps: IExplorerViewContainerProps,
): IExplorerViewProps => {
const yanked = state.register.yank.map(node => node.id)
const { register: { updated, rename } } = state
const {
register: { updated, rename },
} = state
return {
...containerProps,
isActive: state.hasFocus,

View File

@ -30,4 +30,16 @@ export const activate = (
"files-o",
new ExplorerSplit(configuration, workspace, commandManager, editorManager),
)
const toggleExplorer = () => {
sidebarManager.toggleVisibilityById("oni.sidebar.explorer")
}
commandManager.registerCommand({
command: "explorer.toggle",
name: "Explorer: Toggle Visibility",
detail: "Toggles the explorer in the sidebar",
execute: toggleExplorer,
enabled: () => !!workspace.activeWorkspace,
})
}

View File

@ -135,7 +135,7 @@ export const activate = (
sidebarManager.add("search", new SearchPane(editorManager, workspace, onFocusEvent))
const searchAllFiles = () => {
sidebarManager.setActiveEntry("oni.sidebar.search")
sidebarManager.toggleVisibilityById("oni.sidebar.search")
onFocusEvent.dispatch()
}

View File

@ -80,13 +80,8 @@ export class SidebarManager {
this.setWidth(this._configuration.getValue("sidebar.width"))
if (_windowManager) {
this._iconSplit = this._windowManager.createSplit("left", new SidebarSplit(this))
this._contentSplit = this._windowManager.createSplit(
"left",
new SidebarContentSplit(this),
)
}
this._iconSplit = this._windowManager.createSplit("left", new SidebarSplit(this))
this._contentSplit = this._windowManager.createSplit("left", new SidebarContentSplit(this))
}
public increaseWidth(): void {
@ -156,6 +151,28 @@ export class SidebarManager {
}
}
public toggleVisibilityById(id: string): void {
if (id) {
if (id !== this.activeEntryId) {
this._store.dispatch({
type: "SET_ACTIVE_ID",
activeEntryId: id,
})
this._contentSplit.show()
this._contentSplit.focus()
} else {
if (this._contentSplit.isVisible) {
this._contentSplit.hide()
} else {
// In some cases you can have an ACTIVE entry that is hidden
this._contentSplit.show()
this._contentSplit.focus()
}
}
}
}
public enter(): void {
this._store.dispatch({ type: "ENTER" })
}
@ -175,6 +192,11 @@ export class SidebarManager {
entry,
})
}
public hide(): void {
this._contentSplit.hide()
this._iconSplit.hide()
}
}
const DefaultSidebarState: ISidebarState = {

View File

@ -10,35 +10,40 @@ let _sidebarManager: SidebarManager = null
export * from "./SidebarStore"
export const activate = (configuration: Configuration, workspace: Workspace) => {
if (configuration.getValue("sidebar.enabled")) {
_sidebarManager = new SidebarManager(windowManager, configuration)
if (!configuration.getValue("sidebar.default.open")) {
_sidebarManager.toggleSidebarVisibility()
}
// Always create the sidebar to prevent issues. If its disabled, just hide it.
// See #1562 for more information.
_sidebarManager = new SidebarManager(windowManager, configuration)
commandManager.registerCommand({
command: "sidebar.increaseWidth",
name: "Sidebar: Increase Width",
detail: "Increase the width of the sidebar pane",
execute: () => _sidebarManager.increaseWidth(),
})
const sideBarEnabled = configuration.getValue("sidebar.enabled")
commandManager.registerCommand({
command: "sidebar.decreaseWidth",
name: "Sidebar: Decrease Width",
detail: "Decrease the width of the sidebar pane",
execute: () => _sidebarManager.decreaseWidth(),
})
commandManager.registerCommand({
command: "sidebar.toggle",
name: "Sidebar: Toggle",
detail: "Show / hide the contents of the sidebar pane.",
execute: () => _sidebarManager.toggleSidebarVisibility(),
})
} else {
_sidebarManager = new SidebarManager(null, configuration)
if (!sideBarEnabled) {
_sidebarManager.hide()
}
if (sideBarEnabled && !configuration.getValue("sidebar.default.open")) {
_sidebarManager.toggleSidebarVisibility()
}
commandManager.registerCommand({
command: "sidebar.increaseWidth",
name: "Sidebar: Increase Width",
detail: "Increase the width of the sidebar pane",
execute: () => _sidebarManager.increaseWidth(),
})
commandManager.registerCommand({
command: "sidebar.decreaseWidth",
name: "Sidebar: Decrease Width",
detail: "Decrease the width of the sidebar pane",
execute: () => _sidebarManager.decreaseWidth(),
})
commandManager.registerCommand({
command: "sidebar.toggle",
name: "Sidebar: Toggle",
detail: "Show / hide the contents of the sidebar pane.",
execute: () => _sidebarManager.toggleSidebarVisibility(),
})
}
export const getInstance = (): SidebarManager => _sidebarManager

View File

@ -52,6 +52,8 @@ export class WindowSplitHandle implements Oni.WindowSplitHandle {
type: "HIDE_SPLIT",
splitId: this._id,
})
this._windowManager.swapToPreviousSplit(this._id)
}
public show(): void {
@ -260,6 +262,13 @@ export class WindowManager {
}
public close(splitId: string) {
this.swapToPreviousSplit(splitId)
delete this._idToSplit[splitId]
}
// Swaps focus to the most recently focused window, and hides
// the passed split.
public swapToPreviousSplit(splitId: string) {
const currentActiveSplit = this.activeSplit
// Send focus back to most recently focused window
@ -284,8 +293,6 @@ export class WindowManager {
type: "SET_PRIMARY_SPLITS",
splits: state,
})
delete this._idToSplit[splitId]
}
public focusSplit(splitId: string): void {

View File

@ -588,7 +588,10 @@ describe("ExplorerStore", () => {
assert.deepEqual(head(newState), testAction)
})
describe("Register Reducer test", () => {
const { yankRegisterReducer, DefaultExplorerState: { register } } = ExplorerState
const {
yankRegisterReducer,
DefaultExplorerState: { register },
} = ExplorerState
it("It should add paste items to both the paste and undo registers", () => {
const newState = yankRegisterReducer(clone(register), pasteAction)