Skip to content

Commit 1437212

Browse files
authored
1.1.0 (#24)
2 parents 975f8d9 + dbbb1e6 commit 1437212

File tree

21 files changed

+143
-89
lines changed

21 files changed

+143
-89
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
44

5+
## [1.1.0]
6+
- odata-cli 0.3.1 support
7+
- UI improvements and fixes
8+
59
## [1.0.1]
610
- odata-cli exceptions handling
711

README.md

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,37 +4,25 @@
44

55
<p align="center">
66
<a href="https://plugins.jetbrains.com/plugin/24117-odata-cli-ui" target="_blank">
7-
<img src="/img/marketplace.png">
7+
<img src="/img/marketplace.png" alt="Marketplace link">
88
</a>
99
</p>
1010

1111
---
1212

1313
## Installation
1414

15-
1. Install plugin from [Marketplace](https://plugins.jetbrains.com/plugin/24117-odata-cli-ui) or download from [Releases page](https://github.com/ellizio/rider--plugin--odata-cli-ui/releases) and install manually
15+
1. Install plugin from [Marketplace](https://plugins.jetbrains.com/plugin/24117-odata-cli-ui) or download from [Releases page](https://github.com/ellizio/odata-cli-ui/releases) and install manually
1616
2. Install the latest version of the OData CLI tool with the command `dotnet tool install -g Microsoft.OData.Cli`
1717

1818
## Usage
1919

20-
1. Open solution
21-
2. Select `OData Reference...` action under project or Web Reference context menu\
22-
![](/img/action.png)
23-
3. Fill required `Service name` and `Metadata source` and other optional parameters according [documentation](https://learn.microsoft.com/en-us/odata/odatacli/getting-started#options-1)\
24-
![](/img/dialog.png)
25-
4. Click `OK` and wait until generation finishes
26-
![](/img/terminal.png)
27-
28-
## ⚠️ Known Restrictions
29-
30-
1. ✅ Waiting for release with fix\
31-
Output metadata .xml file is always named `OData ServiceCsdl.xml` which will throw a runtime exception. See more [https://github.com/OData/ODataConnectedService/issues/384](https://github.com/OData/ODataConnectedService/issues/384)\
32-
There is a workaround:\
33-
`a.` Rename `OData ServiceCsdl.xml` to `<Service name>Csdl.xml`, where `<Service name>` is value from OData CLI UI dialog\
34-
`b.` Adjust embedded resource path in `.csproj` file\
35-
`c.` Find `GeneratedEdmModel.filePath` constant in `Reference.cs` and change value from `OData ServiceCsdl.xml` to `<Service name>Csdl.xml`, where `<Service name>` is value from OData CLI UI dialog
20+
![](/img/step1.png)
21+
![](/img/step2.png)
22+
![](/img/step3.png)
23+
![](/img/step4.png)
3624

3725
## Additional References
3826

39-
- [Changelog](https://github.com/ellizio/rider--plugin--odata-cli-ui/blob/master/CHANGELOG.md)
27+
- [Changelog](https://github.com/ellizio/odata-cli-ui/blob/master/CHANGELOG.md)
4028
- [OData CLI](https://learn.microsoft.com/en-us/odata/odatacli/getting-started)

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
DotnetPluginId=ReSharperPlugin.ODataCliUi
55
DotnetSolution=ReSharperPlugin.ODataCliUi.sln
66
RiderPluginId=ru.ellizio.odatacliui
7-
PluginVersion=1.0.1
7+
PluginVersion=1.1.0
88

99
BuildConfiguration=Debug
1010

img/action.png

-20.6 KB
Binary file not shown.

img/dialog.png

-81.2 KB
Binary file not shown.

img/step1.png

132 KB
Loading

img/step2.png

133 KB
Loading

img/step3.png

158 KB
Loading

img/step4.png

114 KB
Loading

img/terminal.png

-98.3 KB
Binary file not shown.

protocol/src/main/kotlin/model/rider/ProtocolModel.kt

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,14 @@ import com.jetbrains.rider.model.nova.ide.SolutionModel
55

66
@Suppress("unused")
77
object ProtocolModel : Ext(SolutionModel.Solution) {
8-
private val CliTool = structdef {
8+
private val DotnetToolVersionDefinition = structdef {
9+
field("major", PredefinedType.int)
10+
field("minor", PredefinedType.int)
11+
field("patch", PredefinedType.int)
12+
}
13+
private val DotnetToolDefinition = structdef {
914
field("installed", PredefinedType.bool)
10-
field("version", PredefinedType.string.nullable)
15+
field("version", DotnetToolVersionDefinition.nullable)
1116
}
1217

1318
private val EmbeddedResourceDefinition = structdef {
@@ -16,7 +21,7 @@ object ProtocolModel : Ext(SolutionModel.Solution) {
1621
}
1722

1823
init {
19-
call("getODataCliTool", PredefinedType.void, CliTool)
24+
call("getODataCliTool", PredefinedType.void, DotnetToolDefinition)
2025
call("addEmbeddedResource", EmbeddedResourceDefinition, PredefinedType.void)
2126
}
2227
}

src/dotnet/ReSharperPlugin.ODataCliUi/Tracker.cs renamed to src/dotnet/ReSharperPlugin.ODataCliUi/DotnetToolsTracker.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@
77
namespace ReSharperPlugin.ODataCliUi;
88

99
[SolutionComponent]
10-
public class Tracker
10+
public class DotnetToolsTracker
1111
{
1212
private readonly JetFastSemiReenterableRWLock _lock = new();
1313
private readonly Lifetime _lifetime;
1414
private readonly SolutionDotnetToolsTracker _dotnetToolsTracker;
1515

16-
public event Action<DotNetToolCache> DotNetToolCacheChanged;
16+
public event Action<DotNetToolCache> DotnetToolsCacheChanged;
1717

18-
public Tracker(Lifetime lifetime, SolutionDotnetToolsTracker dotnetToolsTracker)
18+
public DotnetToolsTracker(Lifetime lifetime, SolutionDotnetToolsTracker dotnetToolsTracker)
1919
{
2020
_lifetime = lifetime;
2121
_dotnetToolsTracker = dotnetToolsTracker;
@@ -30,7 +30,7 @@ public void Start()
3030

3131
using var _ = _lock.UsingWriteLock();
3232
var cache = args.New;
33-
DotNetToolCacheChanged?.Invoke(cache);
33+
DotnetToolsCacheChanged?.Invoke(cache);
3434
});
3535
}
3636
}

src/dotnet/ReSharperPlugin.ODataCliUi/PluginHost.cs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,20 @@ namespace ReSharperPlugin.ODataCliUi;
1616
public sealed class PluginHost : IDisposable
1717
{
1818
private readonly ISolution _solution;
19-
private readonly Tracker _tracker;
19+
private readonly DotnetToolsTracker _dotnetToolsTracker;
2020

21-
private CliTool _odataCliTool;
21+
private DotnetToolDefinition _odataCliTool;
2222

23-
public PluginHost(ISolution solution, Tracker tracker)
23+
public PluginHost(ISolution solution, DotnetToolsTracker dotnetToolsTracker)
2424
{
2525
_solution = solution;
2626
var protocolModel = solution.GetProtocolSolution().GetProtocolModel();
2727
protocolModel.GetODataCliTool.SetSync(GetODataCliTool);
2828
protocolModel.AddEmbeddedResource.SetVoidAsync(AddEmbeddedResourceAsync);
2929

30-
_tracker = tracker;
31-
tracker.DotNetToolCacheChanged += OnDotNetToolCacheChanged;
32-
tracker.Start();
30+
_dotnetToolsTracker = dotnetToolsTracker;
31+
dotnetToolsTracker.DotnetToolsCacheChanged += OnDotnetToolsCacheChanged;
32+
dotnetToolsTracker.Start();
3333
}
3434

3535
private Task AddEmbeddedResourceAsync(Lifetime lifetime, EmbeddedResourceDefinition definition)
@@ -46,21 +46,21 @@ private Task AddEmbeddedResourceAsync(Lifetime lifetime, EmbeddedResourceDefinit
4646
return Task.CompletedTask;
4747
}
4848

49-
private CliTool GetODataCliTool(Lifetime lifetime, Unit unit) => _odataCliTool;
49+
private DotnetToolDefinition GetODataCliTool(Lifetime lifetime, Unit unit) => _odataCliTool;
5050

51-
private void OnDotNetToolCacheChanged(DotNetToolCache cache)
51+
private void OnDotnetToolsCacheChanged(DotNetToolCache cache)
5252
{
5353
var tool = cache.ToolGlobalCache.GetGlobalTool(Constants.MicrosoftODataCliPackageId)?.FirstOrDefault();
5454
_odataCliTool = tool is null
55-
? _odataCliTool = new CliTool(false, null)
56-
: _odataCliTool = new CliTool(true, $"Global, {tool.Version}");
55+
? _odataCliTool = new DotnetToolDefinition(false, null)
56+
: _odataCliTool = new DotnetToolDefinition(true, new DotnetToolVersionDefinition(tool.Version.Major, tool.Version.Minor, tool.Version.Patch));
5757
}
5858

5959
public void Dispose()
6060
{
61-
if (_tracker is not null)
61+
if (_dotnetToolsTracker is not null)
6262
{
63-
_tracker.DotNetToolCacheChanged -= OnDotNetToolCacheChanged;
63+
_dotnetToolsTracker.DotnetToolsCacheChanged -= OnDotnetToolsCacheChanged;
6464
}
6565
}
6666
}

src/rider/main/kotlin/ru/ellizio/odatacliui/dialogs/CliDialog.kt

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ import com.intellij.ui.dsl.builder.*
88
import ru.ellizio.odatacliui.Constants
99
import ru.ellizio.odatacliui.UiBundle
1010
import ru.ellizio.odatacliui.extensions.emptyText
11+
import ru.ellizio.odatacliui.extensions.humanize
1112
import ru.ellizio.odatacliui.models.CliDialogModel
13+
import ru.ellizio.odatacliui.models.validators.CliDialogValidators
1214
import javax.swing.JComponent
1315

1416
class CliDialog(private val model: CliDialogModel) : DialogWrapper(false) {
@@ -47,26 +49,29 @@ class CliDialog(private val model: CliDialogModel) : DialogWrapper(false) {
4749
tabbedPane.addTab(UiBundle.text("cli.tab.generation"), generationTab)
4850
tabbedPane.addTab(UiBundle.text("cli.tab.request"), requestTab)
4951

52+
val version = if (!model.odataCliTool.installed) UiBundle.text("cli.cli-version.label-value.not-installed")
53+
else "${UiBundle.text("cli.cli-version.label-value.global")}, ${model.odataCliTool.version?.humanize()}"
54+
5055
return panel {
5156
row {
52-
label(model.odataCliTool.version ?: UiBundle.text("cli.cli-version.label-value.not-installed"))
57+
label(version)
5358
.label(UiBundle.text("cli.cli-version.label"))
5459
.comment(UiBundle.text("cli.cli-version.comment"))
5560
}.bottomGap(BottomGap.SMALL)
5661
row(UiBundle.text("cli.service-name.row")) {
5762
textField()
5863
.align(AlignX.FILL)
5964
.bindText(model.serviceName)
60-
.validationOnInput(model.validator.serviceNameValidation())
61-
.validationOnApply(model.validator.serviceNameValidation())
65+
.validationOnInput(CliDialogValidators.serviceNameValidator())
66+
.validationOnApply(CliDialogValidators.serviceNameValidator())
6267
}
6368
row(UiBundle.text("cli.metadata-source.row")) {
6469
textFieldWithBrowseButton(fileChooserDescriptor = FileChooserDescriptorFactory.createSingleFileDescriptor("xml"))
6570
.align(AlignX.FILL)
6671
.comment(UiBundle.text("cli.metadata-source.comment"), Int.MAX_VALUE)
6772
.bindText(model.metadataUri)
68-
.validationOnInput(model.validator.metadataUriValidation())
69-
.validationOnApply(model.validator.metadataUriValidation())
73+
.validationOnInput(CliDialogValidators.metadataUriValidator())
74+
.validationOnApply(CliDialogValidators.metadataUriValidator())
7075
}.bottomGap(BottomGap.SMALL)
7176
row {
7277
cell(tabbedPane)
@@ -87,8 +92,8 @@ class CliDialog(private val model: CliDialogModel) : DialogWrapper(false) {
8792
.align(AlignX.FILL)
8893
.comment(UiBundle.text("cli.namespace-prefix.comment"))
8994
.bindText(model.namespacePrefix)
90-
.validationOnInput(model.validator.namespacePrefixValidation())
91-
.validationOnApply(model.validator.namespacePrefixValidation())
95+
.validationOnInput(CliDialogValidators.namespacePrefixValidator())
96+
.validationOnApply(CliDialogValidators.namespacePrefixValidator())
9297
}
9398
row("--excluded-operation-imports") {
9499
textField()
@@ -154,6 +159,8 @@ class CliDialog(private val model: CliDialogModel) : DialogWrapper(false) {
154159
.emptyText(UiBundle.text("cli.proxy.empty-text"))
155160
.comment(UiBundle.text("cli.proxy.comment"))
156161
.bindText(model.proxy)
162+
.validationOnInput(CliDialogValidators.proxyValidator())
163+
.validationOnApply(CliDialogValidators.proxyValidator())
157164
}
158165
}.apply {
159166
registerValidators(disposable)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package ru.ellizio.odatacliui.extensions
2+
3+
import com.jetbrains.rd.ide.model.DotnetToolVersionDefinition
4+
5+
fun DotnetToolVersionDefinition.humanize() : String = "$major.$minor.$patch"
6+
7+
fun DotnetToolVersionDefinition.greaterOrEquals(major: Int, minor: Int, patch: Int) : Boolean {
8+
if (this.major > major)
9+
return true
10+
11+
if (this.major == major && this.minor > minor)
12+
return true
13+
14+
if (this.major == major && this.minor == minor && this.patch >= patch)
15+
return true
16+
17+
return false
18+
}

src/rider/main/kotlin/ru/ellizio/odatacliui/models/CliDialogModel.kt

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,34 @@ package ru.ellizio.odatacliui.models
22

33
import com.intellij.execution.configurations.GeneralCommandLine
44
import com.intellij.openapi.project.Project
5-
import com.jetbrains.rd.ide.model.CliTool
5+
import com.jetbrains.rd.ide.model.DotnetToolDefinition
66
import com.jetbrains.rd.ide.model.protocolModel
77
import com.jetbrains.rider.model.dotNetActiveRuntimeModel
88
import ru.ellizio.odatacliui.Constants
99
import ru.ellizio.odatacliui.extensions.dotnetAddPackageCommand
10-
import ru.ellizio.odatacliui.models.validators.CliDialogModelValidator
1110
import ru.ellizio.odatacliui.terminal.BatchCommandLine
1211
import ru.ellizio.odatacliui.terminal.builders.BatchCommandLineBuilder
1312
import com.jetbrains.rider.projectView.solution
13+
import ru.ellizio.odatacliui.extensions.greaterOrEquals
1414
import ru.ellizio.odatacliui.terminal.builders.CommandLineBuilder
1515
import ru.ellizio.odatacliui.utils.DotnetToolsUtils
1616
import kotlin.io.path.Path
1717

1818
private const val CONNECTED_SERVICES = "Connected Services"
19-
private const val CSDL_NAME = "OData ServiceCsdl.xml"
19+
private const val CSDL_NAME_LEGACY = "OData ServiceCsdl.xml"
20+
private const val CSDL_NAME_SUFFIX = "Csdl.xml"
2021

2122
class CliDialogModel(project: Project, private val actionMetadata: ActionMetadata) {
22-
val validator = CliDialogModelValidator()
23+
val odataCliTool: DotnetToolDefinition
24+
private val dotnetCliPath: String?
2325

24-
val odataCliTool: CliTool
25-
val dotnetCliPath: String?
26+
private val atLeast031: Boolean
2627

2728
init {
2829
odataCliTool = project.solution.protocolModel.getODataCliTool.sync(Unit)
2930
dotnetCliPath = project.solution.dotNetActiveRuntimeModel.activeRuntime.valueOrNull?.dotNetCliExePath
31+
32+
atLeast031 = odataCliTool.version?.greaterOrEquals(0, 3, 1) ?: false
3033
}
3134

3235
val serviceName = MutableProperty("")
@@ -47,10 +50,14 @@ class CliDialogModel(project: Project, private val actionMetadata: ActionMetadat
4750

4851
private fun getOutputDirectory(): String = Path(Path(actionMetadata.projectPath).parent.toString(), CONNECTED_SERVICES, serviceName.get()).toString()
4952

50-
fun getCsdlPath(): String = Path(CONNECTED_SERVICES, serviceName.get(), CSDL_NAME).toString()
53+
fun getCsdlPath(): String {
54+
val csdl = if (atLeast031) "${serviceName.get()}$CSDL_NAME_SUFFIX" else CSDL_NAME_LEGACY
55+
return Path(CONNECTED_SERVICES, serviceName.get(), csdl).toString()
56+
}
5157

5258
fun buildODataCliCommand(): GeneralCommandLine = CommandLineBuilder(DotnetToolsUtils.getToolDefaultPath("odata-cli"), "generate")
5359
.withParameter("--metadata-uri", metadataUri.get())
60+
.withParameter("--service-name", serviceName.get(), atLeast031)
5461
.withParameter("--file-name", fileName.get())
5562
.withParameter("--custom-headers", customHeaders.get())
5663
.withParameter("--proxy", proxy.get())

src/rider/main/kotlin/ru/ellizio/odatacliui/models/validators/CliDialogModelValidator.kt

Lines changed: 0 additions & 29 deletions
This file was deleted.
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package ru.ellizio.odatacliui.models.validators
2+
3+
import com.intellij.openapi.ui.TextFieldWithBrowseButton
4+
import com.intellij.openapi.ui.ValidationInfo
5+
import com.intellij.ui.layout.ValidationInfoBuilder
6+
import javax.swing.JTextField
7+
8+
object CliDialogValidators {
9+
private val serviceNameRegex = Regex("^[0-9a-zA-Z_\\-. ]+\$")
10+
private val proxyRegex = Regex("^(\\w+\\\\\\w+(:\\w+)?@)?\\w+:\\d+\$")
11+
12+
fun serviceNameValidator(): ValidationInfoBuilder.(JTextField) -> ValidationInfo? = {
13+
if (it.text.isBlank())
14+
error("Service name must not be empty")
15+
else if (it.text.startsWith(' '))
16+
error("Service name must not start with a space")
17+
else if (it.text.endsWith(' '))
18+
error("Service name must not end with a space")
19+
else if (!serviceNameRegex.matches(it.text))
20+
error("Service name must be in a valid format")
21+
else
22+
null
23+
}
24+
25+
fun metadataUriValidator(): ValidationInfoBuilder.(TextFieldWithBrowseButton) -> ValidationInfo? = {
26+
if (it.text.isBlank())
27+
error("Metadata source must not be empty")
28+
else
29+
null
30+
}
31+
32+
fun namespacePrefixValidator(): ValidationInfoBuilder.(JTextField) -> ValidationInfo? = {
33+
if (it.text.contains(' '))
34+
error("Namespace prefix must not contain spaces")
35+
else
36+
null
37+
}
38+
39+
fun proxyValidator(): ValidationInfoBuilder.(JTextField) -> ValidationInfo? = {
40+
if (!proxyRegex.matches(it.text))
41+
error("Proxy must be in a valid format")
42+
else
43+
null
44+
}
45+
}

0 commit comments

Comments
 (0)