Compare commits

...

2 Commits

Author SHA1 Message Date
Alec Schitzkat 4809931ec9 FIX - unify CityWarn spacing and scrolling 2026-08-24 00:47:08 +02:00
Alec Schitzkat 9efd92e6b6 FIX - repair persisted company messaging defaults 2026-08-24 00:47:00 +02:00
4 changed files with 178 additions and 17 deletions
@@ -106,4 +106,31 @@ describe('company configurator creation contract', () => {
expect(blankRegistration).toBeGreaterThanOrEqual(0)
expect(blankRegistration).toBeLessThan(policeRegistration)
})
it('repairs persisted service-line messaging before Companies starts', () => {
const migration = configuratorServer.slice(
configuratorServer.indexOf(
'local function migrate_unsupported_company_message_defaults()',
),
configuratorServer.indexOf('\n\ndefault_config = {}'),
)
const policeRegistration = configuratorServer.indexOf(
'Bridge.Database.AfterMigration("sky_phone", migrate_police_request_defaults)',
)
const messageRegistration = configuratorServer.indexOf(
'Bridge.Database.AfterMigration("sky_phone", migrate_unsupported_company_message_defaults)',
)
expect(migration).toContain(
'sky-phone:configurator:unsupported-company-message-defaults:v1',
)
expect(migration).toContain('line.CanMessage == true')
expect(migration).toContain('line.CanMessage = false')
expect(migration).toContain('Bridge.Database.Transaction(statements)')
expect(migration).toContain('SET `config_payload` = ?')
expect(migration).toContain('`revision` = `revision` + 1')
expect(migration).toContain('apply_stored_row(read_stored_row())')
expect(migration).toContain('apply_runtime_configuration()')
expect(messageRegistration).toBeGreaterThan(policeRegistration)
})
})
@@ -40,6 +40,10 @@ describe('CityWarn product contract', () => {
})
it('reserves the pill navigation, keeps sheets safe and avoids blur flicker', () => {
expect(source).toMatch(
/\.citywarn-scroll\s*\{[^}]*min-height:\s*0;[^}]*height:\s*auto;[^}]*flex:\s*1 1 0;[^}]*overflow-y:\s*auto;/s,
)
expect(source).not.toMatch(/\.citywarn-scroll\s*\{[^}]*height:\s*100%;/s)
expect(source).toMatch(
/\.citywarn-scroll\.sky-scroll-area--tabbar\s*\{[^}]*padding-bottom:\s*calc\(var\(--sky-safe-area-bottom\) \+ 84px\)/s,
)
@@ -56,6 +60,51 @@ describe('CityWarn product contract', () => {
expect(source).not.toContain('<span>{{ alert.title }}</span>')
})
it('uses one spacing and radius system throughout the current feed', () => {
expect(source).toMatch(
/\.citywarn-overview\s*\{[^}]*padding:\s*var\(--sky-space-3\);[^}]*gap:\s*var\(--sky-space-3\);[^}]*border-radius:\s*var\(--sky-radius-card\);/s,
)
expect(source).toMatch(
/\.citywarn-overview \+ \.citywarn-feed\s*\{[^}]*margin-top:\s*var\(--sky-space-3\);[^}]*gap:\s*var\(--sky-space-3\);/s,
)
expect(source).toMatch(
/\.citywarn-alert-card\s*\{[^}]*border-radius:\s*var\(--sky-radius-card\);/s,
)
expect(source).toMatch(
/\.citywarn-publisher-card\s*\{[^}]*margin:\s*var\(--sky-space-3\) 0 0;[^}]*border-radius:\s*var\(--sky-radius-card\);/s,
)
expect(source).toMatch(
/\.citywarn-publisher-card :deep\(\.sky-card__content\)\s*\{[^}]*padding:\s*var\(--sky-space-3\);[^}]*gap:\s*var\(--sky-space-3\);/s,
)
for (const selector of [
'citywarn-overview-symbol',
'citywarn-card-icon',
'citywarn-publisher-icon',
]) {
expect(source).toMatch(
new RegExp(
`\\.${selector}\\s*\\{[^}]*border-radius:\\s*var\\(--sky-radius-control\\);`,
's',
),
)
}
})
it('keeps settings groups on one compact spacing rhythm', () => {
expect(source).toMatch(
/\.citywarn-settings\s*\{[^}]*gap:\s*var\(--sky-space-5\);/s,
)
expect(source).toMatch(
/\.citywarn-settings :deep\(\.sky-settings-group\)\s*\{[^}]*margin:\s*0;/s,
)
expect(source).toMatch(
/\.citywarn-settings :deep\(\.sky-settings-group__title\)\s*\{[^}]*margin:\s*0 var\(--sky-space-1\) var\(--sky-space-2\);/s,
)
expect(source).toMatch(
/\.citywarn-settings :deep\(\.sky-settings-group__footer\)\s*\{[^}]*margin:\s*var\(--sky-space-2\) var\(--sky-space-1\) 0;/s,
)
})
it('keeps publishing authorization and validation on the server', () => {
expect(server).toContain('Bridge.Framework.GetJob(source)')
expect(server).toContain('SkyPhone.RequireSession(source)')
+34 -17
View File
@@ -1026,7 +1026,9 @@ onMounted(async () => {
height: 18px;
}
.citywarn-scroll {
height: 100%;
min-height: 0;
height: auto;
flex: 1 1 0;
padding: 12px 13px calc(28px + env(safe-area-inset-bottom));
overflow-y: auto;
}
@@ -1045,11 +1047,11 @@ onMounted(async () => {
}
.citywarn-overview {
display: flex;
padding: 15px;
padding: var(--sky-space-3);
align-items: center;
gap: 12px;
gap: var(--sky-space-3);
border: 1px solid #bbf7d0;
border-radius: 18px;
border-radius: var(--sky-radius-card);
background: linear-gradient(135deg, #f0fdf4, #ecfdf5);
}
.citywarn-overview--active {
@@ -1062,7 +1064,7 @@ onMounted(async () => {
height: 46px;
flex: 0 0 auto;
place-items: center;
border-radius: 15px;
border-radius: var(--sky-radius-control);
color: #15803d;
background: #dcfce7;
}
@@ -1086,12 +1088,17 @@ onMounted(async () => {
flex-direction: column;
gap: 10px;
}
.citywarn-overview + .citywarn-feed {
margin-top: var(--sky-space-3);
gap: var(--sky-space-3);
}
.citywarn-alert-card {
position: relative;
padding: 13px 13px 12px 17px;
padding: var(--sky-space-3) var(--sky-space-3) var(--sky-space-3)
var(--sky-space-4);
overflow: hidden;
border: 1px solid #e5e7eb;
border-radius: 17px;
border-radius: var(--sky-radius-card);
background: #fff;
box-shadow: 0 4px 15px rgb(15 23 42 / 5%);
cursor: pointer;
@@ -1115,7 +1122,7 @@ onMounted(async () => {
width: 32px;
height: 32px;
place-items: center;
border-radius: 10px;
border-radius: var(--sky-radius-control);
color: var(--severity);
background: color-mix(in srgb, var(--severity) 12%, white);
}
@@ -1139,7 +1146,7 @@ onMounted(async () => {
color: #9ca3af;
}
.citywarn-alert-card h3 {
margin: 10px 0 5px;
margin: var(--sky-space-2) 0 var(--sky-space-1);
font-size: 16px;
line-height: 1.18;
}
@@ -1155,10 +1162,10 @@ onMounted(async () => {
}
.citywarn-alert-card footer {
display: flex;
margin-top: 11px;
margin-top: var(--sky-space-2);
align-items: center;
justify-content: space-between;
gap: 8px;
gap: var(--sky-space-2);
color: #6b7280;
font-size: 10.5px;
}
@@ -1172,12 +1179,13 @@ onMounted(async () => {
white-space: nowrap;
}
.citywarn-publisher-card {
margin-top: 12px;
margin: var(--sky-space-3) 0 0;
border-radius: var(--sky-radius-card);
}
.citywarn-publisher-card :deep(.sky-card__content) {
display: flex;
padding: 12px;
gap: 10px;
padding: var(--sky-space-3);
gap: var(--sky-space-3);
}
.citywarn-publisher-icon {
display: grid;
@@ -1185,7 +1193,7 @@ onMounted(async () => {
height: 36px;
flex: 0 0 auto;
place-items: center;
border-radius: 11px;
border-radius: var(--sky-radius-control);
color: #1d4ed8;
background: #dbeafe;
}
@@ -1523,11 +1531,20 @@ onMounted(async () => {
.citywarn-settings {
display: flex;
flex-direction: column;
gap: 15px;
gap: var(--sky-space-5);
}
.citywarn-settings :deep(.sky-settings-group) {
margin: 0;
}
.citywarn-settings :deep(.sky-settings-group__title) {
margin: 0 var(--sky-space-1) var(--sky-space-2);
}
.citywarn-settings :deep(.sky-settings-group__footer) {
margin: var(--sky-space-2) var(--sky-space-1) 0;
}
.citywarn-settings-hint {
display: flex;
margin: 0 8px;
margin: 0 var(--sky-space-1);
align-items: flex-start;
gap: 7px;
color: #6b7280;
@@ -1289,6 +1289,73 @@ local function migrate_police_request_defaults()
)
end
local function migrate_unsupported_company_message_defaults()
local migration_name = "sky-phone:configurator:unsupported-company-message-defaults:v1"
local completed = Bridge.Database.Query(
"SELECT 1 FROM `sky_phone_migrations` WHERE `name` = ? LIMIT 1",
{ migration_name }
)
if completed[1] then
return
end
local row = read_stored_row()
local config_payload = decode_payload(row.config_payload, "config")
local definitions = config_payload.Companies
and config_payload.Companies.Definitions
local migrated_companies = {}
if type(definitions) == "table" then
for company_id, definition in pairs(definitions) do
local line = type(definition) == "table" and definition.ServiceLine or nil
if type(line) == "table" and line.CanMessage == true then
line.CanMessage = false
migrated_companies[#migrated_companies + 1] = tostring(company_id)
end
end
end
table.sort(migrated_companies)
local statements = {}
if #migrated_companies > 0 then
statements[#statements + 1] = {
query = ([[
UPDATE `%s`
SET `config_payload` = ?, `revision` = `revision` + 1
WHERE `id` = ?
]]):format(TABLE_NAME),
params = { encode_payload(config_payload, "config"), CONFIG_ROW_ID },
}
end
statements[#statements + 1] = {
query = [[
INSERT IGNORE INTO `sky_phone_migrations` (`name`, `source`, `stats`)
VALUES (?, ?, ?)
]],
params = {
migration_name,
"sky-phone",
json.encode({ companies = migrated_companies }),
},
}
if not Bridge.Database.Transaction(statements) then
error("[sky_phone] Could not migrate unsupported Phone Configurator service-line messaging defaults.")
end
if #migrated_companies == 0 then
return
end
apply_stored_row(read_stored_row())
apply_runtime_configuration()
TriggerEvent("sky_phone:configurator:serverUpdated", revision)
SkyPhoneConfigurator.Broadcast(-1)
Bridge.Debug(
"info",
"[sky_phone] Disabled unsupported Phone Configurator service-line messaging for: %s",
table.concat(migrated_companies, ", "),
{ always = true }
)
end
default_config = {}
for key, value in pairs(ConfigDefaults) do
if key ~= "Media" and key ~= "PhoneConfigurator" and key ~= "CommandPermissions" then
@@ -1311,6 +1378,7 @@ apply_stored_row(read_stored_row())
apply_runtime_configuration()
Bridge.Database.AfterMigration("sky_phone", migrate_blank_company_definitions)
Bridge.Database.AfterMigration("sky_phone", migrate_police_request_defaults)
Bridge.Database.AfterMigration("sky_phone", migrate_unsupported_company_message_defaults)
function SkyPhoneConfigurator.GetAdminData()
local data = build_admin_data()