Fix datetime picker addon position
Fix datetime picker data format mismatch form user selection Fix Tags/Properties page ajax cache issue Remove resvered keywords from devicedetail/tags/properties Add default job name with localizable string Adjust input hint text in schedulejob/editTag/editProperties page Adjust section label text in schedulejob/editTag/editProperties page Disable value input/delete checkbox when property name is empty(same as tag page) remove 'lenght' check from ko if
This commit is contained in:
Родитель
eaa1df678f
Коммит
2a06b20291
|
@ -9,6 +9,7 @@
|
|||
*.user
|
||||
*.sln.docstates
|
||||
*.opendb
|
||||
*.patch
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
|
|
|
@ -2627,7 +2627,7 @@ namespace GlobalResources {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Invoke Method.
|
||||
/// Looks up a localized string similar to Method.
|
||||
/// </summary>
|
||||
public static string InvokeMethodLabel {
|
||||
get {
|
||||
|
@ -3229,6 +3229,15 @@ namespace GlobalResources {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to NewJob yyyy-MM-dd.
|
||||
/// </summary>
|
||||
public static string NewScheduleJobNameFormat {
|
||||
get {
|
||||
return ResourceManager.GetString("NewScheduleJobNameFormat", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Next.
|
||||
/// </summary>
|
||||
|
@ -3680,7 +3689,7 @@ namespace GlobalResources {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Start with "desired." e.g. desired.sampleprop.
|
||||
/// Looks up a localized string similar to desired.sampleprop.
|
||||
/// </summary>
|
||||
public static string PropertyTextPlaceHolder {
|
||||
get {
|
||||
|
@ -4211,7 +4220,7 @@ namespace GlobalResources {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Change Desired Properties.
|
||||
/// Looks up a localized string similar to Desired Properties.
|
||||
/// </summary>
|
||||
public static string ScheduleChangeDesiredProperties {
|
||||
get {
|
||||
|
@ -4220,7 +4229,7 @@ namespace GlobalResources {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Change Tags.
|
||||
/// Looks up a localized string similar to Tags.
|
||||
/// </summary>
|
||||
public static string ScheduleChangeTags {
|
||||
get {
|
||||
|
@ -4238,7 +4247,7 @@ namespace GlobalResources {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Invoke Method.
|
||||
/// Looks up a localized string similar to Method.
|
||||
/// </summary>
|
||||
public static string ScheduleDeviceMethodJobType {
|
||||
get {
|
||||
|
@ -4265,7 +4274,7 @@ namespace GlobalResources {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Edit Value.
|
||||
/// Looks up a localized string similar to Value.
|
||||
/// </summary>
|
||||
public static string ScheduleEditValue {
|
||||
get {
|
||||
|
@ -4337,7 +4346,7 @@ namespace GlobalResources {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Set Job Time.
|
||||
/// Looks up a localized string similar to Job Time.
|
||||
/// </summary>
|
||||
public static string ScheduleSetJobTime {
|
||||
get {
|
||||
|
@ -4805,7 +4814,7 @@ namespace GlobalResources {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Start with "desired." e.g. tag.sampletag.
|
||||
/// Looks up a localized string similar to tags.sampletag.
|
||||
/// </summary>
|
||||
public static string TagTextPlaceHolder {
|
||||
get {
|
||||
|
@ -5075,7 +5084,7 @@ namespace GlobalResources {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to e.g. "123" or Tom.
|
||||
/// Looks up a localized string similar to 123.
|
||||
/// </summary>
|
||||
public static string ValueTextPlaceHolder {
|
||||
get {
|
||||
|
|
|
@ -1703,7 +1703,7 @@
|
|||
<comment>Tooltip.</comment>
|
||||
</data>
|
||||
<data name="InvokeMethodLabel" xml:space="preserve">
|
||||
<value>Invoke Method</value>
|
||||
<value>Method</value>
|
||||
<comment>Hyperlink label.</comment>
|
||||
</data>
|
||||
<data name="EditColumns" xml:space="preserve">
|
||||
|
@ -1767,11 +1767,11 @@
|
|||
<comment>Hyperlink label</comment>
|
||||
</data>
|
||||
<data name="ScheduleChangeDesiredProperties" xml:space="preserve">
|
||||
<value>Change Desired Properties</value>
|
||||
<value>Desired Properties</value>
|
||||
<comment>Input label</comment>
|
||||
</data>
|
||||
<data name="ScheduleChangeTags" xml:space="preserve">
|
||||
<value>Change Tags</value>
|
||||
<value>Tags</value>
|
||||
<comment>Input label</comment>
|
||||
</data>
|
||||
<data name="ScheduleDesiredPropertyName" xml:space="preserve">
|
||||
|
@ -1783,7 +1783,7 @@
|
|||
<comment>Label</comment>
|
||||
</data>
|
||||
<data name="ScheduleEditValue" xml:space="preserve">
|
||||
<value>Edit Value</value>
|
||||
<value>Value</value>
|
||||
<comment>Input label</comment>
|
||||
</data>
|
||||
<data name="ScheduleJobName" xml:space="preserve">
|
||||
|
@ -1791,7 +1791,7 @@
|
|||
<comment>Input label</comment>
|
||||
</data>
|
||||
<data name="ScheduleSetJobTime" xml:space="preserve">
|
||||
<value>Set Job Time</value>
|
||||
<value>Job Time</value>
|
||||
<comment>Input label</comment>
|
||||
</data>
|
||||
<data name="SomeDeviceInapplicable" xml:space="preserve">
|
||||
|
@ -2069,7 +2069,7 @@
|
|||
<comment>Table cell.</comment>
|
||||
</data>
|
||||
<data name="ScheduleDeviceMethodJobType" xml:space="preserve">
|
||||
<value>Invoke Method</value>
|
||||
<value>Method</value>
|
||||
<comment>Table cell.</comment>
|
||||
</data>
|
||||
<data name="ScheduleUpdateTwinJobType" xml:space="preserve">
|
||||
|
@ -2381,15 +2381,15 @@
|
|||
<comment>Label message</comment>
|
||||
</data>
|
||||
<data name="PropertyTextPlaceHolder" xml:space="preserve">
|
||||
<value>Start with "desired." e.g. desired.sampleprop</value>
|
||||
<value>desired.sampleprop</value>
|
||||
<comment>Text input Placeholder </comment>
|
||||
</data>
|
||||
<data name="TagTextPlaceHolder" xml:space="preserve">
|
||||
<value>Start with "tags." e.g. tags.sampletag</value>
|
||||
<value> tags.sampletag</value>
|
||||
<comment>Text input Placeholder</comment>
|
||||
</data>
|
||||
<data name="ValueTextPlaceHolder" xml:space="preserve">
|
||||
<value>e.g. "123" or Tom</value>
|
||||
<value>123</value>
|
||||
<comment>Text input Placeholder</comment>
|
||||
</data>
|
||||
<data name="DeleteIconTooltip" xml:space="preserve">
|
||||
|
@ -2408,4 +2408,8 @@
|
|||
<value>External Job {0}</value>
|
||||
<comment>Table cell.</comment>
|
||||
</data>
|
||||
<data name="NewScheduleJobNameFormat" xml:space="preserve">
|
||||
<value>NewJob yyyy-MM-dd</value>
|
||||
<comment>Name format</comment>
|
||||
</data>
|
||||
</root>
|
|
@ -174,6 +174,6 @@
|
|||
position:relative;
|
||||
height:18px;
|
||||
width:18px;
|
||||
right:25px;
|
||||
right:0px;
|
||||
top:4px;
|
||||
}
|
|
@ -884,7 +884,7 @@ nav .selected {
|
|||
position: relative;
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
right: 25px;
|
||||
right: 0px;
|
||||
top: 4px;
|
||||
}
|
||||
.remove_form {
|
||||
|
|
|
@ -13,6 +13,8 @@ using StringPair = System.Collections.Generic.KeyValuePair<string, string>;
|
|||
|
||||
namespace Microsoft.Azure.Devices.Applications.RemoteMonitoring.DeviceAdmin.Web.Controllers
|
||||
{
|
||||
using Helpers;
|
||||
using System.Threading;
|
||||
using System.Web;
|
||||
|
||||
/// <summary>
|
||||
|
@ -104,6 +106,17 @@ namespace Microsoft.Azure.Devices.Applications.RemoteMonitoring.DeviceAdmin.Web.
|
|||
string key = _configProvider.GetConfigurationSettingValue("MapApiQueryKey");
|
||||
model.MapApiQueryKey = key.Equals("0") ? string.Empty : key;
|
||||
|
||||
// Set default culture
|
||||
HttpCookie cookie = this.Request.Cookies[Constants.CultureCookieName];
|
||||
|
||||
if (cookie == null)
|
||||
{
|
||||
cookie = new HttpCookie(Constants.CultureCookieName);
|
||||
cookie.Value = CultureHelper.GetClosestCulture(Thread.CurrentThread.CurrentCulture.Name).Name;
|
||||
cookie.Expires = DateTime.Now.AddYears(1);
|
||||
Response.Cookies.Add(cookie);
|
||||
}
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
|
|
|
@ -157,6 +157,7 @@ namespace Microsoft.Azure.Devices.Applications.RemoteMonitoring.DeviceAdmin.Web.
|
|||
{
|
||||
FilterId = filterId,
|
||||
FilterName = deviceListFilter.Name,
|
||||
JobName = DateTime.Now.ToString(Strings.NewScheduleJobNameFormat)
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -202,6 +203,7 @@ namespace Microsoft.Azure.Devices.Applications.RemoteMonitoring.DeviceAdmin.Web.
|
|||
{
|
||||
FilterId = filterId,
|
||||
FilterName = deviceListFilter.Name,
|
||||
JobName = DateTime.Now.ToString(Strings.NewScheduleJobNameFormat)
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -102,6 +102,7 @@
|
|||
type: 'PUT',
|
||||
data: ko.mapping.toJSON(updatedata),
|
||||
contentType: "application/json",
|
||||
cache: false,
|
||||
success: function (result) {
|
||||
location.href = resources.redirectUrl;
|
||||
},
|
||||
|
@ -119,6 +120,7 @@
|
|||
$.ajax({
|
||||
url: '/api/v1/devices/' + deviceId + '/twin/desired',
|
||||
type: 'GET',
|
||||
cache: false,
|
||||
success: function (result) {
|
||||
self.reported = ko.mapping.fromJS(result.data.reported);
|
||||
|
||||
|
|
|
@ -80,6 +80,7 @@
|
|||
$.ajax({
|
||||
url: '/api/v1/devices/' + deviceId + '/twin/tag',
|
||||
type: 'PUT',
|
||||
cache: false,
|
||||
data: ko.mapping.toJSON(updatedata),
|
||||
contentType: "application/json",
|
||||
success: function (result) {
|
||||
|
@ -99,6 +100,7 @@
|
|||
$.ajax({
|
||||
url: '/api/v1/devices/' + deviceId + '/twin/tag',
|
||||
type: 'GET',
|
||||
cache: false,
|
||||
success: function (result) {
|
||||
|
||||
//add 'isDeleted' field for model binding, default false
|
||||
|
|
|
@ -85,7 +85,14 @@ function getCulture() {
|
|||
c = c.substring(1);
|
||||
}
|
||||
if (c.indexOf(name) == 0) {
|
||||
return c.substring(name.length, c.length);
|
||||
var localename = c.substring(name.length, c.length);
|
||||
//Match to closet culture
|
||||
switch (localename) {
|
||||
case "zh-Hans": return "zh-cn";
|
||||
case "zh-Hant": return "zh-tw";
|
||||
case "pt-PT": return "pt-br";
|
||||
default: return localename;
|
||||
}
|
||||
}
|
||||
}
|
||||
return window.navigator.language;
|
||||
|
|
|
@ -75,6 +75,7 @@
|
|||
self.saveMethodFilterQuery = $.ajax({
|
||||
url: '/api/v1/devices/count/' + self.filterId + "/save?isMatched="+ isMatched,
|
||||
type: 'POST',
|
||||
cache: false,
|
||||
data: ko.mapping.toJSON({ 'methodName': self.currentMethodData.methodName, 'parameters': self.currentMethodData.params }),
|
||||
contentType: "application/json",
|
||||
success: function (result) {
|
||||
|
@ -97,6 +98,7 @@
|
|||
self.getApplicableDevice= $.ajax({
|
||||
url: '/api/v1/devices/count/' + self.filterId,
|
||||
type: 'POST',
|
||||
cache: false,
|
||||
data: ko.mapping.toJSON({ 'methodName': methodName, 'parameters': param }),
|
||||
contentType: "application/json",
|
||||
success: function (result) {
|
||||
|
@ -175,6 +177,7 @@
|
|||
$.ajax({
|
||||
url: '/api/v1/devices/count/' + self.filterId,
|
||||
type: 'GET',
|
||||
cache: false,
|
||||
success: function (result) {
|
||||
self.totalFilteredCount(result.data);
|
||||
},
|
||||
|
|
|
@ -147,6 +147,7 @@
|
|||
$.ajax({
|
||||
url: '/api/v1/devices/count/' + self.filterId,
|
||||
type: 'GET',
|
||||
cache: false,
|
||||
success: function (result) {
|
||||
self.totalFilteredCount(result.data);
|
||||
},
|
||||
|
|
|
@ -47,12 +47,12 @@
|
|||
</td>
|
||||
<td>
|
||||
<input type="text" class="edit_form__texthalf"
|
||||
data-bind='value: value.value, enable:!isDeleted()' />
|
||||
data-bind='value: value.value, enable:!isDeleted() && key()' />
|
||||
</td>
|
||||
<td>
|
||||
<input type="checkbox"
|
||||
value="true"
|
||||
data-bind='checked: isDeleted' />
|
||||
data-bind='checked: isDeleted ,enable: key().' />
|
||||
</td>
|
||||
<td data-bind="if:$root.MatchReportedProp(key) != null"><span class="edit_form__labelsmall" data-bind="text:$root.MatchReportedProp(key).key"></span></td>
|
||||
<td data-bind="if:$root.MatchReportedProp(key) != null"><span class="edit_form__labelsmall" data-bind="text:$root.fromNowValue($root.MatchReportedProp(key).value.lastUpdated,getCulture())"></span></td>
|
||||
|
|
|
@ -47,12 +47,12 @@
|
|||
</td>
|
||||
<td>
|
||||
<input type="text" class="edit_form__texthalf"
|
||||
data-bind='value: value.value, enable:!isDeleted()' />
|
||||
data-bind='value: value.value, enable:!isDeleted() && key()' />
|
||||
</td>
|
||||
<td>
|
||||
<input type="checkbox"
|
||||
value="true"
|
||||
data-bind='checked: isDeleted' />
|
||||
data-bind='checked: isDeleted ,enable: key()' />
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
@model Microsoft.Azure.Devices.Applications.RemoteMonitoring.DeviceAdmin.Web.Models.DeviceDetailModel
|
||||
@{
|
||||
DateTime? resolvedDate;
|
||||
var tags = Model.DevicePropertyValueModels.Where(m => m.Name.StartsWith("tags."));
|
||||
var desiredProperties = Model.DevicePropertyValueModels.Where(m => m.Name.StartsWith("properties.desired."));
|
||||
var reportedProperties = Model.DevicePropertyValueModels.Where(m => m.Name.StartsWith("properties.reported."));
|
||||
var tags = Model.DevicePropertyValueModels.Where(m => m.Name.StartsWith("tags.") && !m.Name.IsReservedTwinName());
|
||||
var desiredProperties = Model.DevicePropertyValueModels.Where(m => m.Name.StartsWith("properties.desired.") && !m.Name.IsReservedTwinName());
|
||||
var reportedProperties = Model.DevicePropertyValueModels.Where(m => m.Name.StartsWith("properties.reported.") && !m.Name.IsReservedTwinName());
|
||||
var deviceProperties = Model.DevicePropertyValueModels.Except(tags).Except(desiredProperties).Except(reportedProperties);
|
||||
var utcNow = DateTime.UtcNow;
|
||||
}
|
||||
|
|
|
@ -71,15 +71,15 @@
|
|||
@*data-msg-required="@Strings.RequiredValidationString"
|
||||
data-rule-required="true"*@
|
||||
<input type="text" class="edit_form__texthalfvalue" placeholder="@Strings.ValueTextPlaceHolder"
|
||||
data-bind='textInput: PropertyValue, event: { keyup: $root.createEmptyPropertyIfNeeded }, attr: { name: "DesiredProperties[" + $index() + "].PropertyValue", id: "DesiredProperties" + $index() + ".PropertyValue" }' />
|
||||
data-bind='textInput: PropertyValue, enable:PropertyName() && !isDeleted(), event: { keyup: $root.createEmptyPropertyIfNeeded }, attr: { name: "DesiredProperties[" + $index() + "].PropertyValue", id: "DesiredProperties" + $index() + ".PropertyValue" }' />
|
||||
</td>
|
||||
<td>
|
||||
<input type="checkbox"
|
||||
value="true"
|
||||
data-bind='check: isDeleted, attr: { name: "DesiredProperties[" + $index() + "].isDeleted", id: "DesiredProperties" + $index() + ".isDeleted" }' />
|
||||
data-bind='checked: isDeleted, enable:PropertyName() ,attr: { name: "DesiredProperties[" + $index() + "].isDeleted", id: "DesiredProperties" + $index() + ".isDeleted" }' />
|
||||
<input type="hidden" value="false" name="checkbox" data-bind='attr:{ name: "DesiredProperties[" + $index() + "].isDeleted" }' />
|
||||
</td>
|
||||
<td><a data-bind="ifnot:$root.onepropleft , click:$root.removeProperty">@Strings.Clear</a></td>
|
||||
<td><a data-bind="ifnot:$root.onepropleft , click:$root.removeProperty"><small class="text_small">@Strings.Clear</small></a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@ -103,15 +103,15 @@
|
|||
</td>
|
||||
<td>
|
||||
<input type="text" class="edit_form__texthalfvalue" placeholder="@Strings.ValueTextPlaceHolder"
|
||||
data-bind='textInput: TagValue, event: { keyup: $root.createEmptyTagIfNeeded }, attr: { name: "Tags[" + $index() + "].TagValue", id: "Tags" + $index() + ".TagValue" }' />
|
||||
data-bind='textInput: TagValue, enable:TagName() && !isDeleted(), event: { keyup: $root.createEmptyTagIfNeeded }, attr: { name: "Tags[" + $index() + "].TagValue", id: "Tags" + $index() + ".TagValue" }' />
|
||||
</td>
|
||||
<td>
|
||||
<input type="checkbox"
|
||||
value="true"
|
||||
data-bind='check: isDeleted, attr: { name: "Tags[" + $index() + "].isDeleted", id: "Tags" + $index() + ".isDeleted" }' />
|
||||
data-bind='checked: isDeleted, enable:TagName(), attr: { name: "Tags[" + $index() + "].isDeleted", id: "Tags" + $index() + ".isDeleted" }' />
|
||||
<input type="hidden" value="false" name="checkbox" data-bind='attr:{ name: "Tags[" + $index() + "].isDeleted" }' />
|
||||
</td>
|
||||
<td><a class="edit_form__link" data-bind="ifnot:$root.onetagleft , click:$root.removeTag">@Strings.Clear</a></td>
|
||||
<td><a class="edit_form__link" data-bind="ifnot:$root.onetagleft , click:$root.removeTag"><small class="text_small">@Strings.Clear</small></a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
Strings.UpdateTwin, "ScheduleTwinUpdate", "Job",
|
||||
new
|
||||
{
|
||||
filterId = Model.FilterId,
|
||||
filterId = Model.FilterId,
|
||||
},
|
||||
new
|
||||
{
|
||||
|
@ -32,8 +32,8 @@
|
|||
@Html.ActionLink(
|
||||
Strings.InvokeMethod, "ScheduleDeviceMethod", "Job",
|
||||
new
|
||||
{
|
||||
filterId = Model.FilterId,
|
||||
{
|
||||
filterId = Model.FilterId,
|
||||
},
|
||||
new
|
||||
{
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web.Http;
|
||||
|
@ -10,6 +11,7 @@ using Microsoft.Azure.Devices.Applications.RemoteMonitoring.DeviceAdmin.Infrastr
|
|||
using Microsoft.Azure.Devices.Applications.RemoteMonitoring.DeviceAdmin.Web.Security;
|
||||
using Microsoft.Azure.Devices.Shared;
|
||||
|
||||
|
||||
namespace Microsoft.Azure.Devices.Applications.RemoteMonitoring.DeviceAdmin.Web.WebApiControllers
|
||||
{
|
||||
[RoutePrefix("api/v1/devices")]
|
||||
|
@ -30,8 +32,8 @@ namespace Microsoft.Azure.Devices.Applications.RemoteMonitoring.DeviceAdmin.Web.
|
|||
public async Task<HttpResponseMessage> GetDeviceTwinDesired(string deviceId)
|
||||
{
|
||||
var twin = await this._deviceManager.GetTwinAsync(deviceId);
|
||||
IEnumerable<KeyValuePair<string, TwinCollectionExtension.TwinValue>> flattenReportedTwin = twin.Properties.Reported.AsEnumerableFlatten("reported.");
|
||||
IEnumerable<KeyValuePair<string, TwinCollectionExtension.TwinValue>> flattenTwin = twin.Properties.Desired.AsEnumerableFlatten("desired.");
|
||||
IEnumerable<KeyValuePair<string, TwinCollectionExtension.TwinValue>> flattenReportedTwin = twin.Properties.Reported.AsEnumerableFlatten("reported.").Where(t => !t.Key.IsReservedTwinName());
|
||||
IEnumerable<KeyValuePair<string, TwinCollectionExtension.TwinValue>> flattenTwin = twin.Properties.Desired.AsEnumerableFlatten("desired.").Where(t => !t.Key.IsReservedTwinName());
|
||||
return await GetServiceResponseAsync<dynamic>(async () =>
|
||||
{
|
||||
return await Task.FromResult(new { desired = flattenTwin, reported = flattenReportedTwin });
|
||||
|
@ -44,7 +46,7 @@ namespace Microsoft.Azure.Devices.Applications.RemoteMonitoring.DeviceAdmin.Web.
|
|||
public async Task<HttpResponseMessage> GetDeviceTwinTag(string deviceId)
|
||||
{
|
||||
var twin = await this._deviceManager.GetTwinAsync(deviceId);
|
||||
IEnumerable<KeyValuePair<string, TwinCollectionExtension.TwinValue>> flattenTwin = twin.Tags.AsEnumerableFlatten("tags.");
|
||||
IEnumerable<KeyValuePair<string, TwinCollectionExtension.TwinValue>> flattenTwin = twin.Tags.AsEnumerableFlatten("tags.").Where(t=>!t.Key.IsReservedTwinName());
|
||||
return await GetServiceResponseAsync<IEnumerable<KeyValuePair<string, TwinCollectionExtension.TwinValue>>>(async () =>
|
||||
{
|
||||
return await Task.FromResult(flattenTwin);
|
||||
|
|
Загрузка…
Ссылка в новой задаче