abapgit-agent 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/abapgit-agent CHANGED
@@ -1726,6 +1726,243 @@ Examples:
1726
1726
  break;
1727
1727
  }
1728
1728
 
1729
+ case 'preview': {
1730
+ const objectsArgIndex = args.indexOf('--objects');
1731
+ if (objectsArgIndex === -1 || objectsArgIndex + 1 >= args.length) {
1732
+ console.error('Error: --objects parameter required');
1733
+ console.error('Usage: abapgit-agent preview --objects <table1>,<view1>,... [--type <type>] [--limit <n>] [--where <condition>] [--columns <cols>] [--vertical] [--compact] [--json]');
1734
+ console.error('Example: abapgit-agent preview --objects SFLIGHT');
1735
+ console.error('Example: abapgit-agent preview --objects ZC_MY_CDS_VIEW --type DDLS');
1736
+ console.error('Example: abapgit-agent preview --objects SFLIGHT --where "CARRID = \'AA\'"');
1737
+ process.exit(1);
1738
+ }
1739
+
1740
+ const objects = args[objectsArgIndex + 1].split(',').map(o => o.trim().toUpperCase());
1741
+ const typeArg = args.indexOf('--type');
1742
+ const type = typeArg !== -1 ? args[typeArg + 1].toUpperCase() : null;
1743
+ const limitArg = args.indexOf('--limit');
1744
+ const limit = limitArg !== -1 ? parseInt(args[limitArg + 1], 10) : 10;
1745
+ const whereArg = args.indexOf('--where');
1746
+ const where = whereArg !== -1 ? args[whereArg + 1] : null;
1747
+ const columnsArg = args.indexOf('--columns');
1748
+ const columns = columnsArg !== -1 ? args[columnsArg + 1].split(',').map(c => c.trim().toUpperCase()) : null;
1749
+ const verticalOutput = args.includes('--vertical');
1750
+ const compactOutput = args.includes('--compact');
1751
+ const jsonOutput = args.includes('--json');
1752
+
1753
+ console.log(`\n Previewing ${objects.length} object(s)`);
1754
+
1755
+ const config = loadConfig();
1756
+ const csrfToken = await fetchCsrfToken(config);
1757
+
1758
+ const data = {
1759
+ objects: objects,
1760
+ limit: Math.min(Math.max(1, limit), 100)
1761
+ };
1762
+
1763
+ if (type) {
1764
+ data.type = type;
1765
+ }
1766
+
1767
+ if (where) {
1768
+ data.where = where;
1769
+ }
1770
+
1771
+ if (columns) {
1772
+ data.columns = columns;
1773
+ }
1774
+
1775
+ const result = await request('POST', '/sap/bc/z_abapgit_agent/preview', data, { csrfToken });
1776
+
1777
+ // Handle uppercase keys from ABAP
1778
+ const success = result.SUCCESS || result.success;
1779
+ const previewObjects = result.OBJECTS || result.objects || [];
1780
+ const message = result.MESSAGE || result.message || '';
1781
+ const error = result.ERROR || result.error;
1782
+
1783
+ if (!success || error) {
1784
+ console.error(`\n Error: ${error || 'Failed to preview objects'}`);
1785
+ break;
1786
+ }
1787
+
1788
+ if (jsonOutput) {
1789
+ console.log(JSON.stringify(result, null, 2));
1790
+ } else {
1791
+ console.log(`\n ${message}`);
1792
+ console.log('');
1793
+
1794
+ // Track if columns were explicitly specified
1795
+ const columnsExplicit = columns !== null;
1796
+
1797
+ for (let i = 0; i < previewObjects.length; i++) {
1798
+ const obj = previewObjects[i];
1799
+ const objName = obj.NAME || obj.name || `Object ${i + 1}`;
1800
+ const objType = obj.TYPE || obj.type || '';
1801
+ const objTypeText = obj.TYPE_TEXT || obj.type_text || '';
1802
+ // Parse rows - could be a JSON string or array
1803
+ let rows = obj.ROWS || obj.rows || [];
1804
+ if (typeof rows === 'string') {
1805
+ try {
1806
+ rows = JSON.parse(rows);
1807
+ } catch (e) {
1808
+ rows = [];
1809
+ }
1810
+ }
1811
+ const fields = obj.FIELDS || obj.fields || [];
1812
+ const rowCount = obj.ROW_COUNT || obj.row_count || 0;
1813
+ const totalRows = obj.TOTAL_ROWS || obj.total_rows || 0;
1814
+ const notFound = obj.NOT_FOUND || obj.not_found || false;
1815
+ const accessDenied = obj.ACCESS_DENIED || obj.access_denied || false;
1816
+
1817
+ // Check if object was not found
1818
+ if (notFound) {
1819
+ console.log(` ❌ ${objName} (${objTypeText})`);
1820
+ console.log(` Object not found: ${objName}`);
1821
+ continue;
1822
+ }
1823
+
1824
+ // Check if access denied
1825
+ if (accessDenied) {
1826
+ console.log(` ❌ ${objName} (${objTypeText})`);
1827
+ console.log(` Access denied to: ${objName}`);
1828
+ continue;
1829
+ }
1830
+
1831
+ console.log(` 📊 Preview: ${objName} (${objTypeText})`);
1832
+
1833
+ // Check for errors first
1834
+ const objError = obj.ERROR || obj.error;
1835
+ if (objError) {
1836
+ console.log(` ❌ Error: ${objError}`);
1837
+ continue;
1838
+ }
1839
+
1840
+ if (rows.length === 0) {
1841
+ console.log(' No data found');
1842
+ continue;
1843
+ }
1844
+
1845
+ // Get all unique field names from all rows
1846
+ const allFields = new Set();
1847
+ rows.forEach(row => {
1848
+ Object.keys(row).forEach(key => allFields.add(key));
1849
+ });
1850
+ const allFieldNames = Array.from(allFields);
1851
+
1852
+ // Display as table - use fields metadata only if --columns was explicitly specified
1853
+ let fieldNames;
1854
+ let columnsAutoSelected = false;
1855
+ if (columnsExplicit && fields && fields.length > 0) {
1856
+ // Use fields from metadata (filtered by explicit --columns)
1857
+ fieldNames = fields.map(f => f.FIELD || f.field);
1858
+ } else {
1859
+ // Use all fields - let terminal handle wrapping if needed
1860
+ // Terminal width detection is unreliable without a proper TTY
1861
+ fieldNames = allFieldNames;
1862
+ }
1863
+
1864
+ // Calculate column widths - use reasonable defaults
1865
+ const colWidths = {};
1866
+ const maxColWidth = compactOutput ? 10 : 20;
1867
+ fieldNames.forEach(field => {
1868
+ let maxWidth = field.length;
1869
+ rows.forEach(row => {
1870
+ const value = String(row[field] || '');
1871
+ maxWidth = Math.max(maxWidth, value.length);
1872
+ });
1873
+ // Cap at maxColWidth (truncates both headers and data in compact mode)
1874
+ colWidths[field] = Math.min(maxWidth, maxColWidth);
1875
+ });
1876
+
1877
+ // Render output - either vertical or table
1878
+ if (verticalOutput) {
1879
+ // Vertical format: each field on its own line
1880
+ rows.forEach((row, rowIndex) => {
1881
+ if (rows.length > 1) {
1882
+ console.log(`\n Row ${rowIndex + 1}:`);
1883
+ console.log(' ' + '─'.repeat(30));
1884
+ }
1885
+ fieldNames.forEach(field => {
1886
+ const value = String(row[field] || '');
1887
+ console.log(` ${field}: ${value}`);
1888
+ });
1889
+ });
1890
+ console.log('');
1891
+ continue;
1892
+ }
1893
+
1894
+ // Build table header
1895
+ let headerLine = ' ┌';
1896
+ let separatorLine = ' ├';
1897
+ fieldNames.forEach(field => {
1898
+ const width = colWidths[field];
1899
+ headerLine += '─'.repeat(width + 2) + '┬';
1900
+ separatorLine += '─'.repeat(width + 2) + '┼';
1901
+ });
1902
+ headerLine = headerLine.slice(0, -1) + '┐';
1903
+ separatorLine = separatorLine.slice(0, -1) + '┤';
1904
+
1905
+ // Build header row
1906
+ let headerRow = ' │';
1907
+ fieldNames.forEach(field => {
1908
+ const width = colWidths[field];
1909
+ let displayField = String(field);
1910
+ if (displayField.length > width) {
1911
+ displayField = displayField.slice(0, width - 3) + '...';
1912
+ }
1913
+ headerRow += ' ' + displayField.padEnd(width) + ' │';
1914
+ });
1915
+
1916
+ console.log(headerLine);
1917
+ console.log(headerRow);
1918
+ console.log(separatorLine);
1919
+
1920
+ // Build data rows
1921
+ rows.forEach(row => {
1922
+ let dataRow = ' │';
1923
+ fieldNames.forEach(field => {
1924
+ const width = colWidths[field];
1925
+ const value = String(row[field] || '');
1926
+ const displayValue = value.length > width ? value.slice(0, width - 3) + '...' : value;
1927
+ dataRow += ' ' + displayValue.padEnd(width) + ' │';
1928
+ });
1929
+ console.log(dataRow);
1930
+ });
1931
+
1932
+ // Build bottom border
1933
+ let bottomLine = ' └';
1934
+ fieldNames.forEach(field => {
1935
+ const width = colWidths[field];
1936
+ bottomLine += '─'.repeat(width + 2) + '┴';
1937
+ });
1938
+ bottomLine = bottomLine.slice(0, -1) + '┘';
1939
+ console.log(bottomLine);
1940
+
1941
+ // Show row count
1942
+ if (totalRows > rowCount) {
1943
+ console.log(`\n Showing ${rowCount} of ${totalRows} rows`);
1944
+ } else {
1945
+ console.log(`\n ${rowCount} row(s)`);
1946
+ }
1947
+
1948
+ // Note about hidden columns only when --columns was explicitly specified
1949
+ const columnsDisplayed = fieldNames.length;
1950
+ let columnsHidden = [];
1951
+
1952
+ if (columnsExplicit) {
1953
+ columnsHidden = obj.COLUMNS_HIDDEN || obj.columns_hidden || [];
1954
+ if (columnsHidden.length > 0) {
1955
+ console.log(`\n ⚠️ ${columnsHidden.length} more columns hidden (${columnsHidden.join(', ')})`);
1956
+ console.log(' Use --json for full data');
1957
+ }
1958
+ }
1959
+
1960
+ console.log('');
1961
+ }
1962
+ }
1963
+ break;
1964
+ }
1965
+
1729
1966
  case 'help':
1730
1967
  case '--help':
1731
1968
  case '-h':
package/docs/commands.md CHANGED
@@ -14,6 +14,7 @@ All available CLI commands for abapGit Agent.
14
14
  | [tree](tree-command.md) | ✅ | Display package hierarchy tree |
15
15
  | [unit](unit-command.md) | ✅ | Run AUnit tests |
16
16
  | [view](view-command.md) | ✅ | View ABAP object source code from system |
17
+ | [preview](preview-command.md) | 🔄 | Preview table/CDS view data |
17
18
  | [health](health-command.md) | ✅ | Health check |
18
19
  | [status](status-command.md) | ✅ | Status check |
19
20
 
@@ -70,6 +71,10 @@ abapgit-agent tree --package $MY_PACKAGE
70
71
  abapgit-agent view --objects ZCL_MY_CLASS
71
72
  abapgit-agent view --objects SFLIGHT --type TABL
72
73
 
74
+ # Preview table/CDS view data
75
+ abapgit-agent preview --objects SFLIGHT
76
+ abapgit-agent preview --objects ZC_MY_CDS_VIEW --type DDLS
77
+
73
78
  # Check configuration
74
79
  abapgit-agent status
75
80