Skip to content

Commit 9e80a2d

Browse files
committed
feat: add delete functionality for table REST API
1 parent c8875ce commit 9e80a2d

6 files changed

Lines changed: 147 additions & 31 deletions

File tree

src/WebExpress.WebApp/Assets/js/webexpress.webapp.table.js

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,6 @@ webexpress.webapp.TableCtrl = class extends webexpress.webui.TableCtrl {
8989
const endIndex = Math.min(startIndex + pageSize - 1, total); // calculate the index of the last item on the current page
9090

9191
this._columns = response.columns;
92-
this._rows = response.rows;
9392
this._titleDiv.text(response.title);
9493
this._statusDiv.text(`${startIndex} - ${endIndex} / ${total}`);
9594

@@ -102,9 +101,20 @@ webexpress.webapp.TableCtrl = class extends webexpress.webui.TableCtrl {
102101
this._paginationCtrl.page = page;
103102

104103
this._table.removeClass("placeholder-glow");
105-
106-
this._hasOptions = Array.isArray(this._rows) && this._rows.some(row => row.options?.length > 0);
107-
104+
105+
// Bind actions to existing commands
106+
this._rows = response.rows.map(row => {
107+
if (Array.isArray(row.options)) {
108+
this._hasOptions = true;
109+
row.options.forEach(option => {
110+
if (option.command === "delete") {
111+
option.action = () => this._deleteRow.call(this, row.id);
112+
}
113+
});
114+
}
115+
return row;
116+
});
117+
108118
if (this._options?.length > 0) {
109119
this._hasOptions = true;
110120
}
@@ -117,6 +127,26 @@ webexpress.webapp.TableCtrl = class extends webexpress.webui.TableCtrl {
117127
console.error("The request could not be completed successfully:", error);
118128
});
119129
}
130+
131+
/**
132+
* Function to delete a row from the table and send a DELETE request to the REST API.
133+
* @param {number} rowId - The ID of the row to be deleted.
134+
*/
135+
_deleteRow(rowId) {
136+
const confirmModal = new webexpress.webui.ModalConfirmDelete();
137+
138+
confirmModal.confirmation(() => {
139+
fetch(`${this._restUri}?id=${rowId}`, { method: "DELETE" })
140+
.then(response => {
141+
if (!response.ok) throw new Error("Failed to delete row");
142+
143+
this._receiveData();
144+
})
145+
.catch(error => console.error(`Failed to delete row with ID ${rowId}.`, error));
146+
});
147+
148+
confirmModal.show();
149+
}
120150
}
121151

122152
// Register the class in the controller

src/WebExpress.WebApp/WebRestApi/RestApiCrud.cs

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,15 @@ namespace WebExpress.WebApp.WebRestApi
1515
/// <summary>
1616
/// Abstract class providing CRUD operations for REST API.
1717
/// </summary>
18-
/// <typeparam name="T">Type of the index item.</typeparam>
19-
public abstract class RestApiCrud<T> : IRestApi
20-
where T : IIndexItem
18+
/// <typeparam name="TIndexItem">Type of the index item.</typeparam>
19+
public abstract class RestApiCrud<TIndexItem> : IRestApi
20+
where TIndexItem : IIndexItem
2121
{
2222
/// <summary>
2323
/// Returns the lock object.
2424
/// </summary>
2525
protected object Guard { get; } = new object();
2626

27-
/// <summary>
28-
/// Processing of the resource that was called via the get request.
29-
/// </summary>
30-
/// <param name="wql">The filtering and sorting options.</param>
31-
/// <param name="request">The request.</param>
32-
/// <returns>An enumeration of which json serializer can be serialized.</returns>
33-
public abstract IEnumerable<T> GetData(IWqlStatement<T> wql, Request request);
34-
3527
/// <summary>
3628
/// Processing of the resource that was called via the get request.
3729
/// </summary>
@@ -48,8 +40,8 @@ public virtual object GetData(Request request)
4840
lock (Guard)
4941
{
5042
var wqlStatement = !string.IsNullOrWhiteSpace(search) || !string.IsNullOrWhiteSpace(wql)
51-
? WebEx.ComponentHub.GetComponentManager<WebIndex.IndexManager>()?.Retrieve<T>(wql ?? $"{GetDefaultSearchAttribute()}='{search}*'")
52-
: WebEx.ComponentHub.GetComponentManager<WebIndex.IndexManager>()?.Retrieve<T>("");
43+
? WebEx.ComponentHub.GetComponentManager<WebIndex.IndexManager>()?.Retrieve<TIndexItem>(wql ?? $"{GetDefaultSearchAttribute()}='{search}*'")
44+
: WebEx.ComponentHub.GetComponentManager<WebIndex.IndexManager>()?.Retrieve<TIndexItem>("");
5345
var data = GetData(wqlStatement, request);
5446

5547
var count = data.Count();
@@ -64,11 +56,22 @@ public virtual object GetData(Request request)
6456
}
6557
}
6658

59+
/// <summary>
60+
/// Processing of the resource that was called via the get request.
61+
/// </summary>
62+
/// <param name="wql">The filtering and sorting options.</param>
63+
/// <param name="request">The request.</param>
64+
/// <returns>An enumeration of which json serializer can be serialized.</returns>
65+
public virtual IEnumerable<TIndexItem> GetData(IWqlStatement<TIndexItem> wql, Request request)
66+
{
67+
throw new NotImplementedException();
68+
}
69+
6770
/// <summary>
6871
/// Creates data.
6972
/// </summary>
7073
/// <param name="request">The request.</param>
71-
public void CreateData(Request request)
74+
public virtual void CreateData(Request request)
7275
{
7376
throw new NotImplementedException();
7477
}
@@ -77,16 +80,26 @@ public void CreateData(Request request)
7780
/// Updates data.
7881
/// </summary>
7982
/// <param name="request">The request.</param>
80-
public void UpdateData(Request request)
83+
public virtual void UpdateData(Request request)
84+
{
85+
}
86+
87+
/// <summary>
88+
/// Deletes data.
89+
/// </summary>
90+
/// <param name="request">The request.</param>
91+
public virtual void DeleteData(Request request)
8192
{
93+
var id = request.GetParameter("id")?.Value;
94+
DeleteData(id, request);
8295
}
8396

8497
/// <summary>
8598
/// Deletes data.
8699
/// </summary>
87100
/// <param name="id">The id of the data to delete.</param>
88101
/// <param name="request">The request.</param>
89-
public void DeleteData(Request request)
102+
public virtual void DeleteData(string id, Request request)
90103
{
91104
throw new NotImplementedException();
92105
}
@@ -97,7 +110,7 @@ public void DeleteData(Request request)
97110
/// <returns>The name of the default attribute.</returns>
98111
protected virtual string GetDefaultSearchAttribute()
99112
{
100-
return typeof(T).GetProperties()
113+
return typeof(TIndexItem).GetProperties()
101114
.Where(x => x.GetCustomAttribute<IndexDefaultSearchAttribute>() != null)
102115
.Where(x => x.GetCustomAttribute<IndexIgnoreAttribute>() == null)
103116
.Select(x => x.Name)

src/WebExpress.WebApp/WebRestApi/RestApiCrudTable.cs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ namespace WebExpress.WebApp.WebRestApi
1414
/// <summary>
1515
/// Abstract class providing CRUD operations for REST API.
1616
/// </summary>
17-
/// <typeparam name="T">Type of the index item.</typeparam>
18-
public abstract class RestApiCrudTable<T> : RestApiCrud<T>
19-
where T : IIndexItem
17+
/// <typeparam name="TIndexItem">Type of the index item.</typeparam>
18+
public abstract class RestApiCrudTable<TIndexItem> : RestApiCrud<TIndexItem>
19+
where TIndexItem : IIndexItem
2020
{
2121
private readonly Dictionary<PropertyInfo, RestApiCrudTableColumn> _cachedColumns;
2222

@@ -36,7 +36,7 @@ public RestApiCrudTable()
3636
.Select(x => x.ConstructorArguments.FirstOrDefault().Value?.ToString())
3737
.FirstOrDefault();
3838

39-
_cachedColumns = typeof(T)
39+
_cachedColumns = typeof(TIndexItem)
4040
.GetProperties()
4141
.Where(prop => Attribute.IsDefined(prop, typeof(RestTableColumnNameAttribute)))
4242
.ToDictionary(
@@ -59,7 +59,7 @@ public RestApiCrudTable()
5959
/// </summary>
6060
/// <param name="request">The request object containing the criteria for retrieving options. Cannot be null.</param>
6161
/// <param name="row">The row object for which options are being retrieved. Cannot be null.</param>
62-
public virtual IEnumerable<RestApiCrudTableRowOption> GetOptions(Request request, T row)
62+
public virtual IEnumerable<RestApiCrudTableRowOption> GetOptions(Request request, TIndexItem row)
6363
{
6464
return [];
6565
}
@@ -78,8 +78,8 @@ public override object GetData(Request request)
7878
lock (Guard)
7979
{
8080
var wqlStatement = !string.IsNullOrWhiteSpace(wql)
81-
? WebEx.ComponentHub.GetComponentManager<WebIndex.IndexManager>()?.Retrieve<T>(wql)
82-
: WebEx.ComponentHub.GetComponentManager<WebIndex.IndexManager>()?.Retrieve<T>("");
81+
? WebEx.ComponentHub.GetComponentManager<WebIndex.IndexManager>()?.Retrieve<TIndexItem>(wql)
82+
: WebEx.ComponentHub.GetComponentManager<WebIndex.IndexManager>()?.Retrieve<TIndexItem>("");
8383
var columns = _cachedColumns
8484
.Where(x => x.Value.Visible)
8585
.Select(x => x.Value);
@@ -92,6 +92,7 @@ public override object GetData(Request request)
9292
columns = columns,
9393
rows = data.Skip(page * pageSize).Take(pageSize).Select(row => new RestApiCrudTableRow
9494
{
95+
Id = row.Id.ToString(),
9596
Cells = _cachedColumns
9697
.Where(x => x.Value.Visible)
9798
.Select(x => new RestApiCrudTableCell

src/WebExpress.WebApp/WebRestApi/RestApiCrudTableRow.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ public class RestApiCrudTableRow
1212
/// <summary>
1313
/// Returns or sets the id.
1414
/// </summary>
15+
[JsonPropertyName("id")]
16+
public object Id { get; set; }
17+
18+
/// <summary>
19+
/// Returns or sets the cells.
20+
/// </summary>
1521
[JsonPropertyName("cells")]
1622
public IEnumerable<RestApiCrudTableCell> Cells { get; set; } = [];
1723

src/WebExpress.WebApp/WebRestApi/RestApiCrudTableRowOption.cs

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Text.Json.Serialization;
2+
using WebExpress.WebCore.WebMessage;
23

34
namespace WebExpress.WebApp.WebRestApi
45
{
@@ -13,17 +14,29 @@ public class RestApiCrudTableRowOption
1314
[JsonPropertyName("id")]
1415
public string Id { get; set; }
1516

17+
/// <summary>
18+
/// Returns the command.
19+
/// </summary>
20+
[JsonPropertyName("command")]
21+
public virtual string Command => "custom";
22+
1623
/// <summary>
1724
/// Returns or sets the label.
1825
/// </summary>
1926
[JsonPropertyName("content")]
20-
public string Label { get; set; }
27+
public virtual string Label { get; set; }
2128

2229
/// <summary>
2330
/// Returns or sets the icon.
2431
/// </summary>
2532
[JsonPropertyName("icon")]
26-
public string Icon { get; set; }
33+
public virtual string Icon { get; set; }
34+
35+
/// <summary>
36+
/// Returns or sets the text color.
37+
/// </summary>
38+
[JsonPropertyName("color")]
39+
public virtual string Color { get; set; }
2740

2841
/// <summary>
2942
/// Returns or sets the width of the table column in percentage, null for auto.
@@ -37,11 +50,19 @@ public class RestApiCrudTableRowOption
3750
[JsonPropertyName("render")]
3851
public string Render { get; set; }
3952

53+
/// <summary>
54+
/// Returns the request object associated with the current operation.
55+
/// </summary>
56+
[JsonIgnore]
57+
protected Request Request { get; }
58+
4059
/// <summary>
4160
/// Initializes a new instance of the class.
4261
/// </summary>
43-
public RestApiCrudTableRowOption()
62+
/// <param name="request">The request object associated with the current operation.</param>
63+
public RestApiCrudTableRowOption(Request request)
4464
{
65+
Request = request;
4566
}
4667
}
4768
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
using System.Text.Json.Serialization;
2+
using WebExpress.WebCore.Internationalization;
3+
using WebExpress.WebCore.WebMessage;
4+
5+
namespace WebExpress.WebApp.WebRestApi
6+
{
7+
/// <summary>
8+
/// Represents a configuration option for a row in a REST API-based CRUD table.
9+
/// </summary>
10+
public class RestApiCrudTableRowOptionDelete : RestApiCrudTableRowOption
11+
{
12+
/// <summary>
13+
/// Returns or sets the command.
14+
/// </summary>
15+
[JsonPropertyName("command")]
16+
public override string Command => "delete";
17+
18+
/// <summary>
19+
/// Returns the label.
20+
/// </summary>
21+
[JsonPropertyName("content")]
22+
public override string Label => I18N.Translate(Request, "webexpress.webapp:delete.label");
23+
24+
/// <summary>
25+
/// Returns the icon.
26+
/// </summary>
27+
[JsonPropertyName("icon")]
28+
public override string Icon => "fa fa-trash";
29+
30+
/// <summary>
31+
/// Returns or sets the text color.
32+
/// </summary>
33+
[JsonPropertyName("color")]
34+
public override string Color => "text-danger";
35+
36+
/// <summary>
37+
/// Initializes a new instance of the class.
38+
/// </summary>
39+
/// <param name="request">The request object associated with the current operation.</param>
40+
public RestApiCrudTableRowOptionDelete(Request request)
41+
: base(request)
42+
{
43+
}
44+
}
45+
}

0 commit comments

Comments
 (0)