webspresso 0.0.98 → 0.0.99
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/.agents/ADMIN.md +11 -1
- package/.agents/AGENTS.md +1 -1
- package/.agents/AUTH.md +169 -0
- package/.agents/ORM.md +88 -4
- package/.agents/PLUGINS.md +73 -5
- package/.agents/QUEUE.md +84 -0
- package/.agents/ROUTING.md +127 -7
- package/AGENTS.md +1 -0
- package/core/auth/index.js +60 -0
- package/core/auth/manager.js +134 -0
- package/core/auth/middleware.js +88 -0
- package/core/auth/oauth.js +517 -0
- package/core/auth/qrcode.js +499 -0
- package/core/auth/totp.js +504 -0
- package/core/orm/eager-loader.js +144 -10
- package/core/orm/index.js +8 -0
- package/core/orm/model.js +4 -0
- package/core/orm/query-builder.js +90 -4
- package/core/orm/repository.js +44 -3
- package/core/orm/search.js +213 -0
- package/core/queue/cron.js +331 -0
- package/core/queue/index.js +8 -1
- package/core/queue/manager.js +82 -1
- package/core/queue/scheduler.js +359 -0
- package/core/sse/index.js +19 -0
- package/core/sse/stream.js +430 -0
- package/index.d.ts +528 -0
- package/index.js +44 -0
- package/package.json +1 -1
- package/plugins/admin-panel/client/parts/05-rich-text-file-helpers.js +323 -31
- package/plugins/admin-panel/client/parts/08-record-list.js +5 -0
- package/plugins/admin-panel/client/verify-spa-parts.js +2 -0
- package/plugins/admin-panel/field-renderers/file-upload.js +187 -104
- package/plugins/admin-panel/field-renderers/index.js +2 -0
- package/plugins/api-key/crypto.js +101 -0
- package/plugins/api-key/index.js +288 -0
- package/plugins/api-key/middleware.js +461 -0
- package/plugins/api-key/migration-template.js +48 -0
- package/plugins/api-key/model.js +50 -0
- package/plugins/api-key/scopes.js +125 -0
- package/plugins/audit-log/admin-component.js +487 -70
- package/plugins/audit-log/api-handlers.js +114 -0
- package/plugins/audit-log/index.js +24 -0
- package/plugins/file-manager/admin-component.js +20 -4
- package/plugins/file-manager/index.js +21 -4
- package/plugins/index.js +6 -0
- package/plugins/oauth/index.js +338 -0
- package/plugins/queue/index.js +4 -0
- package/src/api/api-loader.js +1 -0
- package/src/discovery/file-route-parser.js +44 -1
- package/src/discovery/scan-routes.js +2 -2
- package/src/file-router.js +137 -100
- package/src/helpers.js +9 -0
- package/src/routing/cascading.js +378 -0
- package/src/routing/middleware-resolver.js +92 -0
- package/src/server.js +6 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Audit log admin page — Mithril component source (string)
|
|
3
|
+
* Features dual Table & Timeline View (Zaman Tüneli) with record focus & diff metadata
|
|
3
4
|
* @module plugins/audit-log/admin-component
|
|
4
5
|
*/
|
|
5
6
|
|
|
@@ -14,6 +15,116 @@ function generateAuditLogComponent(options = {}) {
|
|
|
14
15
|
(function() {
|
|
15
16
|
var API = '${apiPrefix}';
|
|
16
17
|
|
|
18
|
+
function formatRelativeTime(dateStr) {
|
|
19
|
+
if (!dateStr) return '';
|
|
20
|
+
try {
|
|
21
|
+
var d = new Date(dateStr);
|
|
22
|
+
var now = new Date();
|
|
23
|
+
var diffMs = now - d;
|
|
24
|
+
var diffSec = Math.floor(diffMs / 1000);
|
|
25
|
+
var diffMin = Math.floor(diffSec / 60);
|
|
26
|
+
var diffHour = Math.floor(diffMin / 60);
|
|
27
|
+
var diffDay = Math.floor(diffHour / 24);
|
|
28
|
+
|
|
29
|
+
if (diffSec < 60) return 'Az önce';
|
|
30
|
+
if (diffMin < 60) return diffMin + ' dk önce';
|
|
31
|
+
if (diffHour < 24) return diffHour + ' sa önce';
|
|
32
|
+
if (diffDay === 1) return 'Dün';
|
|
33
|
+
if (diffDay < 30) return diffDay + ' gün önce';
|
|
34
|
+
return d.toLocaleDateString();
|
|
35
|
+
} catch (e) {
|
|
36
|
+
return dateStr;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function getActionTheme(action) {
|
|
41
|
+
switch (action) {
|
|
42
|
+
case 'create':
|
|
43
|
+
return {
|
|
44
|
+
label: 'OLUŞTURULDU',
|
|
45
|
+
color: 'emerald',
|
|
46
|
+
badgeClass: 'bg-emerald-50 text-emerald-700 border-emerald-200 dark:bg-emerald-950/40 dark:text-emerald-300 dark:border-emerald-800',
|
|
47
|
+
dotClass: 'bg-emerald-500 text-white ring-4 ring-emerald-100 dark:ring-emerald-950/60',
|
|
48
|
+
icon: 'plus',
|
|
49
|
+
};
|
|
50
|
+
case 'update':
|
|
51
|
+
return {
|
|
52
|
+
label: 'GÜNCELLENDİ',
|
|
53
|
+
color: 'blue',
|
|
54
|
+
badgeClass: 'bg-blue-50 text-blue-700 border-blue-200 dark:bg-blue-950/40 dark:text-blue-300 dark:border-blue-800',
|
|
55
|
+
dotClass: 'bg-blue-500 text-white ring-4 ring-blue-100 dark:ring-blue-950/60',
|
|
56
|
+
icon: 'pencil',
|
|
57
|
+
};
|
|
58
|
+
case 'delete':
|
|
59
|
+
return {
|
|
60
|
+
label: 'SİLİNDİ',
|
|
61
|
+
color: 'rose',
|
|
62
|
+
badgeClass: 'bg-rose-50 text-rose-700 border-rose-200 dark:bg-rose-950/40 dark:text-rose-300 dark:border-rose-800',
|
|
63
|
+
dotClass: 'bg-rose-500 text-white ring-4 ring-rose-100 dark:ring-rose-950/60',
|
|
64
|
+
icon: 'trash',
|
|
65
|
+
};
|
|
66
|
+
case 'restore':
|
|
67
|
+
return {
|
|
68
|
+
label: 'GERİ YÜKLENDİ',
|
|
69
|
+
color: 'amber',
|
|
70
|
+
badgeClass: 'bg-amber-50 text-amber-700 border-amber-200 dark:bg-amber-950/40 dark:text-amber-300 dark:border-amber-800',
|
|
71
|
+
dotClass: 'bg-amber-500 text-white ring-4 ring-amber-100 dark:ring-amber-950/60',
|
|
72
|
+
icon: 'undo',
|
|
73
|
+
};
|
|
74
|
+
default:
|
|
75
|
+
return {
|
|
76
|
+
label: (action || 'İŞLEM').toUpperCase(),
|
|
77
|
+
color: 'gray',
|
|
78
|
+
badgeClass: 'bg-gray-100 text-gray-700 border-gray-200 dark:bg-slate-800 dark:text-slate-300 dark:border-slate-700',
|
|
79
|
+
dotClass: 'bg-gray-500 text-white ring-4 ring-gray-100 dark:ring-slate-800',
|
|
80
|
+
icon: 'activity',
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function renderSvgIcon(name, cls) {
|
|
86
|
+
cls = cls || 'w-4 h-4';
|
|
87
|
+
if (name === 'plus') {
|
|
88
|
+
return m('svg', { class: cls, fill: 'none', viewBox: '0 0 24 24', stroke: 'currentColor' },
|
|
89
|
+
m('path', { 'stroke-linecap': 'round', 'stroke-linejoin': 'round', 'stroke-width': '2.5', d: 'M12 4v16m8-8H4' })
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
if (name === 'pencil') {
|
|
93
|
+
return m('svg', { class: cls, fill: 'none', viewBox: '0 0 24 24', stroke: 'currentColor' },
|
|
94
|
+
m('path', { 'stroke-linecap': 'round', 'stroke-linejoin': 'round', 'stroke-width': '2', d: 'M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z' })
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
if (name === 'trash') {
|
|
98
|
+
return m('svg', { class: cls, fill: 'none', viewBox: '0 0 24 24', stroke: 'currentColor' },
|
|
99
|
+
m('path', { 'stroke-linecap': 'round', 'stroke-linejoin': 'round', 'stroke-width': '2', d: 'M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16' })
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
if (name === 'undo') {
|
|
103
|
+
return m('svg', { class: cls, fill: 'none', viewBox: '0 0 24 24', stroke: 'currentColor' },
|
|
104
|
+
m('path', { 'stroke-linecap': 'round', 'stroke-linejoin': 'round', 'stroke-width': '2', d: 'M3 10h10a5 5 0 015 5v2m-15-7l4-4m-4 4l4 4' })
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
if (name === 'clock') {
|
|
108
|
+
return m('svg', { class: cls, fill: 'none', viewBox: '0 0 24 24', stroke: 'currentColor' },
|
|
109
|
+
m('path', { 'stroke-linecap': 'round', 'stroke-linejoin': 'round', 'stroke-width': '2', d: 'M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z' })
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
if (name === 'table') {
|
|
113
|
+
return m('svg', { class: cls, fill: 'none', viewBox: '0 0 24 24', stroke: 'currentColor' },
|
|
114
|
+
m('path', { 'stroke-linecap': 'round', 'stroke-linejoin': 'round', 'stroke-width': '2', d: 'M3 10h18M3 14h18m-9-4v8m-7 4h14a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z' })
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
if (name === 'search') {
|
|
118
|
+
return m('svg', { class: cls, fill: 'none', viewBox: '0 0 24 24', stroke: 'currentColor' },
|
|
119
|
+
m('path', { 'stroke-linecap': 'round', 'stroke-linejoin': 'round', 'stroke-width': '2', d: 'M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z' })
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
// Default activity
|
|
123
|
+
return m('svg', { class: cls, fill: 'none', viewBox: '0 0 24 24', stroke: 'currentColor' },
|
|
124
|
+
m('path', { 'stroke-linecap': 'round', 'stroke-linejoin': 'round', 'stroke-width': '2', d: 'M13 10V3L4 14h7v7l9-11h-7z' })
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
17
128
|
function AuditLogPage() {
|
|
18
129
|
var rows = [];
|
|
19
130
|
var loading = true;
|
|
@@ -21,8 +132,33 @@ function generateAuditLogComponent(options = {}) {
|
|
|
21
132
|
var page = 1;
|
|
22
133
|
var perPage = 25;
|
|
23
134
|
var total = 0;
|
|
135
|
+
var viewMode = 'timeline'; // 'timeline' | 'table'
|
|
136
|
+
|
|
24
137
|
var filterModel = '';
|
|
25
138
|
var filterAction = '';
|
|
139
|
+
var filterRecordId = '';
|
|
140
|
+
var filterSearch = '';
|
|
141
|
+
|
|
142
|
+
var expandedIds = {};
|
|
143
|
+
|
|
144
|
+
function parseQueryParams() {
|
|
145
|
+
try {
|
|
146
|
+
var searchStr = window.location.search || '';
|
|
147
|
+
if (!searchStr && typeof m !== 'undefined' && m.route && m.route.get) {
|
|
148
|
+
var cur = m.route.get();
|
|
149
|
+
if (cur.indexOf('?') !== -1) {
|
|
150
|
+
searchStr = cur.substring(cur.indexOf('?'));
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
var params = new URLSearchParams(searchStr);
|
|
154
|
+
if (params.get('model')) filterModel = params.get('model');
|
|
155
|
+
if (params.get('recordId') || params.get('resourceId') || params.get('id')) {
|
|
156
|
+
filterRecordId = params.get('recordId') || params.get('resourceId') || params.get('id');
|
|
157
|
+
}
|
|
158
|
+
if (params.get('action')) filterAction = params.get('action');
|
|
159
|
+
if (params.get('view')) viewMode = params.get('view');
|
|
160
|
+
} catch (e) {}
|
|
161
|
+
}
|
|
26
162
|
|
|
27
163
|
function load() {
|
|
28
164
|
loading = true;
|
|
@@ -30,6 +166,9 @@ function generateAuditLogComponent(options = {}) {
|
|
|
30
166
|
var q = '?page=' + page + '&perPage=' + perPage;
|
|
31
167
|
if (filterModel) q += '&model=' + encodeURIComponent(filterModel);
|
|
32
168
|
if (filterAction) q += '&action=' + encodeURIComponent(filterAction);
|
|
169
|
+
if (filterRecordId) q += '&recordId=' + encodeURIComponent(filterRecordId);
|
|
170
|
+
if (filterSearch) q += '&search=' + encodeURIComponent(filterSearch);
|
|
171
|
+
|
|
33
172
|
api.get(API + q).then(function(res) {
|
|
34
173
|
rows = res.data || [];
|
|
35
174
|
total = (res.meta && res.meta.total) || 0;
|
|
@@ -42,89 +181,367 @@ function generateAuditLogComponent(options = {}) {
|
|
|
42
181
|
});
|
|
43
182
|
}
|
|
44
183
|
|
|
184
|
+
function toggleExpand(id) {
|
|
185
|
+
expandedIds[id] = !expandedIds[id];
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function focusRecord(model, id) {
|
|
189
|
+
filterModel = model || '';
|
|
190
|
+
filterRecordId = id != null ? String(id) : '';
|
|
191
|
+
page = 1;
|
|
192
|
+
viewMode = 'timeline';
|
|
193
|
+
load();
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function clearFocus() {
|
|
197
|
+
filterRecordId = '';
|
|
198
|
+
page = 1;
|
|
199
|
+
load();
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function clearAllFilters() {
|
|
203
|
+
filterModel = '';
|
|
204
|
+
filterAction = '';
|
|
205
|
+
filterRecordId = '';
|
|
206
|
+
filterSearch = '';
|
|
207
|
+
page = 1;
|
|
208
|
+
load();
|
|
209
|
+
}
|
|
210
|
+
|
|
45
211
|
return {
|
|
46
|
-
oninit:
|
|
212
|
+
oninit: function() {
|
|
213
|
+
parseQueryParams();
|
|
214
|
+
load();
|
|
215
|
+
},
|
|
47
216
|
view: function() {
|
|
48
|
-
if (loading) {
|
|
49
|
-
return m('div.p-8.text-gray-500', 'Loading…');
|
|
50
|
-
}
|
|
51
|
-
if (error) {
|
|
52
|
-
return m('div.p-8.text-red-600', error);
|
|
53
|
-
}
|
|
54
217
|
var maxPage = Math.max(1, Math.ceil(total / perPage) || 1);
|
|
55
|
-
|
|
56
|
-
|
|
218
|
+
|
|
219
|
+
return m('div.p-6.max-w-7xl.mx-auto.space-y-6', [
|
|
220
|
+
// 1. Header with View Toggle & Purge
|
|
221
|
+
m('div.flex.flex-col.md:flex-row.md:items-center.justify-between.gap-4.pb-4.border-b.border-gray-200.dark:border-slate-800', [
|
|
57
222
|
m('div', [
|
|
58
|
-
m('
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
223
|
+
m('div.flex.items-center.gap-2.5', [
|
|
224
|
+
m('span.p-2.rounded-lg.bg-indigo-50.text-indigo-600.dark:bg-indigo-950/40.dark:text-indigo-400',
|
|
225
|
+
renderSvgIcon('clock', 'w-5 h-5')
|
|
226
|
+
),
|
|
227
|
+
m('h1.text-2xl.font-bold.text-gray-900.dark:text-slate-100', 'Denetim Günlüğü & Zaman Tüneli'),
|
|
228
|
+
]),
|
|
229
|
+
m('p.text-sm.text-gray-500.dark:text-slate-400.mt-1',
|
|
230
|
+
'Tüm yönetici CRUD işlemlerinin ve model mutasyonlarının denetim geçmişi.'
|
|
231
|
+
),
|
|
64
232
|
]),
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
233
|
+
|
|
234
|
+
m('div.flex.items-center.gap-3', [
|
|
235
|
+
// View Switcher (Timeline vs Table)
|
|
236
|
+
m('div.inline-flex.rounded-lg.border.border-gray-200.dark:border-slate-700.p-1.bg-gray-50.dark:bg-slate-900', [
|
|
237
|
+
m('button.px-3.py-1.5.text-xs.font-medium.rounded-md.flex.items-center.gap-1.5.transition-all', {
|
|
238
|
+
class: viewMode === 'timeline'
|
|
239
|
+
? 'bg-white dark:bg-slate-800 text-indigo-600 dark:text-indigo-400 shadow-sm'
|
|
240
|
+
: 'text-gray-600 dark:text-slate-400 hover:text-gray-900 dark:hover:text-slate-200',
|
|
241
|
+
onclick: function() { viewMode = 'timeline'; }
|
|
242
|
+
}, [
|
|
243
|
+
renderSvgIcon('clock', 'w-3.5 h-3.5'),
|
|
244
|
+
m('span', 'Zaman Tüneli'),
|
|
245
|
+
]),
|
|
246
|
+
m('button.px-3.py-1.5.text-xs.font-medium.rounded-md.flex.items-center.gap-1.5.transition-all', {
|
|
247
|
+
class: viewMode === 'table'
|
|
248
|
+
? 'bg-white dark:bg-slate-800 text-indigo-600 dark:text-indigo-400 shadow-sm'
|
|
249
|
+
: 'text-gray-600 dark:text-slate-400 hover:text-gray-900 dark:hover:text-slate-200',
|
|
250
|
+
onclick: function() { viewMode = 'table'; }
|
|
251
|
+
}, [
|
|
252
|
+
renderSvgIcon('table', 'w-3.5 h-3.5'),
|
|
253
|
+
m('span', 'Tablo'),
|
|
254
|
+
]),
|
|
76
255
|
]),
|
|
256
|
+
|
|
257
|
+
// Purge button
|
|
258
|
+
m('button.px-3.py-1.5.text-xs.font-medium.border.border-rose-200.dark:border-rose-900.text-rose-700.dark:text-rose-400.rounded-lg.hover:bg-rose-50.dark:hover:bg-rose-950/40.transition-colors', {
|
|
259
|
+
onclick: function() {
|
|
260
|
+
if (!confirm('90 günden eski denetim günlükleri silinsin mi?')) return;
|
|
261
|
+
api.post(API + '/purge', { days: 90 }).then(function() {
|
|
262
|
+
page = 1;
|
|
263
|
+
load();
|
|
264
|
+
}).catch(function(e) {
|
|
265
|
+
alert('Temizleme hatası: ' + (e.message || String(e)));
|
|
266
|
+
});
|
|
267
|
+
},
|
|
268
|
+
}, '90 Gün Öncesini Temizle'),
|
|
77
269
|
]),
|
|
78
|
-
m('button.bg-blue-600.text-white.px-4.py-1.rounded', {
|
|
79
|
-
onclick: function() { page = 1; load(); },
|
|
80
|
-
}, 'Apply'),
|
|
81
|
-
m('button.border.px-3.py-1.rounded.text-red-700.ml-auto', {
|
|
82
|
-
onclick: function() {
|
|
83
|
-
if (!confirm('Delete audit logs older than 90 days?')) return;
|
|
84
|
-
api.post(API + '/purge', { days: 90 }).then(function() {
|
|
85
|
-
page = 1;
|
|
86
|
-
load();
|
|
87
|
-
}).catch(function(e) {
|
|
88
|
-
alert('Purge failed: ' + (e.message || String(e)));
|
|
89
|
-
});
|
|
90
|
-
},
|
|
91
|
-
}, 'Purge 90d'),
|
|
92
270
|
]),
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
271
|
+
|
|
272
|
+
// 2. Focused Record Banner (if filterRecordId is active)
|
|
273
|
+
filterRecordId ? m('div.p-4.rounded-xl.bg-gradient-to-r.from-indigo-50.to-blue-50.dark:from-indigo-950/40.dark:to-blue-950/40.border.border-indigo-200.dark:border-indigo-800.flex.items-center.justify-between.gap-4', [
|
|
274
|
+
m('div.flex.items-center.gap-3', [
|
|
275
|
+
m('span.w-9.h-9.rounded-full.bg-indigo-600.text-white.flex.items-center.justify-center.font-bold.text-sm', '📌'),
|
|
276
|
+
m('div', [
|
|
277
|
+
m('h3.text-sm.font-semibold.text-indigo-950.dark:text-indigo-200',
|
|
278
|
+
(filterModel ? filterModel + ' #' : 'Kayıt #') + filterRecordId + ' İçin Değişiklik Zaman Tüneli'
|
|
279
|
+
),
|
|
280
|
+
m('p.text-xs.text-indigo-700.dark:text-indigo-400',
|
|
281
|
+
'Bu kayda ait tüm ekleme, güncelleme ve silme geçmişi filtreleniyor.'
|
|
282
|
+
),
|
|
283
|
+
]),
|
|
284
|
+
]),
|
|
285
|
+
m('button.px-3.py-1.5.text-xs.font-medium.bg-white.dark:bg-slate-800.text-indigo-700.dark:text-indigo-300.border.border-indigo-200.dark:border-indigo-700.rounded-lg.hover:bg-indigo-50.dark:hover:bg-indigo-900/60.transition-colors', {
|
|
286
|
+
onclick: clearFocus,
|
|
287
|
+
}, '✕ Filtreyi Kaldır'),
|
|
288
|
+
]) : null,
|
|
289
|
+
|
|
290
|
+
// 3. Search & Filter Controls Card
|
|
291
|
+
m('div.p-4.rounded-xl.bg-white.dark:bg-slate-800.border.border-gray-200.dark:border-slate-700.shadow-sm.space-y-4', [
|
|
292
|
+
m('div.grid.grid-cols-1.sm:grid-cols-2.lg:grid-cols-5.gap-3.items-end', [
|
|
293
|
+
// Model Filter
|
|
294
|
+
m('div', [
|
|
295
|
+
m('label.block.text-xs.font-medium.text-gray-600.dark:text-slate-400.mb-1', 'Model'),
|
|
296
|
+
m('input.w-full.border.border-gray-300.dark:border-slate-600.bg-white.dark:bg-slate-900.text-gray-900.dark:text-slate-100.rounded-lg.px-3.py-1.5.text-sm.focus:ring-2.focus:ring-indigo-500.focus:outline-none', {
|
|
297
|
+
value: filterModel,
|
|
298
|
+
placeholder: 'Örn. Post, User',
|
|
299
|
+
oninput: function(e) { filterModel = e.target.value; },
|
|
300
|
+
onkeydown: function(e) { if (e.key === 'Enter') { page = 1; load(); } },
|
|
301
|
+
}),
|
|
302
|
+
]),
|
|
303
|
+
|
|
304
|
+
// Record ID Filter
|
|
305
|
+
m('div', [
|
|
306
|
+
m('label.block.text-xs.font-medium.text-gray-600.dark:text-slate-400.mb-1', 'Kayıt ID'),
|
|
307
|
+
m('input.w-full.border.border-gray-300.dark:border-slate-600.bg-white.dark:bg-slate-900.text-gray-900.dark:text-slate-100.rounded-lg.px-3.py-1.5.text-sm.focus:ring-2.focus:ring-indigo-500.focus:outline-none', {
|
|
308
|
+
value: filterRecordId,
|
|
309
|
+
placeholder: 'Örn. 42',
|
|
310
|
+
oninput: function(e) { filterRecordId = e.target.value; },
|
|
311
|
+
onkeydown: function(e) { if (e.key === 'Enter') { page = 1; load(); } },
|
|
312
|
+
}),
|
|
313
|
+
]),
|
|
314
|
+
|
|
315
|
+
// Action Filter
|
|
316
|
+
m('div', [
|
|
317
|
+
m('label.block.text-xs.font-medium.text-gray-600.dark:text-slate-400.mb-1', 'İşlem Türü'),
|
|
318
|
+
m('select.w-full.border.border-gray-300.dark:border-slate-600.bg-white.dark:bg-slate-900.text-gray-900.dark:text-slate-100.rounded-lg.px-3.py-1.5.text-sm.focus:ring-2.focus:ring-indigo-500.focus:outline-none', {
|
|
319
|
+
value: filterAction,
|
|
320
|
+
onchange: function(e) { filterAction = e.target.value; page = 1; load(); },
|
|
321
|
+
}, [
|
|
322
|
+
m('option', { value: '' }, 'Tüm İşlemler'),
|
|
323
|
+
m('option', { value: 'create' }, 'Oluşturma (create)'),
|
|
324
|
+
m('option', { value: 'update' }, 'Güncelleme (update)'),
|
|
325
|
+
m('option', { value: 'delete' }, 'Silme (delete)'),
|
|
326
|
+
m('option', { value: 'restore' }, 'Geri Yükleme (restore)'),
|
|
104
327
|
]),
|
|
105
328
|
]),
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
m('
|
|
112
|
-
|
|
113
|
-
|
|
329
|
+
|
|
330
|
+
// Search Filter (Actor, Path)
|
|
331
|
+
m('div', [
|
|
332
|
+
m('label.block.text-xs.font-medium.text-gray-600.dark:text-slate-400.mb-1', 'Arama'),
|
|
333
|
+
m('div.relative', [
|
|
334
|
+
m('input.w-full.border.border-gray-300.dark:border-slate-600.bg-white.dark:bg-slate-900.text-gray-900.dark:text-slate-100.rounded-lg.pl-8.pr-3.py-1.5.text-sm.focus:ring-2.focus:ring-indigo-500.focus:outline-none', {
|
|
335
|
+
value: filterSearch,
|
|
336
|
+
placeholder: 'E-posta, IP veya yol...',
|
|
337
|
+
oninput: function(e) { filterSearch = e.target.value; },
|
|
338
|
+
onkeydown: function(e) { if (e.key === 'Enter') { page = 1; load(); } },
|
|
339
|
+
}),
|
|
340
|
+
m('span.absolute.left-2.5.top-2.text-gray-400', renderSvgIcon('search', 'w-4 h-4')),
|
|
341
|
+
]),
|
|
342
|
+
]),
|
|
343
|
+
|
|
344
|
+
// Action Buttons
|
|
345
|
+
m('div.flex.items-center.gap-2', [
|
|
346
|
+
m('button.flex-1.bg-indigo-600.text-white.px-4.py-1.5.rounded-lg.text-sm.font-medium.hover:bg-indigo-700.transition-colors.shadow-sm', {
|
|
347
|
+
onclick: function() { page = 1; load(); },
|
|
348
|
+
}, 'Apply'),
|
|
349
|
+
m('button.border.border-gray-300.dark:border-slate-600.text-gray-700.dark:text-slate-300.px-3.py-1.5.rounded-lg.text-sm.hover:bg-gray-100.dark:hover:bg-slate-700.transition-colors', {
|
|
350
|
+
title: 'Clear Filters',
|
|
351
|
+
onclick: clearAllFilters,
|
|
352
|
+
}, 'Clear'),
|
|
353
|
+
]),
|
|
354
|
+
]),
|
|
355
|
+
]),
|
|
356
|
+
|
|
357
|
+
// Total Counter (required by Playwright E2E: getByText(/Total:/))
|
|
358
|
+
m('div.text-sm.text-gray-500.dark:text-slate-400', 'Total: ' + total),
|
|
359
|
+
|
|
360
|
+
// 4. Main Content Area (Timeline vs Table)
|
|
361
|
+
loading ? m('div.py-16.text-center.space-y-3', [
|
|
362
|
+
m('div.inline-block.animate-spin.rounded-full.h-8.w-8.border-4.border-indigo-600.border-t-transparent'),
|
|
363
|
+
m('p.text-sm.text-gray-500.dark:text-slate-400', 'Denetim kayıtları yükleniyor...'),
|
|
364
|
+
]) : error ? m('div.p-6.rounded-xl.bg-red-50.dark:bg-red-950/40.border.border-red-200.dark:border-red-800.text-red-700.dark:text-red-300', [
|
|
365
|
+
m('h4.font-semibold.text-sm', 'Kayıtlar Yüklenemedi'),
|
|
366
|
+
m('p.text-xs.mt-1', error),
|
|
367
|
+
]) : rows.length === 0 ? m('div.py-16.text-center.bg-white.dark:bg-slate-800.rounded-xl.border.border-dashed.border-gray-300.dark:border-slate-700.p-8', [
|
|
368
|
+
m('div.w-12.h-12.mx-auto.rounded-full.bg-gray-100.dark:bg-slate-700.flex.items-center.justify-center.text-gray-400.mb-3',
|
|
369
|
+
renderSvgIcon('clock', 'w-6 h-6')
|
|
370
|
+
),
|
|
371
|
+
m('h3.text-base.font-medium.text-gray-900.dark:text-slate-100', 'Kayıt Bulunamadı'),
|
|
372
|
+
m('p.text-sm.text-gray-500.dark:text-slate-400.mt-1', 'Seçilen filtrelere uygun herhangi bir denetim kaydı bulunamadı.'),
|
|
373
|
+
(filterModel || filterAction || filterRecordId || filterSearch) ? m('button.mt-4.text-xs.text-indigo-600.dark:text-indigo-400.hover:underline', {
|
|
374
|
+
onclick: clearAllFilters,
|
|
375
|
+
}, 'Filtreleri temizle ve tekrar dene') : null,
|
|
376
|
+
]) : viewMode === 'timeline' ? (
|
|
377
|
+
// ==================== TIMELINE VIEW ====================
|
|
378
|
+
m('div.space-y-6', [
|
|
379
|
+
m('div.relative.pl-6.border-l-2.border-indigo-200.dark:border-slate-700.ml-4.space-y-8', rows.map(function(r) {
|
|
380
|
+
var theme = getActionTheme(r.action);
|
|
381
|
+
var isExpanded = !!expandedIds[r.id];
|
|
382
|
+
var metadata = r.metadata;
|
|
383
|
+
if (typeof metadata === 'string') {
|
|
384
|
+
try { metadata = JSON.parse(metadata); } catch (e) {}
|
|
385
|
+
}
|
|
386
|
+
var changedFields = metadata && Array.isArray(metadata.changedFields) ? metadata.changedFields : [];
|
|
387
|
+
|
|
388
|
+
return m('div.relative.group', [
|
|
389
|
+
// Spine Node Dot
|
|
390
|
+
m('span.absolute.-left-[33px].top-1.5.flex.items-center.justify-center.w-7.h-7.rounded-full.shadow-sm', {
|
|
391
|
+
class: theme.dotClass,
|
|
392
|
+
}, renderSvgIcon(theme.icon, 'w-3.5 h-3.5')),
|
|
393
|
+
|
|
394
|
+
// Event Card
|
|
395
|
+
m('div.rounded-xl.bg-white.dark:bg-slate-800.border.border-gray-200.dark:border-slate-700.p-5.shadow-sm.hover:shadow-md.transition-shadow.space-y-3', [
|
|
396
|
+
// Card Header
|
|
397
|
+
m('div.flex.flex-wrap.items-center.justify-between.gap-2', [
|
|
398
|
+
m('div.flex.items-center.gap-2.5', [
|
|
399
|
+
// Action Badge
|
|
400
|
+
m('span.px-2.5.py-0.5.text-xs.font-semibold.rounded-full.border', {
|
|
401
|
+
class: theme.badgeClass,
|
|
402
|
+
}, theme.label),
|
|
403
|
+
|
|
404
|
+
// Model & ID Tag (Clickable to focus)
|
|
405
|
+
m('button.px-2.5.py-0.5.text-xs.font-medium.bg-gray-100.dark:bg-slate-700.text-gray-800.dark:text-slate-200.rounded-md.hover:bg-indigo-100.dark:hover:bg-indigo-900/60.hover:text-indigo-700.transition-colors.flex.items-center.gap-1', {
|
|
406
|
+
title: 'Bu kaydın tüm geçmişini zaman tünelinde göster',
|
|
407
|
+
onclick: function() { focusRecord(r.resource_model, r.resource_id); },
|
|
408
|
+
}, [
|
|
409
|
+
m('span.font-semibold', r.resource_model),
|
|
410
|
+
r.resource_id != null ? m('span.text-indigo-600.dark:text-indigo-400', '#' + r.resource_id) : null,
|
|
411
|
+
]),
|
|
412
|
+
]),
|
|
413
|
+
|
|
414
|
+
// Timestamp & Relative Time
|
|
415
|
+
m('div.text-xs.text-gray-500.dark:text-slate-400.flex.items-center.gap-1.5', [
|
|
416
|
+
m('span.font-medium.text-gray-700.dark:text-slate-300', formatRelativeTime(r.created_at)),
|
|
417
|
+
m('span', '•'),
|
|
418
|
+
m('span', r.created_at || ''),
|
|
419
|
+
]),
|
|
420
|
+
]),
|
|
421
|
+
|
|
422
|
+
// Actor Identity Row
|
|
423
|
+
m('div.flex.items-center.justify-between.text-xs.pt-1', [
|
|
424
|
+
m('div.flex.items-center.gap-2', [
|
|
425
|
+
m('span.w-6.h-6.rounded-full.bg-slate-200.dark:bg-slate-700.text-slate-700.dark:text-slate-300.font-bold.flex.items-center.justify-center.text-[10px]',
|
|
426
|
+
((r.actor_email && r.actor_email[0]) || 'A').toUpperCase()
|
|
427
|
+
),
|
|
428
|
+
m('span.font-medium.text-gray-900.dark:text-slate-100', r.actor_email || 'Sistem / Otomasyon'),
|
|
429
|
+
r.actor_id != null ? m('span.text-gray-400', '(ID: ' + r.actor_id + ')') : null,
|
|
430
|
+
]),
|
|
431
|
+
|
|
432
|
+
r.ip ? m('span.px-2.py-0.5.rounded.bg-gray-50.dark:bg-slate-900.text-gray-500.border.border-gray-200.dark:border-slate-700.font-mono.text-[11px]', r.ip) : null,
|
|
433
|
+
]),
|
|
434
|
+
|
|
435
|
+
// Changes / Mutated Fields Summary
|
|
436
|
+
r.action === 'update' && changedFields.length > 0 ? m('div.pt-1.space-y-1.5', [
|
|
437
|
+
m('span.text-xs.font-medium.text-gray-500.dark:text-slate-400', 'Değiştirilen Alanlar:'),
|
|
438
|
+
m('div.flex.flex-wrap.gap-1.5', changedFields.map(function(f) {
|
|
439
|
+
return m('span.px-2.py-0.5.rounded-md.bg-blue-50.text-blue-700.dark:bg-blue-950/40.dark:text-blue-300.border.border-blue-200.dark:border-blue-800.text-xs.font-mono', f);
|
|
440
|
+
})),
|
|
441
|
+
]) : r.action === 'create' ? m('p.text-xs.text-gray-600.dark:text-slate-300',
|
|
442
|
+
'Kayıt başarıyla oluşturuldu ve veritabanına eklendi.'
|
|
443
|
+
) : r.action === 'delete' ? m('p.text-xs.text-rose-600.dark:text-rose-400',
|
|
444
|
+
'Kayıt veritabanından silindi (soft delete/hard delete).'
|
|
445
|
+
) : r.action === 'restore' ? m('p.text-xs.text-amber-600.dark:text-amber-400',
|
|
446
|
+
'Silinmiş kayıt başarıyla geri yüklendi.'
|
|
447
|
+
) : null,
|
|
448
|
+
|
|
449
|
+
// Details Toggle Accordion
|
|
450
|
+
m('div.pt-2.border-t.border-gray-100.dark:border-slate-750', [
|
|
451
|
+
m('button.text-xs.text-indigo-600.dark:text-indigo-400.hover:underline.flex.items-center.gap-1', {
|
|
452
|
+
onclick: function() { toggleExpand(r.id); }
|
|
453
|
+
}, [
|
|
454
|
+
m('span', isExpanded ? '▲ Teknik Detayları Gizle' : '▼ Teknik Detayları Göster'),
|
|
455
|
+
]),
|
|
456
|
+
|
|
457
|
+
isExpanded ? m('div.mt-3.p-3.rounded-lg.bg-gray-50.dark:bg-slate-900.border.border-gray-200.dark:border-slate-700.text-xs.space-y-2', [
|
|
458
|
+
m('div.grid.grid-cols-1.md:grid-cols-2.gap-2', [
|
|
459
|
+
m('div', [
|
|
460
|
+
m('span.font-semibold.text-gray-600.dark:text-slate-400', 'Yol: '),
|
|
461
|
+
m('span.font-mono.text-gray-800.dark:text-slate-200', (r.http_method || '') + ' ' + (r.path || '—')),
|
|
462
|
+
]),
|
|
463
|
+
m('div', [
|
|
464
|
+
m('span.font-semibold.text-gray-600.dark:text-slate-400', 'Tarayıcı / Agent: '),
|
|
465
|
+
m('span.truncate.text-gray-800.dark:text-slate-200.inline-block.max-w-xs', { title: r.user_agent || '' }, r.user_agent || '—'),
|
|
466
|
+
]),
|
|
467
|
+
]),
|
|
468
|
+
metadata ? m('div.pt-1', [
|
|
469
|
+
m('span.font-semibold.text-gray-600.dark:text-slate-400.block.mb-1', 'Metadata:'),
|
|
470
|
+
m('pre.p-2.rounded.bg-gray-900.text-emerald-400.font-mono.text-[11px].overflow-x-auto',
|
|
471
|
+
JSON.stringify(metadata, null, 2)
|
|
472
|
+
),
|
|
473
|
+
]) : null,
|
|
474
|
+
]) : null,
|
|
475
|
+
]),
|
|
476
|
+
]),
|
|
114
477
|
]);
|
|
115
478
|
})),
|
|
479
|
+
])
|
|
480
|
+
) : (
|
|
481
|
+
// ==================== TABLE VIEW ====================
|
|
482
|
+
m('div.overflow-x-auto.border.border-gray-200.dark:border-slate-700.rounded-xl.bg-white.dark:bg-slate-800.shadow-sm', [
|
|
483
|
+
m('table.min-w-full.text-sm', [
|
|
484
|
+
m('thead.bg-gray-50.dark:bg-slate-900.border-b.border-gray-200.dark:border-slate-700', [
|
|
485
|
+
m('tr', [
|
|
486
|
+
m('th.text-left.p-3.font-semibold.text-gray-700.dark:text-slate-300', 'Zaman'),
|
|
487
|
+
m('th.text-left.p-3.font-semibold.text-gray-700.dark:text-slate-300', 'Kullanıcı'),
|
|
488
|
+
m('th.text-left.p-3.font-semibold.text-gray-700.dark:text-slate-300', 'İşlem'),
|
|
489
|
+
m('th.text-left.p-3.font-semibold.text-gray-700.dark:text-slate-300', 'Model'),
|
|
490
|
+
m('th.text-left.p-3.font-semibold.text-gray-700.dark:text-slate-300', 'Kayıt ID'),
|
|
491
|
+
m('th.text-left.p-3.font-semibold.text-gray-700.dark:text-slate-300', 'Yol'),
|
|
492
|
+
m('th.text-right.p-3.font-semibold.text-gray-700.dark:text-slate-300', 'Zaman Tüneli'),
|
|
493
|
+
]),
|
|
494
|
+
]),
|
|
495
|
+
m('tbody.divide-y.divide-gray-100.dark:divide-slate-700', rows.map(function(r) {
|
|
496
|
+
var theme = getActionTheme(r.action);
|
|
497
|
+
return m('tr.hover:bg-gray-50.dark:hover:bg-slate-750.transition-colors', [
|
|
498
|
+
m('td.p-3.whitespace-nowrap.text-gray-600.dark:text-slate-300', [
|
|
499
|
+
m('span.block.font-medium.text-gray-900.dark:text-slate-100', formatRelativeTime(r.created_at)),
|
|
500
|
+
m('span.text-xs.text-gray-400', r.created_at || ''),
|
|
501
|
+
]),
|
|
502
|
+
m('td.p-3.text-gray-800.dark:text-slate-200', [
|
|
503
|
+
m('span.block.font-medium', r.actor_email || 'Sistem'),
|
|
504
|
+
r.actor_id != null ? m('span.text-xs.text-gray-400', '#' + r.actor_id) : null,
|
|
505
|
+
]),
|
|
506
|
+
m('td.p-3', [
|
|
507
|
+
m('span.px-2.py-0.5.text-xs.font-semibold.rounded-full.border', {
|
|
508
|
+
class: theme.badgeClass,
|
|
509
|
+
}, r.action),
|
|
510
|
+
]),
|
|
511
|
+
m('td.p-3.font-medium.text-gray-900.dark:text-slate-100', r.resource_model),
|
|
512
|
+
m('td.p-3.text-gray-600.dark:text-slate-300', r.resource_id != null ? '#' + r.resource_id : '—'),
|
|
513
|
+
m('td.p-3.max-w-xs.truncate.text-xs.font-mono.text-gray-500.dark:text-slate-400', { title: r.path || '' }, r.path || ''),
|
|
514
|
+
m('td.p-3.text-right', [
|
|
515
|
+
m('button.px-2.5.py-1.text-xs.font-medium.text-indigo-600.dark:text-indigo-400.hover:bg-indigo-50.dark:hover:bg-indigo-950/40.rounded-lg.transition-colors', {
|
|
516
|
+
onclick: function() { focusRecord(r.resource_model, r.resource_id); },
|
|
517
|
+
}, 'Tünelde Gör →'),
|
|
518
|
+
]),
|
|
519
|
+
]);
|
|
520
|
+
})),
|
|
521
|
+
]),
|
|
522
|
+
])
|
|
523
|
+
),
|
|
524
|
+
|
|
525
|
+
// 5. Pagination Bar
|
|
526
|
+
m('div.flex.flex-col.sm:flex-row.items-center.justify-between.gap-3.pt-2', [
|
|
527
|
+
m('div.text-xs.text-gray-500.dark:text-slate-400', [
|
|
528
|
+
m('strong.font-semibold.text-gray-800.dark:text-slate-200', total),
|
|
529
|
+
m('span', ' records listed'),
|
|
530
|
+
]),
|
|
531
|
+
|
|
532
|
+
m('div.flex.items-center.gap-2', [
|
|
533
|
+
m('button.px-3.py-1.5.text-xs.font-medium.border.border-gray-300.dark:border-slate-700.rounded-lg.bg-white.dark:bg-slate-800.text-gray-700.dark:text-slate-200.hover:bg-gray-50.dark:hover:bg-slate-750.disabled:opacity-40.disabled:cursor-not-allowed.transition-colors', {
|
|
534
|
+
disabled: page <= 1,
|
|
535
|
+
onclick: function() { if (page > 1) { page--; load(); } },
|
|
536
|
+
}, 'Prev'),
|
|
537
|
+
m('span.text-xs.font-medium.text-gray-700.dark:text-slate-300.px-2',
|
|
538
|
+
'Page ' + page + ' / ' + maxPage
|
|
539
|
+
),
|
|
540
|
+
m('button.px-3.py-1.5.text-xs.font-medium.border.border-gray-300.dark:border-slate-700.rounded-lg.bg-white.dark:bg-slate-800.text-gray-700.dark:text-slate-200.hover:bg-gray-50.dark:hover:bg-slate-750.disabled:opacity-40.disabled:cursor-not-allowed.transition-colors', {
|
|
541
|
+
disabled: page >= maxPage,
|
|
542
|
+
onclick: function() { if (page < maxPage) { page++; load(); } },
|
|
543
|
+
}, 'Next'),
|
|
116
544
|
]),
|
|
117
|
-
]),
|
|
118
|
-
m('div.flex.items-center.gap-2', [
|
|
119
|
-
m('button.px-3.py-1.border.rounded', {
|
|
120
|
-
disabled: page <= 1,
|
|
121
|
-
onclick: function() { if (page > 1) { page--; load(); } },
|
|
122
|
-
}, 'Prev'),
|
|
123
|
-
m('span.text-sm', 'Page ' + page + ' / ' + maxPage),
|
|
124
|
-
m('button.px-3.py-1.border.rounded', {
|
|
125
|
-
disabled: page >= maxPage,
|
|
126
|
-
onclick: function() { if (page < maxPage) { page++; load(); } },
|
|
127
|
-
}, 'Next'),
|
|
128
545
|
]),
|
|
129
546
|
]);
|
|
130
547
|
},
|