v1.3.49: edit modal — remove mode toggle, show archive name, timeout-only save; add PUT /functions/:name/timeout
This commit is contained in:
@@ -52,7 +52,7 @@ spec:
|
|||||||
serviceAccountName: fission-console
|
serviceAccountName: fission-console
|
||||||
containers:
|
containers:
|
||||||
- name: console
|
- name: console
|
||||||
image: naeel/fission-console:v1.3.48
|
image: naeel/fission-console:v1.3.49
|
||||||
imagePullPolicy: Always
|
imagePullPolicy: Always
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 8090
|
- containerPort: 8090
|
||||||
|
|||||||
@@ -310,6 +310,12 @@ func (s *Server) handleFunctionsAction(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// /functions/:name/timeout — обновление только таймаута (без замены архива/кода)
|
||||||
|
if len(parts) == 2 && parts[1] == "timeout" && r.Method == http.MethodPut {
|
||||||
|
s.handleUpdateFunctionTimeout(w, r, name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// /functions/:name/archive — обновление через zip-архив
|
// /functions/:name/archive — обновление через zip-архив
|
||||||
if len(parts) == 2 && parts[1] == "archive" && r.Method == http.MethodPut {
|
if len(parts) == 2 && parts[1] == "archive" && r.Method == http.MethodPut {
|
||||||
s.handleUpdateFunctionArchive(w, r, name)
|
s.handleUpdateFunctionArchive(w, r, name)
|
||||||
@@ -760,6 +766,45 @@ func (s *Server) handleUpdateFunctionCode(w http.ResponseWriter, r *http.Request
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handleUpdateFunctionTimeout обновляет только spec.functionTimeout функции (без замены кода/архива).
|
||||||
|
func (s *Server) handleUpdateFunctionTimeout(w http.ResponseWriter, r *http.Request, name string) {
|
||||||
|
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
ns := s.userNS(r)
|
||||||
|
|
||||||
|
var req struct {
|
||||||
|
Timeout int64 `json:"timeout"`
|
||||||
|
}
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||||
|
writeJSONError(w, http.StatusBadRequest, fmt.Sprintf("decode request: %v", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
timeout := normalizeFunctionTimeout(req.Timeout)
|
||||||
|
|
||||||
|
fn, err := s.dyn.Resource(fission.FunctionGVR).Namespace(ns).Get(ctx, name, metav1.GetOptions{})
|
||||||
|
if err != nil {
|
||||||
|
writeJSONError(w, http.StatusBadGateway, fmt.Sprintf("get function %q: %v", name, err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := unstructured.SetNestedField(fn.Object, timeout, "spec", "functionTimeout"); err != nil {
|
||||||
|
writeJSONError(w, http.StatusInternalServerError, fmt.Sprintf("set timeout: %v", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
now := time.Now().UTC().Format(time.RFC3339)
|
||||||
|
ann := fn.GetAnnotations()
|
||||||
|
if ann == nil {
|
||||||
|
ann = map[string]string{}
|
||||||
|
}
|
||||||
|
ann[functionUpdatedAtAnnotation] = now
|
||||||
|
fn.SetAnnotations(ann)
|
||||||
|
|
||||||
|
if _, err := s.dyn.Resource(fission.FunctionGVR).Namespace(ns).Update(ctx, fn, metav1.UpdateOptions{}); err != nil {
|
||||||
|
writeJSONError(w, http.StatusBadGateway, fmt.Sprintf("update function %q: %v", name, err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
writeAnyJSON(w, http.StatusOK, map[string]any{"updated": true, "timeout": timeout})
|
||||||
|
}
|
||||||
|
|
||||||
// handleInvokeFunction вызывает функцию через Fission router.
|
// handleInvokeFunction вызывает функцию через Fission router.
|
||||||
// Определяет реальный URL из HTTPTrigger, выбирает метод (POST/GET).
|
// Определяет реальный URL из HTTPTrigger, выбирает метод (POST/GET).
|
||||||
func (s *Server) handleInvokeFunction(w http.ResponseWriter, r *http.Request, name string) {
|
func (s *Server) handleInvokeFunction(w http.ResponseWriter, r *http.Request, name string) {
|
||||||
|
|||||||
@@ -102,7 +102,7 @@
|
|||||||
<div class="nubes">NUBES</div>
|
<div class="nubes">NUBES</div>
|
||||||
<div class="product">FISSION CONSOLE</div>
|
<div class="product">FISSION CONSOLE</div>
|
||||||
</div>
|
</div>
|
||||||
<div style="font-size:0.65rem; color:var(--text-secondary); margin-left:10px; align-self:center; opacity:0.7;">v1.3.48</div>
|
<div style="font-size:0.65rem; color:var(--text-secondary); margin-left:10px; align-self:center; opacity:0.7;">v1.3.49</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row" style="margin:0;">
|
<div class="row" style="margin:0;">
|
||||||
<button class="btn ghost" onclick="reloadAll()">Refresh</button>
|
<button class="btn ghost" onclick="reloadAll()">Refresh</button>
|
||||||
@@ -352,10 +352,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div style="display:flex; gap:4px; margin-bottom:6px;">
|
|
||||||
<button class="btn ghost" id="e-mode-code" onclick="setCodeMode('e','code')" style="font-size:.8rem; padding:3px 10px;">✏️ Код</button>
|
|
||||||
<button class="btn ghost" id="e-mode-archive" onclick="setCodeMode('e','archive')" style="font-size:.8rem; padding:3px 10px;">📦 Архив (.zip)</button>
|
|
||||||
</div>
|
|
||||||
<div id="e-code-area">
|
<div id="e-code-area">
|
||||||
<label>Код</label>
|
<label>Код</label>
|
||||||
<textarea id="e-code"></textarea>
|
<textarea id="e-code"></textarea>
|
||||||
@@ -367,6 +363,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="e-archive-area" style="display:none;">
|
<div id="e-archive-area" style="display:none;">
|
||||||
|
<div id="e-archive-current" style="margin-bottom:10px; padding:8px 12px; background:var(--bg-alt); border-radius:6px; font-size:13px; color:var(--text-secondary);">
|
||||||
|
📦 <span id="e-archive-name"></span>
|
||||||
|
</div>
|
||||||
|
<label style="font-size:12px; color:var(--text-secondary); margin-bottom:4px; display:block;">Заменить архив (необязательно)</label>
|
||||||
<input type="file" id="e-archive-file" accept=".zip" style="display:block; margin-bottom:8px; color:var(--text-primary);">
|
<input type="file" id="e-archive-file" accept=".zip" style="display:block; margin-bottom:8px; color:var(--text-primary);">
|
||||||
<div style="display:flex; gap:6px; flex-wrap:wrap;">
|
<div style="display:flex; gap:6px; flex-wrap:wrap;">
|
||||||
<button id="e-lint-btn" class="btn ghost" onclick="lintArchiveFile('e')">🔍 Проверка архива линтером</button>
|
<button id="e-lint-btn" class="btn ghost" onclick="lintArchiveFile('e')">🔍 Проверка архива линтером</button>
|
||||||
@@ -462,7 +462,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="actions" style="justify-content:space-between; align-items:center;">
|
<div class="actions" style="justify-content:space-between; align-items:center;">
|
||||||
<span style="font-size:0.75rem; color:var(--text-secondary);">v1.3.48</span>
|
<span style="font-size:0.75rem; color:var(--text-secondary);">v1.3.49</span>
|
||||||
<button class="btn ghost" onclick="closeHelp()">Закрыть</button>
|
<button class="btn ghost" onclick="closeHelp()">Закрыть</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -149,6 +149,10 @@ async function openEdit(name) {
|
|||||||
// Сбрасываем режим: source_type из API (code / archive)
|
// Сбрасываем режим: source_type из API (code / archive)
|
||||||
if (fn.source_type === 'archive') {
|
if (fn.source_type === 'archive') {
|
||||||
setCodeMode('e', 'archive');
|
setCodeMode('e', 'archive');
|
||||||
|
var archiveNameEl = document.getElementById('e-archive-name');
|
||||||
|
if (archiveNameEl) archiveNameEl.textContent = fn.package || 'архив';
|
||||||
|
var archiveFile = document.getElementById('e-archive-file');
|
||||||
|
if (archiveFile) archiveFile.value = '';
|
||||||
} else {
|
} else {
|
||||||
setCodeMode('e', 'code');
|
setCodeMode('e', 'code');
|
||||||
}
|
}
|
||||||
@@ -205,6 +209,11 @@ async function submitEdit() {
|
|||||||
var resp = await fetch(API_BASE + '/functions/' + encodeURIComponent(name) + '/archive',
|
var resp = await fetch(API_BASE + '/functions/' + encodeURIComponent(name) + '/archive',
|
||||||
{ method: 'PUT', headers: authHeaders(), body: fd });
|
{ method: 'PUT', headers: authHeaders(), body: fd });
|
||||||
if (!resp.ok) { var e = await resp.json().catch(() => ({})); throw new Error(e.error || resp.statusText); }
|
if (!resp.ok) { var e = await resp.json().catch(() => ({})); throw new Error(e.error || resp.statusText); }
|
||||||
|
} else if (isArchiveMode) {
|
||||||
|
// Архив не заменяется — обновляем только timeout
|
||||||
|
await requestJSON(API_BASE + '/functions/' + encodeURIComponent(name) + '/timeout', 'PUT', {
|
||||||
|
timeout: parseTimeout(document.getElementById('e-timeout').value)
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
await requestJSON(API_BASE + '/functions/' + encodeURIComponent(name) + '/code', 'PUT', {
|
await requestJSON(API_BASE + '/functions/' + encodeURIComponent(name) + '/code', 'PUT', {
|
||||||
code: document.getElementById('e-code').value,
|
code: document.getElementById('e-code').value,
|
||||||
|
|||||||
Reference in New Issue
Block a user