-
Notifications
You must be signed in to change notification settings - Fork 275
AWS Explorer #4
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
AWS Explorer #4
Conversation
aws-intellij-toolkit.iml
Outdated
| @@ -0,0 +1,12 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need the .iml file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it is not necessary for importing the project, we can remove this. I added .iml files in .gitignore.
| import com.intellij.util.ui.UIUtil; | ||
| import org.jetbrains.annotations.NonNls; | ||
|
|
||
| import javax.annotation.Nonnull; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we use jet-brains annotations for this instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
| */ | ||
| public class AwsRegionPanel { | ||
| private JPanel regionPanel; | ||
| private com.intellij.openapi.ui.ComboBox<AwsRegion> regionCombo; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason this is the FQ class name?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Imported the class and removed the FQ class name
| } | ||
| }); | ||
|
|
||
| for (AwsRegion region : AwsRegionManager.INSTANCE.getRegions()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we use forEach instead ? 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
| } | ||
|
|
||
| private void selectRegion(String regionId) { | ||
| for (AwsRegion region : AwsRegionManager.INSTANCE.getRegions()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
stream().filter(r -> r.getId().equals(regionId)).findFirst().ifPresent(r -> regionCombo.setSelectedItem(r));
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
| class AwsExplorerLambdaRootNode(project: Project?, region: String): | ||
| AwsExplorerServiceRootNode<FunctionConfiguration>(project, "AWS Lambda", region, LAMBDA_SERVICE_ICON) { | ||
|
|
||
| private var client: AWSLambda = AWSLambdaClientBuilder.standard() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this be a val ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The original concern is when region gets updated so we need to create a new client. Our current implementation is to redraw the Tree when region gets updated to avoid potential bugs for updating the Tree. Therefore, I can change this to val.
| class AwsExplorerRootNode(project: Project?, region: String): | ||
| AwsExplorerNode<String>(project, "ROOT", region, AWS_ICON) { | ||
|
|
||
| override fun getChildren(): MutableCollection<out AbstractTreeNode<String>> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this have to be a MutableCollection ? Can we make it immutable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
| /** | ||
| * Created by zhaoxiz on 7/27/17. | ||
| */ | ||
| enum class AwsExplorerService(val serviceId: String) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it make sense to have this more like an extension point like @abrooksv did with the Credential Management? Then every time we add a new service (that has it's own 'resources' to display in the explorer) it can register as a provider here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was my first version of the Explorer but dropped that after talking to @abrooksv. The reason was that:
- The Extension Point has a low performance.
- We are not planning to provide different IntelliJ plugins based on services like Eclipse do. We want to integrate all the services in one plugin. We provide different plugins based on different languages.
| }, | ||
| ; | ||
|
|
||
| abstract fun buildServiceRoodNode(project: Project?, region: String): AbstractTreeNode<String> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rood -> root
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Woops, corrected.
| } | ||
|
|
||
| // This method may throw RuntimeException, must handle it | ||
| abstract fun loadResources(): MutableList<Resource> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this throw an exception? Is there a better way of communicating this? What if it returned a nullable MutableList? Alternatively you can do this with an Either if the error is actually important
https://discuss.kotlinlang.org/t/disjoint-unions-in-kotlin/413
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The loadResources() method mostly would throw an AmazonServiceException which is a RuntimeException.
The return type is MutableList<Resource>, so no null value is returned.
I think whether to use Either or not depends where do we want to handle this exception. I personally prefer to current way as the loadResources method should only be called in the super class when loading specific resources like S3 buckets or Lambda functions. The super class would handle the exceptions to report in the UI.
abrooksv
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall I would look into if we can convert more of the mutable stuff to immutable.
Also remove all the author blocks
| /** | ||
| * Created by zhaoxiz on 7/20/17. | ||
| */ | ||
| public class ExplorerToolbar { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should rename this since it is not just the toolbar, but the tree too. If its the full tool window then call it ExplorerToolWindow?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. ExplorerToolWindow better fits the class name.
| public ExplorerToolbar(@NonNls Project project, @NonNls Wrapper wrapper) { | ||
| this.project = project; | ||
| this.regionProvider = AwsDefaultRegionProvider.getInstance(project); | ||
| this.wrapper = wrapper; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How does the wrapper get into the mainPanel?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The mainPanel is only for the toolbar. The wrapper panel is for the tree. The wrapper panel is created in the class AwsExplorerFactory, the wrapper is passed in as a parameter so that when region changes, we can update the tree panel in the wrapper.
val simpleToolWindowPanel = SimpleToolWindowPanel(true, false)
val wrapperPane = Wrapper()
simpleToolWindowPanel.setToolbar(ExplorerToolWindow(project, wrapperPane).mainPanel)
simpleToolWindowPanel.setContent(wrapperPane)| @@ -0,0 +1,11 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | |||
| <form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.amazonaws.intellij.ui.explorer.ExplorerToolbar"> | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not seeing much reason to bind this to a form since it is an empty panel. Do you see much reason to keep this as a bound .form instead of just writing it in Kotlin?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed this form.
| private ComboBox<AwsRegion> regionCombo; | ||
|
|
||
| public AwsRegionPanel(String defaultRegion) { | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
delete blank line
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
| } | ||
| }); | ||
|
|
||
| AwsRegionManager.INSTANCE.getRegions().forEach((region)-> {regionCombo.addItem(region);}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Look into setting the ComboBox to use a CollectionComboBoxModel
This will remove the need for the stream, and also using the model is typesafe
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
| class AwsExplorerLambdaRootNode(project: Project?, region: String): | ||
| AwsExplorerServiceRootNode<FunctionConfiguration>(project, "AWS Lambda", region, LAMBDA_SERVICE_ICON) { | ||
|
|
||
| private val client: AWSLambda = AWSLambdaClientBuilder.standard() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add TODO to move to a client manager so we don't lose it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed. Will send a separate PR for ClientManager
| .withRegion(region) | ||
| .build() | ||
|
|
||
| override fun loadResources(): MutableList<FunctionConfiguration> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should not be mutable list
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
|
|
||
| override fun createToolWindowContent(project: Project, toolWindow: ToolWindow) { | ||
| val simpleToolWindowPanel = SimpleToolWindowPanel(true, false) | ||
| val wrapperPane = Wrapper() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wrapper out here seems weird inversion of control. Can we move it into the tool panel?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
| * Created by zhaoxiz on 7/27/17. | ||
| */ | ||
|
|
||
| abstract class AwsExplorerNode<T>(project: Project?, value: T, val region: String, val awsIcon: Icon?): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is there an interface T is?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there an interface T? What do you mean?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Opps thought I deleted this comment because I saw there wasn't
Question was is there better type bounds for T, basically
| val cache: ClearableLazyValue<MutableCollection<AwsExplorerNode<*>>> | ||
|
|
||
| init { | ||
| cache = object : ClearableLazyValue<MutableCollection<AwsExplorerNode<*>>>() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does this need to be mutable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replaced with Immutable.
| AwsRegionManager.INSTANCE.getRegions().forEach((region)-> {regionCombo.addItem(region);}); | ||
| regionCombo.setModel(regionModel); | ||
|
|
||
| AwsRegionManager.INSTANCE.getRegions().forEach(regionModel::add); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can just say regionModel.add(AwsRegionManager.INSTANCE.getRegions())
or in the constructor of the collection pass it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
|
|
||
| private class AwsResources(val region: String) { | ||
| val s3Client: AmazonS3 = AmazonS3Client() //AmazonS3ClientBuilder.standard().withRegion(region).build() | ||
| val s3Client: AmazonS3 = AmazonS3Client() //AmazonS3ClientBuilder.standard().withRegion(region).parse() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the commented out part for?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Forgot to address this. This is because a rename to the method build() -> parse(), but somehow IntelliJ replaces all the occurrences of build to parse. This code would be replaced anyway, so leave it as is for now
| private ComboBox<AwsRegion> regionCombo; | ||
| private final CollectionComboBoxModel<AwsRegion> regionModel = new CollectionComboBoxModel<>(); | ||
|
|
||
| public AwsRegionPanel(String defaultRegion) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this just take the AwsRegion type as the parameter? Saves us the filter and find later
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
|
|
||
| public AwsRegionPanel(String defaultRegion) { | ||
|
|
||
| regionCombo.setRenderer(new DefaultListCellRenderer() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lets look into ListCellRendererWrapper. It is type safe and the comment says it is less ugly 😸
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. Thanks for the info :)
| object AwsRegionManager { | ||
|
|
||
| private val regions = mutableListOf<AwsRegion>() | ||
| var regions: List<AwsRegion> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should be val
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
| import javax.swing.tree.DefaultMutableTreeNode | ||
| import javax.swing.tree.DefaultTreeModel | ||
|
|
||
| class ExplorerToolWindow(val project: Project, val treePanelWrapper: Wrapper) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make this extend the simple tool window and call setContent in init{}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. Removed the form file also
…ome other small refactors.
abrooksv
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just change the XML node name in the persistent component
…o-gennerated headers comments.
First batch for AWS Explorer in IntelliJ.
Empty Node


Error Node