mirror of https://github.com/portainer/portainer
feat(motd): add the ability to use custom style (#2918)
* feat(motd): rework motd display mechanism for more flexibility on motd content * feat(api): enhance MOTD * refactor(api): refactor MOTD related codebase * feat(motd): hash on messagepull/2926/head
parent
1d9166216a
commit
50f547a6e7
|
@ -1,7 +1,9 @@
|
|||
package motd
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/portainer/libhttp/response"
|
||||
"github.com/portainer/portainer/api"
|
||||
|
@ -10,25 +12,44 @@ import (
|
|||
)
|
||||
|
||||
type motdResponse struct {
|
||||
Title string `json:"Title"`
|
||||
Message string `json:"Message"`
|
||||
Hash []byte `json:"Hash"`
|
||||
Title string `json:"Title"`
|
||||
Message string `json:"Message"`
|
||||
ContentLayout map[string]string `json:"ContentLayout"`
|
||||
Style string `json:"Style"`
|
||||
Hash []byte `json:"Hash"`
|
||||
}
|
||||
|
||||
type motdData struct {
|
||||
Title string `json:"title"`
|
||||
Message []string `json:"message"`
|
||||
ContentLayout map[string]string `json:"contentLayout"`
|
||||
Style string `json:"style"`
|
||||
}
|
||||
|
||||
func (handler *Handler) motd(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
motd, err := client.Get(portainer.MessageOfTheDayURL, 0)
|
||||
if err != nil {
|
||||
response.JSON(w, &motdResponse{Message: ""})
|
||||
return
|
||||
}
|
||||
|
||||
title, err := client.Get(portainer.MessageOfTheDayTitleURL, 0)
|
||||
var data motdData
|
||||
err = json.Unmarshal(motd, &data)
|
||||
if err != nil {
|
||||
response.JSON(w, &motdResponse{Message: ""})
|
||||
return
|
||||
}
|
||||
|
||||
hash := crypto.HashFromBytes(motd)
|
||||
response.JSON(w, &motdResponse{Title: string(title), Message: string(motd), Hash: hash})
|
||||
message := strings.Join(data.Message, "\n")
|
||||
|
||||
hash := crypto.HashFromBytes([]byte(message))
|
||||
resp := motdResponse{
|
||||
Title: data.Title,
|
||||
Message: message,
|
||||
Hash: hash,
|
||||
ContentLayout: data.ContentLayout,
|
||||
Style: data.Style,
|
||||
}
|
||||
|
||||
response.JSON(w, &resp)
|
||||
}
|
||||
|
|
|
@ -860,9 +860,7 @@ const (
|
|||
// AssetsServerURL represents the URL of the Portainer asset server
|
||||
AssetsServerURL = "https://portainer-io-assets.sfo2.digitaloceanspaces.com"
|
||||
// MessageOfTheDayURL represents the URL where Portainer MOTD message can be retrieved
|
||||
MessageOfTheDayURL = AssetsServerURL + "/motd.html"
|
||||
// MessageOfTheDayTitleURL represents the URL where Portainer MOTD title can be retrieved
|
||||
MessageOfTheDayTitleURL = AssetsServerURL + "/motd-title.txt"
|
||||
MessageOfTheDayURL = AssetsServerURL + "/motd.json"
|
||||
// ExtensionDefinitionsURL represents the URL where Portainer extension definitions can be retrieved
|
||||
ExtensionDefinitionsURL = AssetsServerURL + "/extensions-1.20.3.json"
|
||||
// PortainerAgentHeader represents the name of the header available in any agent response
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
angular.module('portainer.app').component('motdPanel', {
|
||||
templateUrl: './motdPanel.html',
|
||||
bindings: {
|
||||
motd: '<',
|
||||
dismissAction: '&?'
|
||||
},
|
||||
transclude: true
|
||||
});
|
|
@ -0,0 +1,26 @@
|
|||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<rd-widget>
|
||||
<rd-widget-body classes="motd-body">
|
||||
<style ng-if="$ctrl.motd.Style">
|
||||
{{ $ctrl.motd.Style }}
|
||||
</style>
|
||||
<div ng-style="{{ $ctrl.motd.ContentLayout ? $ctrl.motd.ContentLayout : {} }}">
|
||||
<div class="col-sm-12 form-section-title">
|
||||
<span style="float: left;">
|
||||
{{ $ctrl.motd.Title }}
|
||||
</span>
|
||||
<span class="small" style="float: right;" ng-if="$ctrl.dismissAction">
|
||||
<a ng-click="$ctrl.dismissAction()"><i class="fa fa-times"></i> dismiss</a>
|
||||
</span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<span class="text-muted">
|
||||
<p ng-bind-html="$ctrl.motd.Message"></p>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</rd-widget-body>
|
||||
</rd-widget>
|
||||
</div>
|
||||
</div>
|
|
@ -2,4 +2,6 @@ export function MotdViewModel(data) {
|
|||
this.Title = data.Title;
|
||||
this.Message = data.Message;
|
||||
this.Hash = data.Hash;
|
||||
this.Style = data.Style;
|
||||
this.ContentLayout = data.ContentLayout;
|
||||
}
|
||||
|
|
|
@ -7,14 +7,11 @@
|
|||
<rd-header-content>Endpoints</rd-header-content>
|
||||
</rd-header>
|
||||
|
||||
<information-panel
|
||||
<motd-panel
|
||||
ng-if="motd && motd.Message !== '' && applicationState.UI.dismissedInfoHash !== motd.Hash"
|
||||
title-text="{{ motd.Title }}"
|
||||
motd="motd"
|
||||
dismiss-action="dismissImportantInformation(motd.Hash)">
|
||||
<span class="text-muted">
|
||||
<p ng-bind-html="motd.Message"></p>
|
||||
</span>
|
||||
</information-panel>
|
||||
</motd-panel>
|
||||
|
||||
<information-panel
|
||||
ng-if="!isAdmin && endpoints.length === 0"
|
||||
|
|
Loading…
Reference in New Issue