drf-to-mkdoc 0.2.3__py3-none-any.whl → 0.3.0__py3-none-any.whl

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.

Potentially problematic release.


This version of drf-to-mkdoc might be problematic. Click here for more details.

Files changed (40) hide show
  1. drf_to_mkdoc/conf/defaults.py +1 -0
  2. drf_to_mkdoc/conf/settings.py +1 -0
  3. drf_to_mkdoc/management/commands/build_model_docs.py +10 -1
  4. drf_to_mkdoc/static/drf-to-mkdoc/javascripts/field-sections-loader.js +29 -0
  5. drf_to_mkdoc/static/drf-to-mkdoc/javascripts/query-parameters-loader.js +16 -0
  6. drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/field-extractor.js +200 -0
  7. drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/form-manager.js +307 -14
  8. drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/main.js +39 -11
  9. drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/modal.js +298 -18
  10. drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/query-parameters-extractor.js +94 -0
  11. drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/request-executor.js +278 -62
  12. drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/response-modal.js +173 -0
  13. drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/suggestions.js +59 -152
  14. drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/tabs.js +52 -9
  15. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/badges.css +13 -5
  16. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/theme-toggle.css +297 -25
  17. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/try-out/fab.css +204 -0
  18. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/try-out/response.css +323 -0
  19. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/try-out/variables.css +139 -0
  20. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/field-sections.css +136 -0
  21. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/form.css +539 -0
  22. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/modal.css +239 -17
  23. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/response.css +503 -43
  24. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/tabs.css +71 -19
  25. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/variables.css +71 -15
  26. drf_to_mkdoc/templates/endpoints/detail/request_body.html +2 -0
  27. drf_to_mkdoc/templates/er_diagrams/app.html +26 -0
  28. drf_to_mkdoc/templates/er_diagrams/index.html +14 -0
  29. drf_to_mkdoc/templates/er_diagrams/main.html +22 -0
  30. drf_to_mkdoc/templates/try-out/fab.html +67 -3
  31. drf_to_mkdoc/templates/try-out/form.html +221 -74
  32. drf_to_mkdoc/templates/try-out/modal.html +75 -7
  33. drf_to_mkdoc/templates/try-out/response-modal.html +138 -9
  34. drf_to_mkdoc/utils/endpoint_detail_generator.py +1 -0
  35. drf_to_mkdoc/utils/er_diagram_generator.py +230 -0
  36. {drf_to_mkdoc-0.2.3.dist-info → drf_to_mkdoc-0.3.0.dist-info}/METADATA +89 -10
  37. {drf_to_mkdoc-0.2.3.dist-info → drf_to_mkdoc-0.3.0.dist-info}/RECORD +40 -27
  38. {drf_to_mkdoc-0.2.3.dist-info → drf_to_mkdoc-0.3.0.dist-info}/WHEEL +0 -0
  39. {drf_to_mkdoc-0.2.3.dist-info → drf_to_mkdoc-0.3.0.dist-info}/licenses/LICENSE +0 -0
  40. {drf_to_mkdoc-0.2.3.dist-info → drf_to_mkdoc-0.3.0.dist-info}/top_level.txt +0 -0
@@ -2,22 +2,30 @@
2
2
  const TryOutSuggestions = {
3
3
  init: function() {
4
4
  this.suggestions = this.getAvailableSuggestions();
5
- this.setupAutocomplete();
5
+ this.updateDatalist();
6
+
7
+ // Re-initialize when window.queryParametersData changes
8
+ if (window.MutationObserver) {
9
+ this.setupDataObserver();
10
+ }
6
11
  },
7
-
8
- setupAutocomplete: function() {
9
- // Setup event listeners for all query parameter inputs
10
- document.addEventListener('click', (e) => {
11
- // Hide all suggestion dropdowns when clicking outside
12
- if (!e.target.matches('#queryParams input')) {
13
- this.hideAllSuggestions();
12
+
13
+ setupDataObserver: function() {
14
+ // Check for changes in queryParametersData every second
15
+ setInterval(() => {
16
+ if (window.queryParametersData && window.queryParametersData._lastUpdate !== this._lastDataUpdate) {
17
+ this._lastDataUpdate = window.queryParametersData._lastUpdate;
18
+ this.suggestions = this.getAvailableSuggestions();
19
+ this.updateDatalist();
14
20
  }
15
- });
21
+ }, 1000);
22
+ },
16
23
 
17
- // Initial setup for existing inputs
24
+ setupAutocomplete: function() {
25
+ // Using native datalist, just make sure all inputs are properly initialized
18
26
  this.setupExistingInputs();
19
-
20
- // Setup for the add button to attach listeners to new inputs
27
+
28
+ // Setup for the add button to mark new inputs as initialized
21
29
  const addBtn = document.querySelector('.add-btn');
22
30
  if (addBtn) {
23
31
  addBtn.addEventListener('click', () => {
@@ -28,10 +36,27 @@ const TryOutSuggestions = {
28
36
  });
29
37
  }
30
38
  },
39
+
40
+ updateDatalist: function() {
41
+ // Update the datalist with our suggestions
42
+ const datalist = document.getElementById('paramSuggestions');
43
+ if (datalist && this.suggestions.length > 0) {
44
+ // Clear existing options
45
+ datalist.innerHTML = '';
46
+
47
+ // Add new options from our suggestions - without descriptions
48
+ this.suggestions.forEach(suggestion => {
49
+ const option = document.createElement('option');
50
+ option.value = suggestion.name;
51
+ // No description text as per requirement
52
+ datalist.appendChild(option);
53
+ });
54
+ }
55
+ },
31
56
 
32
57
  setupExistingInputs: function() {
33
58
  // Find all parameter name inputs
34
- const paramInputs = document.querySelectorAll('#queryParams .kv-item input:first-child');
59
+ const paramInputs = document.querySelectorAll('#queryParams .name-input');
35
60
  paramInputs.forEach(input => {
36
61
  // Skip if already initialized
37
62
  if (input.dataset.autocompleteInitialized) return;
@@ -39,177 +64,59 @@ const TryOutSuggestions = {
39
64
  // Mark as initialized
40
65
  input.dataset.autocompleteInitialized = 'true';
41
66
 
42
- // Create suggestions container for this input
43
- const suggestionsContainer = document.createElement('div');
44
- suggestionsContainer.className = 'param-suggestions';
45
- suggestionsContainer.id = 'suggestions-' + Math.random().toString(36).substr(2, 9);
46
- input.parentNode.style.position = 'relative';
47
- input.parentNode.appendChild(suggestionsContainer);
48
-
49
- // Store reference to container
50
- input.dataset.suggestionsContainer = suggestionsContainer.id;
51
-
52
- // Add event listeners
53
- input.addEventListener('focus', () => this.showSuggestions(input));
54
- input.addEventListener('input', () => this.filterSuggestions(input));
55
- input.addEventListener('keydown', (e) => this.handleKeyNavigation(e, input));
67
+ // We're using the native datalist for autocomplete
68
+ // No need for custom suggestions dropdown
56
69
  });
57
70
  },
58
71
 
59
72
  getAvailableSuggestions: function() {
73
+ // Get query parameters only from window.queryParametersData
60
74
  const suggestions = [];
61
75
 
62
- // Try to get query parameters from the page context
63
76
  if (window.queryParametersData) {
64
77
  const data = window.queryParametersData;
65
78
 
66
79
  // Add filter fields
67
80
  if (data.filter_fields && data.filter_fields.length > 0) {
68
- suggestions.push(...data.filter_fields);
81
+ suggestions.push(...data.filter_fields.map(field => ({
82
+ name: field
83
+ })));
69
84
  }
70
85
 
71
- // Add search if available
72
- if (data.search_fields && data.search_fields.length > 0) {
73
- suggestions.push('search');
74
- }
86
+ // Add search fields - only add the 'search' key, not individual fields
87
+ // The 'search' key will be added via special_keys
88
+
89
+ // Add ordering fields - only add the 'ordering' key, not individual fields
90
+ // The 'ordering' key will be added via special_keys
75
91
 
76
- // Add ordering if available
77
- if (data.ordering_fields && data.ordering_fields.length > 0) {
78
- suggestions.push('ordering');
92
+ // Add special keys
93
+ if (data.special_keys && data.special_keys.length > 0) {
94
+ suggestions.push(...data.special_keys.map(key => ({
95
+ name: key
96
+ })));
79
97
  }
80
98
 
81
- // Add pagination
99
+ // Add pagination fields
82
100
  if (data.pagination_fields && data.pagination_fields.length > 0) {
83
- suggestions.push(...data.pagination_fields);
101
+ suggestions.push(...data.pagination_fields.map(field => ({
102
+ name: field
103
+ })));
84
104
  }
85
105
  }
86
106
 
87
- // Default common parameters
88
- if (suggestions.length === 0) {
89
- suggestions.push('search', 'ordering', 'page', 'page_size');
90
- }
91
-
92
- // Remove duplicates and return
93
- return [...new Set(suggestions)];
94
- },
95
-
96
- showSuggestions: function(input) {
97
- const container = document.getElementById(input.dataset.suggestionsContainer);
98
- if (!container) return;
99
-
100
- // Clear existing suggestions
101
- container.innerHTML = '';
102
-
103
- // Filter suggestions based on input value
104
- const inputValue = input.value.toLowerCase();
105
- const filteredSuggestions = this.suggestions.filter(suggestion =>
106
- suggestion.toLowerCase().includes(inputValue)
107
- );
108
-
109
- if (filteredSuggestions.length === 0) {
110
- container.classList.remove('show');
111
- return;
112
- }
113
-
114
- // Add suggestions to container
115
- filteredSuggestions.forEach(suggestion => {
116
- const suggestionElement = document.createElement('div');
117
- suggestionElement.className = 'param-suggestion';
118
- suggestionElement.textContent = suggestion;
119
- suggestionElement.addEventListener('click', (e) => {
120
- e.stopPropagation();
121
- this.selectSuggestion(input, suggestion);
122
- });
123
- container.appendChild(suggestionElement);
124
- });
125
-
126
- // Show suggestions
127
- container.classList.add('show');
128
- },
129
-
130
- filterSuggestions: function(input) {
131
- // Just re-show suggestions with current filter
132
- this.showSuggestions(input);
133
- },
134
-
135
- hideAllSuggestions: function() {
136
- document.querySelectorAll('.param-suggestions').forEach(container => {
137
- container.classList.remove('show');
138
- });
107
+ return suggestions;
139
108
  },
140
109
 
141
110
  selectSuggestion: function(input, suggestion) {
142
111
  // Set input value
143
112
  input.value = suggestion;
144
113
 
145
- // Hide suggestions
146
- const container = document.getElementById(input.dataset.suggestionsContainer);
147
- if (container) {
148
- container.classList.remove('show');
149
- }
150
-
151
114
  // Focus on value input
152
115
  const valueInput = input.nextElementSibling;
153
116
  if (valueInput) {
154
117
  valueInput.focus();
155
118
  }
156
119
  },
157
-
158
- handleKeyNavigation: function(event, input) {
159
- const container = document.getElementById(input.dataset.suggestionsContainer);
160
- if (!container || !container.classList.contains('show')) return;
161
-
162
- const suggestions = container.querySelectorAll('.param-suggestion');
163
- if (suggestions.length === 0) return;
164
-
165
- // Find currently selected suggestion
166
- const selectedIndex = Array.from(suggestions).findIndex(el => el.classList.contains('selected'));
167
-
168
- switch (event.key) {
169
- case 'ArrowDown':
170
- event.preventDefault();
171
- this.navigateSuggestion(suggestions, selectedIndex, 1);
172
- break;
173
-
174
- case 'ArrowUp':
175
- event.preventDefault();
176
- this.navigateSuggestion(suggestions, selectedIndex, -1);
177
- break;
178
-
179
- case 'Enter':
180
- event.preventDefault();
181
- if (selectedIndex >= 0) {
182
- this.selectSuggestion(input, suggestions[selectedIndex].textContent);
183
- } else if (suggestions.length > 0) {
184
- this.selectSuggestion(input, suggestions[0].textContent);
185
- }
186
- break;
187
-
188
- case 'Escape':
189
- event.preventDefault();
190
- container.classList.remove('show');
191
- break;
192
- }
193
- },
194
-
195
- navigateSuggestion: function(suggestions, currentIndex, direction) {
196
- // Remove current selection
197
- if (currentIndex >= 0) {
198
- suggestions[currentIndex].classList.remove('selected');
199
- }
200
-
201
- // Calculate new index
202
- let newIndex;
203
- if (currentIndex < 0) {
204
- newIndex = direction > 0 ? 0 : suggestions.length - 1;
205
- } else {
206
- newIndex = (currentIndex + direction + suggestions.length) % suggestions.length;
207
- }
208
-
209
- // Select new suggestion
210
- suggestions[newIndex].classList.add('selected');
211
- suggestions[newIndex].scrollIntoView({ block: 'nearest' });
212
- }
213
120
  };
214
121
 
215
122
  // Export for global access
@@ -1,33 +1,76 @@
1
1
  // Tab management functionality
2
2
  const TabManager = {
3
3
  init: function() {
4
- document.querySelectorAll('.try-out-form .tab').forEach(tab => {
4
+ document.querySelectorAll('.try-out-form .tab, .smart-tabs .tab, .response-tabs .tab').forEach(tab => {
5
5
  tab.addEventListener('click', () => {
6
6
  this.switchTab(tab);
7
7
  });
8
+
9
+ // Add keyboard support
10
+ tab.addEventListener('keydown', (e) => {
11
+ if (e.key === 'Enter' || e.key === ' ') {
12
+ e.preventDefault();
13
+ this.switchTab(tab);
14
+ }
15
+ });
8
16
  });
9
17
  },
10
18
 
11
19
  switchTab: function(activeTab) {
12
- // Remove active class from all tabs and contents
13
- document.querySelectorAll('.try-out-form .tab').forEach(t => t.classList.remove('active'));
14
- document.querySelectorAll('.try-out-form .tab-content').forEach(c => c.classList.remove('active'));
20
+ const tabContainer = activeTab.closest('.smart-tabs, .response-tabs, .try-out-form');
21
+ if (!tabContainer) return;
22
+
23
+ // Remove active class from all tabs in this container
24
+ tabContainer.querySelectorAll('.tab').forEach(t => {
25
+ t.classList.remove('active');
26
+ t.setAttribute('aria-selected', 'false');
27
+ });
15
28
 
16
- // Add active class to clicked tab
29
+ // Remove active class from all tab content
30
+ const contentContainer = tabContainer.parentElement || document;
31
+ contentContainer.querySelectorAll('.tab-content').forEach(c => {
32
+ c.classList.remove('active');
33
+ });
34
+
35
+ // Add active class to clicked tab and its content
17
36
  activeTab.classList.add('active');
37
+ activeTab.setAttribute('aria-selected', 'true');
18
38
 
19
39
  // Show corresponding content
20
- const tabName = activeTab.getAttribute('data-tab');
21
- const content = document.getElementById(tabName + 'Tab');
22
- if (content) {
23
- content.classList.add('active');
40
+ const contentId = activeTab.getAttribute('aria-controls') || activeTab.getAttribute('data-tab');
41
+ let content;
42
+
43
+ if (contentId) {
44
+ content = document.getElementById(contentId) || document.getElementById(contentId + 'Tab');
45
+ if (content) {
46
+ content.classList.add('active');
47
+ }
24
48
  }
49
+
50
+ // Debug logging
51
+ console.log('Tab switched to:', contentId, 'Content element:', content);
25
52
  }
26
53
  };
27
54
 
28
55
  // Initialize tabs when DOM is ready
29
56
  document.addEventListener('DOMContentLoaded', function() {
30
57
  TabManager.init();
58
+
59
+ // Also initialize when modal is shown (for dynamic content)
60
+ const modal = document.getElementById('tryOutModal');
61
+ if (modal) {
62
+ const observer = new MutationObserver(function(mutations) {
63
+ mutations.forEach(function(mutation) {
64
+ if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
65
+ if (modal.classList.contains('show')) {
66
+ // Re-initialize tabs when modal is shown
67
+ setTimeout(() => TabManager.init(), 100);
68
+ }
69
+ }
70
+ });
71
+ });
72
+ observer.observe(modal, { attributes: true });
73
+ }
31
74
  });
32
75
 
33
76
  // Export for global access
@@ -1,16 +1,22 @@
1
1
  /* ===== METHOD BADGES ===== */
2
2
  .method-badge {
3
3
  position: relative;
4
- padding: 6px 12px;
4
+ display: inline-block;
5
+ padding: 4px 8px;
5
6
  font-size: 12px;
6
7
  font-weight: bold;
7
- border-radius: 20px;
8
+ border-radius: 16px;
8
9
  color: white;
9
10
  text-transform: uppercase;
10
11
  overflow: hidden;
11
- min-width: 60px;
12
+ min-width: 50px;
12
13
  text-align: center;
13
14
  flex-shrink: 0;
15
+ z-index: 0;
16
+ vertical-align: middle;
17
+ line-height: 1.2;
18
+ box-sizing: border-box;
19
+ white-space: nowrap;
14
20
  }
15
21
 
16
22
  .method-badge::before {
@@ -20,8 +26,10 @@
20
26
  left: -100%;
21
27
  width: 100%;
22
28
  height: 100%;
23
- background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent);
24
- transition: left 0.5s ease;
29
+ background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent);
30
+ transition: left 0.6s ease;
31
+ z-index: 1;
32
+ pointer-events: none;
25
33
  }
26
34
 
27
35
  .method-badge:hover::before {