Commit bfd278e3 by Mac Stephens

Added fnc grid and filtering

parent 601d01e1
...@@ -32,21 +32,6 @@ object FOrderList: TFOrderList ...@@ -32,21 +32,6 @@ object FOrderList: TFOrderList
HeightPercent = 100.000000000000000000 HeightPercent = 100.000000000000000000
WidthPercent = 100.000000000000000000 WidthPercent = 100.000000000000000000
end end
object edtSearch: TWebEdit
Left = 8
Top = 384
Width = 121
Height = 22
HelpType = htKeyword
ChildOrder = 8
ElementClassName = 'form-control'
ElementID = 'edtsearch'
ElementFont = efCSS
HeightStyle = ssAuto
HeightPercent = 100.000000000000000000
HideSelection = False
WidthPercent = 100.000000000000000000
end
object pnlMessage: TWebPanel object pnlMessage: TWebPanel
Left = 24 Left = 24
Top = 57 Top = 57
...@@ -59,7 +44,7 @@ object FOrderList: TFOrderList ...@@ -59,7 +44,7 @@ object FOrderList: TFOrderList
ElementFont = efCSS ElementFont = efCSS
ElementPosition = epRelative ElementPosition = epRelative
Role = 'alert' Role = 'alert'
TabOrder = 1 TabOrder = 0
object lblMessage: TWebLabel object lblMessage: TWebLabel
Left = 28 Left = 28
Top = 9 Top = 9
...@@ -90,39 +75,6 @@ object FOrderList: TFOrderList ...@@ -90,39 +75,6 @@ object FOrderList: TFOrderList
WidthPercent = 100.000000000000000000 WidthPercent = 100.000000000000000000
end end
end end
object WebDBTableControl: TWebDBTableControl
Left = 172
Top = 287
Width = 530
Height = 265
ElementClassName = 'table-responsive'
ElementId = 'customer_list'
BorderColor = clSilver
ChildOrder = 5
ColHeader = False
ElementTableClassName = 'table table-striped table-bordered table-hover dataTable'
Options.ResizeColumns = True
Columns = <
item
DataField = 'ID'
Title = 'ID'
Width = 24
end
item
DataField = 'NAME'
Title = 'NAME'
Width = 100
end
item
DataField = 'SHORT_NAME'
Title = 'SHORT_NAME'
end
item
DataField = 'ADDRESS'
Title = 'ADDRESS'
end>
DataSource = wdsCustomers
end
object cbCorrugatedPlate: TWebCheckBox object cbCorrugatedPlate: TWebCheckBox
Left = 172 Left = 172
Top = 210 Top = 210
...@@ -176,6 +128,210 @@ object FOrderList: TFOrderList ...@@ -176,6 +128,210 @@ object FOrderList: TFOrderList
WidthPercent = 100.000000000000000000 WidthPercent = 100.000000000000000000
OnClick = btnConfirmClick OnClick = btnConfirmClick
end end
object btnFilter: TWebButton
Left = 564
Top = 195
Width = 96
Height = 25
Caption = 'Filter'
ChildOrder = 9
HeightPercent = 100.000000000000000000
WidthPercent = 100.000000000000000000
OnClick = btnFilterClick
end
object TMSFNCGrid1: TTMSFNCGrid
Left = 228
Top = 308
Width = 588
Height = 353
AdaptToStyle = True
ParentDoubleBuffered = False
DoubleBuffered = True
TabOrder = 7
DefaultRowHeight = 40.000000000000000000
FixedColumns = 0
ColumnCount = 0
RowCount = 1
Options.Bands.Enabled = True
Options.Editing.CalcFormat = '%g'
Options.Filtering.MultiColumn = True
Options.Grouping.CalcFormat = '%g'
Options.Grouping.GroupCountFormat = '(%d)'
Options.IO.XMLEncoding = 'ISO-8859-1'
Options.Mouse.ColumnSizing = True
Options.Mouse.ClickMargin = 0
Options.Mouse.ColumnSizeMargin = 6
Options.Mouse.RowSizing = True
Options.Mouse.RowSizeMargin = 6
Options.Mouse.FixedColumnSizing = True
Options.Mouse.FixedRowSizing = True
Columns = <
item
BorderWidth = 1
FixedFont.Charset = DEFAULT_CHARSET
FixedFont.Color = clWindowText
FixedFont.Height = -11
FixedFont.Name = 'Tahoma'
FixedFont.Style = []
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
ID = ''
Width = 68.000000000000000000
end
item
BorderWidth = 1
FixedFont.Charset = DEFAULT_CHARSET
FixedFont.Color = clWindowText
FixedFont.Height = -11
FixedFont.Name = 'Tahoma'
FixedFont.Style = []
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
ID = ''
Width = 68.000000000000000000
end
item
BorderWidth = 1
FixedFont.Charset = DEFAULT_CHARSET
FixedFont.Color = clWindowText
FixedFont.Height = -11
FixedFont.Name = 'Tahoma'
FixedFont.Style = []
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
ID = ''
Width = 68.000000000000000000
end
item
BorderWidth = 1
FixedFont.Charset = DEFAULT_CHARSET
FixedFont.Color = clWindowText
FixedFont.Height = -11
FixedFont.Name = 'Tahoma'
FixedFont.Style = []
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
ID = ''
Width = 68.000000000000000000
end
item
BorderWidth = 1
FixedFont.Charset = DEFAULT_CHARSET
FixedFont.Color = clWindowText
FixedFont.Height = -11
FixedFont.Name = 'Tahoma'
FixedFont.Style = []
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
ID = ''
Width = 68.000000000000000000
end>
DefaultFont.Charset = DEFAULT_CHARSET
DefaultFont.Color = clBlack
DefaultFont.Height = -11
DefaultFont.Name = 'Segoe UI'
DefaultFont.Style = []
Stroke.Color = 15987699
TopRow = 1
Appearance.FixedLayout.Fill.Kind = gfkGradient
Appearance.FixedLayout.Fill.Color = 16382457
Appearance.FixedLayout.Fill.ColorTo = 16382457
Appearance.FixedLayout.Stroke.Color = 15987699
Appearance.FixedLayout.Font.Charset = DEFAULT_CHARSET
Appearance.FixedLayout.Font.Color = clBlack
Appearance.FixedLayout.Font.Height = -11
Appearance.FixedLayout.Font.Name = 'Tahoma'
Appearance.FixedLayout.Font.Style = [fsBold]
Appearance.NormalLayout.Fill.Color = -1
Appearance.NormalLayout.Stroke.Color = 15987699
Appearance.NormalLayout.Font.Charset = DEFAULT_CHARSET
Appearance.NormalLayout.Font.Color = clBlack
Appearance.NormalLayout.Font.Height = -11
Appearance.NormalLayout.Font.Name = 'Tahoma'
Appearance.NormalLayout.Font.Style = []
Appearance.GroupLayout.Fill.Kind = gfkGradient
Appearance.GroupLayout.Fill.Color = 15385233
Appearance.GroupLayout.Fill.ColorTo = 15385233
Appearance.GroupLayout.Stroke.Color = 15987699
Appearance.GroupLayout.Font.Charset = DEFAULT_CHARSET
Appearance.GroupLayout.Font.Color = clBlack
Appearance.GroupLayout.Font.Height = -11
Appearance.GroupLayout.Font.Name = 'Tahoma'
Appearance.GroupLayout.Font.Style = []
Appearance.SummaryLayout.Fill.Kind = gfkGradient
Appearance.SummaryLayout.Fill.Color = 15385233
Appearance.SummaryLayout.Fill.ColorTo = 15385233
Appearance.SummaryLayout.Stroke.Color = 15987699
Appearance.SummaryLayout.Font.Charset = DEFAULT_CHARSET
Appearance.SummaryLayout.Font.Color = clBlack
Appearance.SummaryLayout.Font.Height = -11
Appearance.SummaryLayout.Font.Name = 'Tahoma'
Appearance.SummaryLayout.Font.Style = []
Appearance.SelectedLayout.Fill.Kind = gfkGradient
Appearance.SelectedLayout.Fill.Color = 15385233
Appearance.SelectedLayout.Fill.ColorTo = 15385233
Appearance.SelectedLayout.Stroke.Color = 15987699
Appearance.SelectedLayout.Font.Charset = DEFAULT_CHARSET
Appearance.SelectedLayout.Font.Color = clBlack
Appearance.SelectedLayout.Font.Height = -11
Appearance.SelectedLayout.Font.Name = 'Tahoma'
Appearance.SelectedLayout.Font.Style = []
Appearance.FocusedLayout.Fill.Kind = gfkGradient
Appearance.FocusedLayout.Fill.Color = 15385233
Appearance.FocusedLayout.Fill.ColorTo = 15385233
Appearance.FocusedLayout.Stroke.Color = 15987699
Appearance.FocusedLayout.Font.Charset = DEFAULT_CHARSET
Appearance.FocusedLayout.Font.Color = clBlack
Appearance.FocusedLayout.Font.Height = -11
Appearance.FocusedLayout.Font.Name = 'Tahoma'
Appearance.FocusedLayout.Font.Style = []
Appearance.FixedSelectedLayout.Fill.Kind = gfkGradient
Appearance.FixedSelectedLayout.Fill.Color = 15385233
Appearance.FixedSelectedLayout.Fill.ColorTo = 15385233
Appearance.FixedSelectedLayout.Stroke.Color = 15987699
Appearance.FixedSelectedLayout.Font.Charset = DEFAULT_CHARSET
Appearance.FixedSelectedLayout.Font.Color = clBlack
Appearance.FixedSelectedLayout.Font.Height = -11
Appearance.FixedSelectedLayout.Font.Name = 'Tahoma'
Appearance.FixedSelectedLayout.Font.Style = []
Appearance.BandLayout.Fill.Color = clLightyellow
Appearance.BandLayout.Stroke.Color = 15987699
Appearance.BandLayout.Font.Charset = DEFAULT_CHARSET
Appearance.BandLayout.Font.Color = clWindowText
Appearance.BandLayout.Font.Height = -11
Appearance.BandLayout.Font.Name = 'Tahoma'
Appearance.BandLayout.Font.Style = []
Appearance.ProgressLayout.Color = 15385233
Appearance.ProgressLayout.Format = '%.0f%%'
LeftCol = 0
ScrollMode = scmItemScrolling
DesignTimeSampleData = True
end
object edtSearch: TWebEdit
Left = 437
Top = 198
Width = 121
Height = 22
ChildOrder = 8
HeightPercent = 100.000000000000000000
WidthPercent = 100.000000000000000000
OnChange = edtSearchChange
end
object XDataWebClient1: TXDataWebClient object XDataWebClient1: TXDataWebClient
Connection = DMConnection.ApiConnection Connection = DMConnection.ApiConnection
Left = 88 Left = 88
......
...@@ -3,48 +3,48 @@ unit View.OrderList; ...@@ -3,48 +3,48 @@ unit View.OrderList;
interface interface
uses uses
System.SysUtils, System.Generics.Collections, System.Classes, JS, Web, WEBLib.Graphics, WEBLib.Controls, System.SysUtils, System.Classes, JS, Web, WEBLib.Graphics, WEBLib.Controls,
WEBLib.Forms, WEBLib.Dialogs, WEBLib.Menus, WEBLib.ExtCtrls, WEBLib.StdCtrls, WEBLib.Forms, WEBLib.Dialogs, WEBLib.StdCtrls, XData.Web.Client, WEBLib.ExtCtrls,
WEBLib.JSON, Auth.Service, XData.Web.Client, WebLib.Storage, Data.DB, XData.Web.Dataset, VCL.TMSFNCTypes, VCL.TMSFNCGrid, VCL.TMSFNCGridData,
ConnectionModule, App.Types, Vcl.StdCtrls, Vcl.Controls, WEBLib.DBCtrls, VCL.TMSFNCUtils, VCL.TMSFNCGraphics, VCL.TMSFNCGraphicsTypes,
Data.DB, XData.Web.JsonDataset, XData.Web.Dataset, WEBLib.DB, WEBLib.Grids, VCL.TMSFNCGridCell, VCL.TMSFNCGridOptions, VCL.TMSFNCCustomComponent,
Vcl.Grids; VCL.TMSFNCCustomGrid, VCL.TMSFNCGridDatabaseAdapter, VCL.TMSFNCCustomControl,
VCL.TMSFNCCustomScrollControl, WEBLib.DB, XData.Web.JsonDataset, Vcl.StdCtrls,
Vcl.Controls, ConnectionModule;
type type
TFOrderList = class(TWebForm) TFOrderList = class(TWebForm)
lblEntries: TWebLabel; lblEntries: TWebLabel;
lblEntries2: TWebLabel; lblEntries2: TWebLabel;
edtSearch: TWebEdit; edtSearch: TWebEdit;
edtCompanyName: TWebEdit;
edtID: TWebEdit;
pnlMessage: TWebPanel; pnlMessage: TWebPanel;
lblMessage: TWebLabel; lblMessage: TWebLabel;
btnCloseNotification: TWebButton; btnCloseNotification: TWebButton;
btnFilter: TWebButton;
XDataWebClient1: TXDataWebClient; XDataWebClient1: TXDataWebClient;
xdwdsCustomers: TXDataWebDataSet;
wdsCustomers: TWebDataSource; wdsCustomers: TWebDataSource;
xdwdsCustomers: TXDataWebDataSet;
xdwdsCustomersID: TIntegerField; xdwdsCustomersID: TIntegerField;
xdwdsCustomersNAME: TStringField; xdwdsCustomersNAME: TStringField;
xdwdsCustomersSHORT_NAME: TStringField; xdwdsCustomersSHORT_NAME: TStringField;
xdwdsCustomersADDRESS: TStringField; xdwdsCustomersADDRESS: TStringField;
WebDBTableControl: TWebDBTableControl; TMSFNCGrid1: TTMSFNCGrid;
btnConfirm: TWebButton;
cbCorrugatedPlate: TWebCheckBox; cbCorrugatedPlate: TWebCheckBox;
cbWebPlate: TWebCheckBox; cbWebPlate: TWebCheckBox;
edtCompanyName: TWebEdit;
edtID: TWebEdit;
btnConfirm: TWebButton;
procedure WebFormShow(Sender: TObject); procedure WebFormShow(Sender: TObject);
procedure WebDBTableControlGetCellChildren(Sender: TObject; ACol, procedure btnFilterClick(Sender: TObject);
ARow: Integer; AField: TField; AValue: string;
AElement: TJSHTMLElementRecord);
procedure cbCorrugatedPlateClick(Sender: TObject); procedure cbCorrugatedPlateClick(Sender: TObject);
procedure cbWebPlateClick(Sender: TObject); procedure cbWebPlateClick(Sender: TObject);
procedure btnConfirmClick(Sender: TObject); procedure btnConfirmClick(Sender: TObject);
procedure edtSearchChange(Sender: TObject);
private private
//FJSONProc: TJSONProc;
procedure AddRowToTable();
procedure ClearTable();
[async] procedure getCustomers(); [async] procedure getCustomers();
procedure PopulateGridManually;
procedure ApplyFilter;
public public
class function CreateForm(AElementID: string): TWebForm;
end; end;
var var
...@@ -54,129 +54,127 @@ implementation ...@@ -54,129 +54,127 @@ implementation
{$R *.dfm} {$R *.dfm}
class function TFOrderList.CreateForm(AElementID: string): TWebForm; procedure TFOrderList.WebFormShow(Sender: TObject);
begin begin
Application.CreateForm(TFOrderList, AElementID, Result, getCustomers(); // Fetch and populate the grid with customer data
procedure(AForm: TObject)
begin
with TFOrderList(AForm) do
begin
end;
end
);
end; end;
procedure TFOrderList.WebDBTableControlGetCellChildren(Sender: TObject; ACol, [async]
ARow: Integer; AField: TField; AValue: string; procedure TFOrderList.getCustomers();
AElement: TJSHTMLElementRecord); var
xdcResponse: TXDataClientResponse;
customerList: TJSObject;
begin begin
//WebDBTableControl.WidthStyle := TSizeStyle.ssAuto; // Fetch data from XData service
console.log(AValue); xdcResponse := await(XDataWebClient1.RawInvokeAsync('ILookupService.GetCustomers', []));
WebDBTableControl.ColWidths[ACol] := AValue.Length * 12; customerList := TJSObject(xdcResponse.Result);
// Load data into TXDataWebDataset
xdwdsCustomers.Close;
xdwdsCustomers.SetJsonData(customerList['data']);
xdwdsCustomers.Open;
// Manually populate the grid
PopulateGridManually;
end; end;
procedure TFOrderList.WebFormShow(Sender: TObject); procedure TFOrderList.PopulateGridManually;
var
RowIndex: Integer;
begin begin
getCustomers(); TMSFNCGrid1.BeginUpdate;
try
TMSFNCGrid1.Clear; // Clear any existing data
// Set up column headers
TMSFNCGrid1.ColumnCount := 4;
TMSFNCGrid1.RowCount := 1;
TMSFNCGrid1.Cells[0, 0] := 'ID';
TMSFNCGrid1.Cells[1, 0] := 'Name';
TMSFNCGrid1.Cells[2, 0] := 'Short Name';
TMSFNCGrid1.Cells[3, 0] := 'Address';
// Populate the grid with data from the dataset
xdwdsCustomers.First;
RowIndex := 1;
while not xdwdsCustomers.EOF do
begin
TMSFNCGrid1.RowCount := RowIndex + 1;
TMSFNCGrid1.Cells[0, RowIndex] := xdwdsCustomers.FieldByName('ID').AsString;
TMSFNCGrid1.Cells[1, RowIndex] := xdwdsCustomers.FieldByName('NAME').AsString;
TMSFNCGrid1.Cells[2, RowIndex] := xdwdsCustomers.FieldByName('SHORT_NAME').AsString;
TMSFNCGrid1.Cells[3, RowIndex] := xdwdsCustomers.FieldByName('ADDRESS').AsString;
Inc(RowIndex);
xdwdsCustomers.Next;
end;
// Auto-size columns
TMSFNCGrid1.AutoSizeColumns;
finally
TMSFNCGrid1.EndUpdate;
end;
end; end;
procedure TFOrderList.btnConfirmClick(Sender: TObject); procedure TFOrderList.ApplyFilter;
var
fd: TTMSFNCGridFilterData;
i: Integer;
SearchText: string;
begin begin
Close; SearchText := Trim(edtSearch.Text);
// Remove any existing filters
TMSFNCGrid1.RemoveFilter;
TMSFNCGrid1.Filter.Clear;
// Add a filter for each column
for i := 0 to TMSFNCGrid1.ColumnCount - 1 do
begin
fd := TMSFNCGrid1.Filter.Add;
fd.Column := i;
fd.Condition := '*' + SearchText + '*'; // Match text anywhere in the cell
fd.CaseSensitive := False; // Make the filter case-insensitive
// Use foOR for "match any column" logic
if i > 0 then
fd.Operation := foOR
else
fd.Operation := foNONE; // First filter has no logical operation
end;
// Apply the filters to the grid
TMSFNCGrid1.ApplyFilter;
end; end;
procedure TFOrderList.cbCorrugatedPlateClick(Sender: TObject);
procedure TFOrderList.btnFilterClick(Sender: TObject);
begin begin
cbWebPlate.Checked := false; ApplyFilter;
end; end;
procedure TFOrderList.cbWebPlateClick(Sender: TObject); procedure TFOrderList.cbCorrugatedPlateClick(Sender: TObject);
begin begin
cbCorrugatedPlate.Checked := false; cbWebPlate.Checked := False;
end; end;
procedure TFOrderList.ClearTable(); procedure TFOrderList.cbWebPlateClick(Sender: TObject);
// clears the table
var
tbody: TJSHTMLElement;
begin begin
tbody := TJSHTMLElement(document.getElementById('tblCustomerGrid').getElementsByTagName('tbody')[0]); cbCorrugatedPlate.Checked := False;
tbody.innerHTML := '';
end; end;
procedure TFOrderList.getCustomers(); procedure TFOrderList.btnConfirmClick(Sender: TObject);
var
xdcResponse: TXDataClientResponse;
customerList: TJSObject;
data: TJSArray;
i, count: integer;
temp: TJSONObject;
customer: TJSObject;
begin begin
xdcResponse := await(XDataWebClient1.RawInvokeAsync('ILookupService.GetCustomers', Close;
[]));
customerList := TJSObject(xdcResponse.Result);
data := TJSArray(customerList['data']);
count := integer(customerList['count']);
xdwdsCustomers.Close;
xdwdsCustomers.SetJsonData(customerList['data']);
xdwdsCustomers.Open;
end; end;
procedure TFOrderList.AddRowToTable(); procedure TFOrderList.edtSearchChange(Sender: TObject);
var
NewRow, Cell, P, Button, Audio: TJSHTMLElement;
ClickHandler: TJSFunction;
//strColorList: string;
id: integer;
begin begin
NewRow := TJSHTMLElement(document.createElement('tr')); ApplyFilter;
//NewRow.Attrs['orderType'] := XDataWebDataSet1orderType.Value;
NewRow.addEventListener('click', procedure
begin
//orderEntry(NewRow.Attrs['id'], 'EDIT');
end);
// Company ID Cell
NewRow.Attrs['id'] := xdwdsCustomersID.AsString;
Cell := TJSHTMLElement(document.createElement('td'));
Cell.setAttribute('data-label', 'Order ID');
if xdwdsCustomersID.AsString = '' then
Cell.innerText := 'None'
else
Cell.innerText := xdwdsCustomersID.AsString;
NewRow.appendChild(Cell);
// Company Name Cell
Cell := TJSHTMLElement(document.createElement('td'));
Cell.setAttribute('data-label', 'Company Name');
if xdwdsCustomersNAME.Value = '' then
Cell.innerText := 'None'
else
Cell.innerText := xdwdsCustomersNAME.Value;
NewRow.appendChild(Cell);
// Short Name Cell
Cell := TJSHTMLElement(document.createElement('td'));
Cell.setAttribute('data-label', 'Job Name');
if xdwdsCustomersSHORT_NAME.Value = '' then
Cell.innerText := 'None'
else
Cell.innerText := xdwdsCustomersSHORT_NAME.Value;
NewRow.appendChild(Cell);
// Address Cell
Cell := TJSHTMLElement(document.createElement('td'));
Cell.setAttribute('data-label', 'Order Date');
if xdwdsCustomersADDRESS.Value = '' then
Cell.innerText := 'None'
else
Cell.innerText := xdwdsCustomersADDRESS.Value;
NewRow.appendChild(Cell);
// Appends new rows to the table body
TJSHTMLElement(document.getElementById('tblCustomerGrid').getElementsByTagName('tbody')[0]).appendChild(NewRow);
end; end;
end. end.
......
...@@ -22,8 +22,6 @@ object AuthDatabase: TAuthDatabase ...@@ -22,8 +22,6 @@ object AuthDatabase: TAuthDatabase
SpecificOptions.Strings = ( SpecificOptions.Strings = (
'PostgreSQL.Schema=envoy') 'PostgreSQL.Schema=envoy')
Username = 'root' Username = 'root'
Server = '192.168.159.132'
Connected = True
LoginPrompt = False LoginPrompt = False
Left = 67 Left = 67
Top = 131 Top = 131
......
...@@ -8,8 +8,6 @@ object FDatabaseModule: TFDatabaseModule ...@@ -8,8 +8,6 @@ object FDatabaseModule: TFDatabaseModule
SpecificOptions.Strings = ( SpecificOptions.Strings = (
'PostgreSQL.Schema=envoy') 'PostgreSQL.Schema=envoy')
Username = 'root' Username = 'root'
Server = '192.168.159.132'
Connected = True
LoginPrompt = False LoginPrompt = False
Left = 75 Left = 75
Top = 139 Top = 139
......
[Options] [Options]
LogFileNum=230 LogFileNum=234
UpdateTimerLength=0 UpdateTimerLength=0
[Database] [Database]
Server=192.168.159.132 --Server=192.168.159.132
--Server=192.168.102.129 --Server=192.168.102.129
Server=192.168.102.130
[Twilio] [Twilio]
AccountSID=AC37aeef9c36a2cccbaecbadafc172b2ff AccountSID=AC37aeef9c36a2cccbaecbadafc172b2ff
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment