Skip to content

Commit 9ac694d

Browse files
authored
View bucket by entering bucket name/URI (#2722)
* Initial changes * ListBuckets required * View bucket with bucket name * detekt changes * minor change * minor change * dialog changes * detekt changes * feedback changes * Validation checks added based on resource * detekt changes * parameter removed * change log added
1 parent e5a4711 commit 9ac694d

File tree

17 files changed

+162
-67
lines changed

17 files changed

+162
-67
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type" : "feature",
3+
"description" : "Add ability to view bucket by entering bucket name/URI"
4+
}

jetbrains-core/resources/META-INF/plugin.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,8 @@ with what features/services are supported.
375375
<group id="aws.toolkit.explorer.s3" popup="false" compact="false">
376376
<action id="s3.create.bucket"
377377
class="software.aws.toolkits.jetbrains.services.s3.bucketActions.CreateBucketAction"/>
378+
<action id="s3.view.bucket"
379+
class="software.aws.toolkits.jetbrains.services.s3.bucketActions.ViewBucketAction"/>
378380
</group>
379381

380382
<group id="aws.toolkit.explorer.s3.bucket" popup="true" compact="false">
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package software.aws.toolkits.jetbrains.core.explorer
5+
6+
import com.intellij.openapi.project.Project
7+
import com.intellij.openapi.ui.DialogWrapper
8+
import com.intellij.ui.layout.panel
9+
import javax.swing.JComponent
10+
11+
class ViewResourceDialog(project: Project, val resourceType: String, actionTitle: String, checkResourceNameValidity: (resource: String?) -> Boolean) :
12+
DialogWrapper(project) {
13+
var resourceName = ""
14+
private val component by lazy {
15+
panel {
16+
row("$resourceType:") {
17+
textField(::resourceName).constraints(grow).withErrorOnApplyIf("$resourceType must be entered") {
18+
it.text.isNullOrBlank() || checkResourceNameValidity(it.text)
19+
}
20+
}
21+
}
22+
}
23+
24+
init {
25+
title = actionTitle
26+
init()
27+
}
28+
29+
override fun createCenterPanel(): JComponent = component
30+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package software.aws.toolkits.jetbrains.core.explorer.actions
5+
6+
import com.intellij.openapi.actionSystem.AnActionEvent
7+
import com.intellij.openapi.project.DumbAware
8+
import software.aws.toolkits.jetbrains.core.explorer.ViewResourceDialog
9+
import software.aws.toolkits.jetbrains.core.explorer.nodes.AwsExplorerNode
10+
11+
abstract class ViewResourceAction<in T : AwsExplorerNode<*>>(private val actionTitle: String, val resourceType: String) :
12+
SingleExplorerNodeAction<T>(actionTitle), DumbAware {
13+
14+
override fun actionPerformed(selected: T, e: AnActionEvent) {
15+
val getResourceNameDialog = ViewResourceDialog(selected.nodeProject, resourceType, actionTitle, this::checkResourceNameValidity)
16+
if (getResourceNameDialog.showAndGet()) {
17+
viewResource(getResourceNameDialog.resourceName, selected)
18+
}
19+
}
20+
21+
abstract fun viewResource(resourceToView: String, selected: T)
22+
23+
abstract fun checkResourceNameValidity(resourceName: String?): Boolean
24+
}

jetbrains-core/src/software/aws/toolkits/jetbrains/services/s3/S3ExplorerNode.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class S3BucketNode(project: Project, val bucket: Bucket) :
3232
override fun isAlwaysShowPlus(): Boolean = false
3333

3434
override fun onDoubleClick() {
35-
openEditor(nodeProject, bucket)
35+
openEditor(nodeProject, bucket.name())
3636
}
3737

3838
override fun displayName(): String = bucket.name()

jetbrains-core/src/software/aws/toolkits/jetbrains/services/s3/S3ViewerProvider.kt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import com.intellij.openapi.project.PossiblyDumbAware
1616
import com.intellij.openapi.project.Project
1717
import com.intellij.openapi.util.UserDataHolderBase
1818
import com.intellij.openapi.vfs.VirtualFile
19-
import software.amazon.awssdk.services.s3.model.Bucket
2019
import software.aws.toolkits.jetbrains.core.awsClient
2120
import software.aws.toolkits.jetbrains.services.s3.editor.S3ViewerPanel
2221
import software.aws.toolkits.jetbrains.services.s3.editor.S3VirtualBucket
@@ -77,11 +76,11 @@ class S3ViewerEditor(project: Project, private val bucket: S3VirtualBucket) : Us
7776
override fun setState(state: FileEditorState) {}
7877
}
7978

80-
fun openEditor(project: Project, bucket: Bucket, prefix: String = ""): Editor? = try {
79+
fun openEditor(project: Project, bucketName: String, prefix: String = ""): Editor? = try {
8180
FileEditorManager.getInstance(project).openTextEditor(
8281
OpenFileDescriptor(
8382
project,
84-
S3VirtualBucket(bucket, prefix, project.awsClient(), project)
83+
S3VirtualBucket(bucketName, prefix, project.awsClient(), project)
8584
),
8685
true
8786
).also {

jetbrains-core/src/software/aws/toolkits/jetbrains/services/s3/bucketActions/OpenBucketViewerAction.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@ import software.aws.toolkits.jetbrains.services.s3.openEditor
1010

1111
class OpenBucketViewerAction : SingleResourceNodeAction<S3BucketNode>(), DumbAware {
1212
override fun actionPerformed(selected: S3BucketNode, e: AnActionEvent) {
13-
openEditor(selected.nodeProject, selected.bucket)
13+
openEditor(selected.nodeProject, selected.bucket.name())
1414
}
1515
}

jetbrains-core/src/software/aws/toolkits/jetbrains/services/s3/bucketActions/OpenPrefixedBucketViewerAction.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,6 @@ class OpenPrefixedBucketViewerAction : SingleResourceNodeAction<S3BucketNode>(),
2828
return
2929
}
3030

31-
openEditor(selected.nodeProject, selected.bucket, prefix)
31+
openEditor(selected.nodeProject, selected.bucket.name(), prefix)
3232
}
3333
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package software.aws.toolkits.jetbrains.services.s3.bucketActions
5+
6+
import software.amazon.awssdk.services.s3.model.S3Exception
7+
import software.aws.toolkits.jetbrains.core.explorer.actions.ViewResourceAction
8+
import software.aws.toolkits.jetbrains.services.s3.S3ServiceNode
9+
import software.aws.toolkits.jetbrains.services.s3.openEditor
10+
import software.aws.toolkits.jetbrains.utils.notifyError
11+
import software.aws.toolkits.resources.message
12+
13+
class ViewBucketAction : ViewResourceAction<S3ServiceNode>(message("action.aws.toolkit.s3.open.bucket.viewer.text"), message("s3.bucket.label")) {
14+
15+
override fun viewResource(resourceToView: String, selected: S3ServiceNode) {
16+
try {
17+
if (resourceToView.startsWith("S3://", ignoreCase = true)) {
18+
openEditor(selected.nodeProject, resourceToView.split("S3://", ignoreCase = true).last().substringBefore("/"))
19+
} else {
20+
openEditor(selected.nodeProject, resourceToView)
21+
}
22+
} catch (e: S3Exception) {
23+
e.notifyError(message("s3.open.viewer.bucket.failed"))
24+
}
25+
}
26+
27+
override fun checkResourceNameValidity(resourceName: String?): Boolean = resourceName.equals("S3://", ignoreCase = true)
28+
}

jetbrains-core/src/software/aws/toolkits/jetbrains/services/s3/editor/S3TreeNode.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@ import com.intellij.ui.SimpleTextAttributes
1111
import com.intellij.ui.treeStructure.SimpleNode
1212
import kotlinx.coroutines.runBlocking
1313
import software.amazon.awssdk.services.s3.model.NoSuchBucketException
14+
import software.amazon.awssdk.services.s3.model.S3Exception
1415
import software.aws.toolkits.core.utils.error
1516
import software.aws.toolkits.core.utils.getLogger
1617
import software.aws.toolkits.jetbrains.core.utils.buildList
1718
import software.aws.toolkits.jetbrains.services.s3.NOT_VERSIONED_VERSION_ID
19+
import software.aws.toolkits.jetbrains.utils.notifyError
1820
import software.aws.toolkits.resources.message
1921
import java.time.Instant
2022

@@ -128,6 +130,15 @@ open class S3TreeDirectoryNode(bucket: S3VirtualBucket, parent: S3TreeDirectoryN
128130
} catch (e: NoSuchBucketException) {
129131
bucket.handleDeletedBucket()
130132
return emptyList()
133+
} catch (e: S3Exception) {
134+
e.notifyError("Access denied to bucket")
135+
return buildList {
136+
if (continuationMarker != null) {
137+
add(S3TreeErrorContinuationNode(bucket, this@S3TreeDirectoryNode, this@S3TreeDirectoryNode.key, continuationMarker))
138+
} else {
139+
add(S3TreeErrorNode(bucket, this@S3TreeDirectoryNode))
140+
}
141+
}
131142
} catch (e: Exception) {
132143
LOG.error(e) { "Loading objects failed!" }
133144
return buildList {

0 commit comments

Comments
 (0)