feat(policy): add policy to show/hide version number
Made-with: Cursor
This commit is contained in:
parent
f41fe2caba
commit
aa2bd95ccb
|
|
@ -210,6 +210,11 @@ export declare type EffectivePolicy = Message<"olivetin.api.v1.EffectivePolicy">
|
||||||
* @generated from field: bool show_log_list = 2;
|
* @generated from field: bool show_log_list = 2;
|
||||||
*/
|
*/
|
||||||
showLogList: boolean;
|
showLogList: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from field: bool show_version_number = 3;
|
||||||
|
*/
|
||||||
|
showVersionNumber: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1853,4 +1858,3 @@ export declare const OliveTinApiService: GenService<{
|
||||||
output: typeof EntitySchema;
|
output: typeof EntitySchema;
|
||||||
},
|
},
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -31,7 +31,7 @@
|
||||||
<footer title="footer" v-if="showFooter">
|
<footer title="footer" v-if="showFooter">
|
||||||
<p>
|
<p>
|
||||||
<img title="application icon" :src="logoUrl" alt="OliveTin logo" style="height: 1em;" class="logo" />
|
<img title="application icon" :src="logoUrl" alt="OliveTin logo" style="height: 1em;" class="logo" />
|
||||||
OliveTin {{ currentVersion }}
|
OliveTin <span v-if="showVersionNumber">{{ currentVersion }}</span>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<span>
|
<span>
|
||||||
|
|
@ -52,7 +52,7 @@
|
||||||
|
|
||||||
<span>{{ t('connected') }}</span>
|
<span>{{ t('connected') }}</span>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p v-if="showVersionNumber">
|
||||||
<a id="available-version" href="http://olivetin.app" target="_blank" hidden>?</a>
|
<a id="available-version" href="http://olivetin.app" target="_blank" hidden>?</a>
|
||||||
</p>
|
</p>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
@ -68,7 +68,7 @@
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
<p class="browser-languages">
|
<p class="browser-languages">
|
||||||
{{ t('language-dialog.browser-languages') }}:
|
{{ t('language-dialog.browser-languages') }}:
|
||||||
<span v-if="browserLanguages.length > 0">{{ browserLanguages.join(', ') }}</span>
|
<span v-if="browserLanguages.length > 0">{{ browserLanguages.join(', ') }}</span>
|
||||||
<span v-else>{{ t('language-dialog.not-available') }}</span>
|
<span v-else>{{ t('language-dialog.not-available') }}</span>
|
||||||
</p>
|
</p>
|
||||||
|
|
@ -126,6 +126,7 @@ const showFooter = ref(true)
|
||||||
const showNavigation = ref(true)
|
const showNavigation = ref(true)
|
||||||
const showLogs = ref(true)
|
const showLogs = ref(true)
|
||||||
const showDiagnostics = ref(true)
|
const showDiagnostics = ref(true)
|
||||||
|
const showVersionNumber = ref(true)
|
||||||
const showLoginLink = ref(true)
|
const showLoginLink = ref(true)
|
||||||
const sectionNavigationStyle = ref('sidebar')
|
const sectionNavigationStyle = ref('sidebar')
|
||||||
|
|
||||||
|
|
@ -184,7 +185,7 @@ function normalizeBrowserLanguage() {
|
||||||
if (navigator.languages && navigator.languages.length > 0) {
|
if (navigator.languages && navigator.languages.length > 0) {
|
||||||
for (const candidate of navigator.languages) {
|
for (const candidate of navigator.languages) {
|
||||||
const lowerCandidate = candidate.toLowerCase()
|
const lowerCandidate = candidate.toLowerCase()
|
||||||
|
|
||||||
// Try exact match (case-insensitive)
|
// Try exact match (case-insensitive)
|
||||||
const exact = available.find(locale => locale.toLowerCase() === lowerCandidate)
|
const exact = available.find(locale => locale.toLowerCase() === lowerCandidate)
|
||||||
if (exact) {
|
if (exact) {
|
||||||
|
|
@ -223,6 +224,7 @@ function updateHeaderFromInit() {
|
||||||
showNavigation.value = window.initResponse.showNavigation
|
showNavigation.value = window.initResponse.showNavigation
|
||||||
showLogs.value = window.initResponse.showLogList
|
showLogs.value = window.initResponse.showLogList
|
||||||
showDiagnostics.value = window.initResponse.showDiagnostics
|
showDiagnostics.value = window.initResponse.showDiagnostics
|
||||||
|
showVersionNumber.value = window.initResponse.effectivePolicy?.showVersionNumber ?? true
|
||||||
sectionNavigationStyle.value = window.initResponse.sectionNavigationStyle || 'sidebar'
|
sectionNavigationStyle.value = window.initResponse.sectionNavigationStyle || 'sidebar'
|
||||||
availableThemes.value = window.initResponse.availableThemes || []
|
availableThemes.value = window.initResponse.availableThemes || []
|
||||||
|
|
||||||
|
|
@ -277,7 +279,7 @@ function renderNavigation() {
|
||||||
|
|
||||||
function openLanguageDialog() {
|
function openLanguageDialog() {
|
||||||
selectedLanguage.value = languagePreference.value
|
selectedLanguage.value = languagePreference.value
|
||||||
|
|
||||||
if (typeof navigator !== 'undefined' && Array.isArray(navigator.languages)) {
|
if (typeof navigator !== 'undefined' && Array.isArray(navigator.languages)) {
|
||||||
browserLanguages.value = navigator.languages
|
browserLanguages.value = navigator.languages
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -327,7 +329,7 @@ function handleLanguageDialogClick(event) {
|
||||||
|
|
||||||
function openThemeDialog() {
|
function openThemeDialog() {
|
||||||
selectedTheme.value = themePreference.value || ''
|
selectedTheme.value = themePreference.value || ''
|
||||||
|
|
||||||
if (themeDialog.value) {
|
if (themeDialog.value) {
|
||||||
themeDialog.value.showModal()
|
themeDialog.value.showModal()
|
||||||
}
|
}
|
||||||
|
|
@ -354,7 +356,7 @@ function changeTheme() {
|
||||||
|
|
||||||
function applyTheme() {
|
function applyTheme() {
|
||||||
let themeStyle = document.getElementById('theme-style')
|
let themeStyle = document.getElementById('theme-style')
|
||||||
|
|
||||||
if (!themeStyle) {
|
if (!themeStyle) {
|
||||||
themeStyle = document.createElement('style')
|
themeStyle = document.createElement('style')
|
||||||
themeStyle.id = 'theme-style'
|
themeStyle.id = 'theme-style'
|
||||||
|
|
@ -404,10 +406,10 @@ window.updateHeaderFromInit = updateHeaderFromInit
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
serverConnection.value = true;
|
serverConnection.value = true;
|
||||||
updateHeaderFromInit()
|
updateHeaderFromInit()
|
||||||
|
|
||||||
// Initialize selected language from stored preference
|
// Initialize selected language from stored preference
|
||||||
selectedLanguage.value = languagePreference.value
|
selectedLanguage.value = languagePreference.value
|
||||||
|
|
||||||
// Initialize selected theme from stored preference
|
// Initialize selected theme from stored preference
|
||||||
selectedTheme.value = themePreference.value || ''
|
selectedTheme.value = themePreference.value || ''
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -162,7 +162,10 @@ async function generateBrowserInfo() {
|
||||||
userAgentData: userAgentData
|
userAgentData: userAgentData
|
||||||
}
|
}
|
||||||
|
|
||||||
const olivetinVersion = window.initResponse?.currentVersion || t('diagnostics.unknown')
|
const showVersionNumber = window.initResponse?.effectivePolicy?.showVersionNumber ?? true
|
||||||
|
const olivetinVersion = showVersionNumber
|
||||||
|
? (window.initResponse?.currentVersion || t('diagnostics.unknown'))
|
||||||
|
: '[hidden]'
|
||||||
const currentLanguage = locale.value || t('diagnostics.unknown')
|
const currentLanguage = locale.value || t('diagnostics.unknown')
|
||||||
|
|
||||||
let output = '';
|
let output = '';
|
||||||
|
|
@ -300,4 +303,4 @@ onMounted(() => {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 1em;
|
gap: 1em;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,7 @@ message GetDashboardResponse {
|
||||||
message EffectivePolicy {
|
message EffectivePolicy {
|
||||||
bool show_diagnostics = 1;
|
bool show_diagnostics = 1;
|
||||||
bool show_log_list = 2;
|
bool show_log_list = 2;
|
||||||
|
bool show_version_number = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message GetDashboardRequest {
|
message GetDashboardRequest {
|
||||||
|
|
|
||||||
|
|
@ -410,11 +410,12 @@ func (x *GetDashboardResponse) GetDashboard() *Dashboard {
|
||||||
}
|
}
|
||||||
|
|
||||||
type EffectivePolicy struct {
|
type EffectivePolicy struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
ShowDiagnostics bool `protobuf:"varint,1,opt,name=show_diagnostics,json=showDiagnostics,proto3" json:"show_diagnostics,omitempty"`
|
ShowDiagnostics bool `protobuf:"varint,1,opt,name=show_diagnostics,json=showDiagnostics,proto3" json:"show_diagnostics,omitempty"`
|
||||||
ShowLogList bool `protobuf:"varint,2,opt,name=show_log_list,json=showLogList,proto3" json:"show_log_list,omitempty"`
|
ShowLogList bool `protobuf:"varint,2,opt,name=show_log_list,json=showLogList,proto3" json:"show_log_list,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
ShowVersionNumber bool `protobuf:"varint,3,opt,name=show_version_number,json=showVersionNumber,proto3" json:"show_version_number,omitempty"`
|
||||||
sizeCache protoimpl.SizeCache
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *EffectivePolicy) Reset() {
|
func (x *EffectivePolicy) Reset() {
|
||||||
|
|
@ -461,6 +462,13 @@ func (x *EffectivePolicy) GetShowLogList() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *EffectivePolicy) GetShowVersionNumber() bool {
|
||||||
|
if x != nil {
|
||||||
|
return x.ShowVersionNumber
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
type GetDashboardRequest struct {
|
type GetDashboardRequest struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"`
|
Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"`
|
||||||
|
|
@ -3934,10 +3942,11 @@ const file_olivetin_api_v1_olivetin_proto_rawDesc = "" +
|
||||||
"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"f\n" +
|
"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"f\n" +
|
||||||
"\x14GetDashboardResponse\x12\x14\n" +
|
"\x14GetDashboardResponse\x12\x14\n" +
|
||||||
"\x05title\x18\x01 \x01(\tR\x05title\x128\n" +
|
"\x05title\x18\x01 \x01(\tR\x05title\x128\n" +
|
||||||
"\tdashboard\x18\x04 \x01(\v2\x1a.olivetin.api.v1.DashboardR\tdashboard\"`\n" +
|
"\tdashboard\x18\x04 \x01(\v2\x1a.olivetin.api.v1.DashboardR\tdashboard\"\x90\x01\n" +
|
||||||
"\x0fEffectivePolicy\x12)\n" +
|
"\x0fEffectivePolicy\x12)\n" +
|
||||||
"\x10show_diagnostics\x18\x01 \x01(\bR\x0fshowDiagnostics\x12\"\n" +
|
"\x10show_diagnostics\x18\x01 \x01(\bR\x0fshowDiagnostics\x12\"\n" +
|
||||||
"\rshow_log_list\x18\x02 \x01(\bR\vshowLogList\"k\n" +
|
"\rshow_log_list\x18\x02 \x01(\bR\vshowLogList\x12.\n" +
|
||||||
|
"\x13show_version_number\x18\x03 \x01(\bR\x11showVersionNumber\"k\n" +
|
||||||
"\x13GetDashboardRequest\x12\x14\n" +
|
"\x13GetDashboardRequest\x12\x14\n" +
|
||||||
"\x05title\x18\x01 \x01(\tR\x05title\x12\x1f\n" +
|
"\x05title\x18\x01 \x01(\tR\x05title\x12\x1f\n" +
|
||||||
"\ventity_type\x18\x02 \x01(\tR\n" +
|
"\ventity_type\x18\x02 \x01(\tR\n" +
|
||||||
|
|
|
||||||
|
|
@ -710,7 +710,9 @@ func (api *oliveTinAPI) WhoAmI(ctx ctx.Context, req *connect.Request[apiv1.WhoAm
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *oliveTinAPI) SosReport(ctx ctx.Context, req *connect.Request[apiv1.SosReportRequest]) (*connect.Response[apiv1.SosReportResponse], error) {
|
func (api *oliveTinAPI) SosReport(ctx ctx.Context, req *connect.Request[apiv1.SosReportRequest]) (*connect.Response[apiv1.SosReportResponse], error) {
|
||||||
sos := installationinfo.GetSosReport()
|
user := auth.UserFromApiCall(ctx, req, api.cfg)
|
||||||
|
redactVersion := !user.EffectivePolicy.ShowVersionNumber
|
||||||
|
sos := installationinfo.GetSosReport(redactVersion)
|
||||||
|
|
||||||
if !api.cfg.InsecureAllowDumpSos {
|
if !api.cfg.InsecureAllowDumpSos {
|
||||||
log.Info(sos)
|
log.Info(sos)
|
||||||
|
|
@ -914,12 +916,19 @@ func (api *oliveTinAPI) Init(ctx ctx.Context, req *connect.Request[apiv1.InitReq
|
||||||
|
|
||||||
loginRequired := user.IsGuest() && api.cfg.AuthRequireGuestsToLogin
|
loginRequired := user.IsGuest() && api.cfg.AuthRequireGuestsToLogin
|
||||||
|
|
||||||
|
showVersion := user.EffectivePolicy.ShowVersionNumber
|
||||||
|
currentVersion := ""
|
||||||
|
availableVersion := ""
|
||||||
|
if showVersion {
|
||||||
|
currentVersion = installationinfo.Build.Version
|
||||||
|
availableVersion = installationinfo.Runtime.AvailableVersion
|
||||||
|
}
|
||||||
res := &apiv1.InitResponse{
|
res := &apiv1.InitResponse{
|
||||||
ShowFooter: api.cfg.ShowFooter,
|
ShowFooter: api.cfg.ShowFooter,
|
||||||
ShowNavigation: api.cfg.ShowNavigation,
|
ShowNavigation: api.cfg.ShowNavigation,
|
||||||
ShowNewVersions: api.cfg.ShowNewVersions,
|
ShowNewVersions: showVersion && api.cfg.ShowNewVersions,
|
||||||
AvailableVersion: installationinfo.Runtime.AvailableVersion,
|
AvailableVersion: availableVersion,
|
||||||
CurrentVersion: installationinfo.Build.Version,
|
CurrentVersion: currentVersion,
|
||||||
PageTitle: api.cfg.PageTitle,
|
PageTitle: api.cfg.PageTitle,
|
||||||
SectionNavigationStyle: api.cfg.SectionNavigationStyle,
|
SectionNavigationStyle: api.cfg.SectionNavigationStyle,
|
||||||
DefaultIconForBack: api.cfg.DefaultIconForBack,
|
DefaultIconForBack: api.cfg.DefaultIconForBack,
|
||||||
|
|
|
||||||
|
|
@ -55,8 +55,9 @@ func matchesEntity(binding *executor.ActionBinding, entity *entities.Entity) boo
|
||||||
|
|
||||||
func buildEffectivePolicy(policy *config.ConfigurationPolicy) *apiv1.EffectivePolicy {
|
func buildEffectivePolicy(policy *config.ConfigurationPolicy) *apiv1.EffectivePolicy {
|
||||||
ret := &apiv1.EffectivePolicy{
|
ret := &apiv1.EffectivePolicy{
|
||||||
ShowDiagnostics: policy.ShowDiagnostics,
|
ShowDiagnostics: policy.ShowDiagnostics,
|
||||||
ShowLogList: policy.ShowLogList,
|
ShowLogList: policy.ShowLogList,
|
||||||
|
ShowVersionNumber: policy.ShowVersionNumber,
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
|
||||||
|
|
@ -76,8 +76,9 @@ func (u *AuthenticatedUser) BuildUserAcls(cfg *config.Config) {
|
||||||
|
|
||||||
func getEffectivePolicy(cfg *config.Config, u *AuthenticatedUser) *config.ConfigurationPolicy {
|
func getEffectivePolicy(cfg *config.Config, u *AuthenticatedUser) *config.ConfigurationPolicy {
|
||||||
ret := &config.ConfigurationPolicy{
|
ret := &config.ConfigurationPolicy{
|
||||||
ShowDiagnostics: cfg.DefaultPolicy.ShowDiagnostics,
|
ShowDiagnostics: cfg.DefaultPolicy.ShowDiagnostics,
|
||||||
ShowLogList: cfg.DefaultPolicy.ShowLogList,
|
ShowLogList: cfg.DefaultPolicy.ShowLogList,
|
||||||
|
ShowVersionNumber: cfg.DefaultPolicy.ShowVersionNumber,
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, acl := range cfg.AccessControlLists {
|
for _, acl := range cfg.AccessControlLists {
|
||||||
|
|
@ -98,5 +99,9 @@ func buildConfigurationPolicy(ret *config.ConfigurationPolicy, policy config.Con
|
||||||
ret.ShowLogList = policy.ShowLogList
|
ret.ShowLogList = policy.ShowLogList
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if policy.ShowVersionNumber {
|
||||||
|
ret.ShowVersionNumber = policy.ShowVersionNumber
|
||||||
|
}
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -98,8 +98,9 @@ type AccessControlList struct {
|
||||||
|
|
||||||
// ConfigurationPolicy defines global settings which are overridden with an ACL.
|
// ConfigurationPolicy defines global settings which are overridden with an ACL.
|
||||||
type ConfigurationPolicy struct {
|
type ConfigurationPolicy struct {
|
||||||
ShowDiagnostics bool `koanf:"showDiagnostics"`
|
ShowDiagnostics bool `koanf:"showDiagnostics"`
|
||||||
ShowLogList bool `koanf:"showLogList"`
|
ShowLogList bool `koanf:"showLogList"`
|
||||||
|
ShowVersionNumber bool `koanf:"showVersionNumber"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type PrometheusConfig struct {
|
type PrometheusConfig struct {
|
||||||
|
|
@ -297,6 +298,7 @@ func DefaultConfigWithBasePort(basePort int) *Config {
|
||||||
|
|
||||||
config.DefaultPolicy.ShowDiagnostics = true
|
config.DefaultPolicy.ShowDiagnostics = true
|
||||||
config.DefaultPolicy.ShowLogList = true
|
config.DefaultPolicy.ShowLogList = true
|
||||||
|
config.DefaultPolicy.ShowVersionNumber = true
|
||||||
|
|
||||||
return &config
|
return &config
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,15 +40,23 @@ func configToSosreport(cfg *config.Config) *sosReportConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetSosReport() string {
|
func GetSosReport(redactVersion bool) string {
|
||||||
ret := ""
|
ret := ""
|
||||||
|
|
||||||
ret += "### SOSREPORT START (copy all text to SOSREPORT END)\n"
|
ret += "### SOSREPORT START (copy all text to SOSREPORT END)\n"
|
||||||
|
|
||||||
out, _ := yaml.Marshal(Build)
|
buildForReport := *Build
|
||||||
|
if redactVersion {
|
||||||
|
buildForReport.Version = "[redacted]"
|
||||||
|
}
|
||||||
|
out, _ := yaml.Marshal(&buildForReport)
|
||||||
ret += fmt.Sprintf("# Build: \n%+v\n", string(out))
|
ret += fmt.Sprintf("# Build: \n%+v\n", string(out))
|
||||||
|
|
||||||
out, _ = yaml.Marshal(Runtime)
|
runtimeForReport := *Runtime
|
||||||
|
if redactVersion {
|
||||||
|
runtimeForReport.AvailableVersion = "[redacted]"
|
||||||
|
}
|
||||||
|
out, _ = yaml.Marshal(&runtimeForReport)
|
||||||
ret += fmt.Sprintf("# Runtime:\n%+v\n", string(out))
|
ret += fmt.Sprintf("# Runtime:\n%+v\n", string(out))
|
||||||
|
|
||||||
out, _ = yaml.Marshal(configToSosreport(Config))
|
out, _ = yaml.Marshal(configToSosreport(Config))
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue