Handle Stale access token for Gmail and update the startup schema repair. Style the kanban for darkmode better
This commit is contained in:
@@ -537,6 +537,8 @@ CREATE TABLE IF NOT EXISTS "GmailConnections" (
|
|||||||
// Ensure ownership columns exist even on non-legacy DBs.
|
// Ensure ownership columns exist even on non-legacy DBs.
|
||||||
EnsureColumn(conn, "Companies", "OwnerUserId", "ALTER TABLE Companies ADD COLUMN OwnerUserId TEXT NULL;");
|
EnsureColumn(conn, "Companies", "OwnerUserId", "ALTER TABLE Companies ADD COLUMN OwnerUserId TEXT NULL;");
|
||||||
EnsureColumn(conn, "JobApplications", "OwnerUserId", "ALTER TABLE JobApplications ADD COLUMN OwnerUserId TEXT NULL;");
|
EnsureColumn(conn, "JobApplications", "OwnerUserId", "ALTER TABLE JobApplications ADD COLUMN OwnerUserId TEXT NULL;");
|
||||||
|
EnsureColumn(conn, "Correspondences", "Subject", "ALTER TABLE Correspondences ADD COLUMN Subject TEXT NULL;");
|
||||||
|
EnsureColumn(conn, "Correspondences", "Channel", "ALTER TABLE Correspondences ADD COLUMN Channel TEXT NULL;");
|
||||||
EnsureColumn(conn, "Correspondences", "ExternalMessageId", "ALTER TABLE Correspondences ADD COLUMN ExternalMessageId TEXT NULL;");
|
EnsureColumn(conn, "Correspondences", "ExternalMessageId", "ALTER TABLE Correspondences ADD COLUMN ExternalMessageId TEXT NULL;");
|
||||||
|
|
||||||
// Ensure data folder exists before creating/opening SQLite files.
|
// Ensure data folder exists before creating/opening SQLite files.
|
||||||
|
|||||||
@@ -228,7 +228,15 @@ public sealed class GmailOAuthService : IGmailOAuthService
|
|||||||
connection.AccessTokenExpiresAt is { } expiresAt &&
|
connection.AccessTokenExpiresAt is { } expiresAt &&
|
||||||
expiresAt > DateTimeOffset.UtcNow.AddMinutes(1))
|
expiresAt > DateTimeOffset.UtcNow.AddMinutes(1))
|
||||||
{
|
{
|
||||||
return _protector.Unprotect(connection.EncryptedAccessToken);
|
try
|
||||||
|
{
|
||||||
|
return _protector.Unprotect(connection.EncryptedAccessToken);
|
||||||
|
}
|
||||||
|
catch (CryptographicException)
|
||||||
|
{
|
||||||
|
connection.EncryptedAccessToken = null;
|
||||||
|
connection.AccessTokenExpiresAt = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string refreshToken;
|
string refreshToken;
|
||||||
|
|||||||
@@ -131,19 +131,19 @@ export default function KanbanBoard() {
|
|||||||
cursor: "grab",
|
cursor: "grab",
|
||||||
borderRadius: 3,
|
borderRadius: 3,
|
||||||
border: `1px solid ${alpha(c, theme.palette.mode === "dark" ? 0.22 : 0.14)}`,
|
border: `1px solid ${alpha(c, theme.palette.mode === "dark" ? 0.22 : 0.14)}`,
|
||||||
background: theme.palette.mode === "dark" ? "#f8fafc" : "rgba(255,255,255,0.96)",
|
background: theme.palette.mode === "dark" ? "rgba(15,23,42,0.82)" : "rgba(255,255,255,0.96)",
|
||||||
backdropFilter: "blur(8px)",
|
backdropFilter: "blur(8px)",
|
||||||
color: "#0f172a",
|
color: theme.palette.mode === "dark" ? "#e5eefc" : "#0f172a",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CardContent sx={{ p: 1.25, "&:last-child": { pb: 1.25 } }}>
|
<CardContent sx={{ p: 1.25, "&:last-child": { pb: 1.25 } }}>
|
||||||
<Box sx={{ display: "flex", justifyContent: "space-between", gap: 1 }}>
|
<Box sx={{ display: "flex", justifyContent: "space-between", gap: 1 }}>
|
||||||
<Typography sx={{ fontWeight: 800, lineHeight: 1.25, color: "#0f172a" }}>
|
<Typography sx={{ fontWeight: 800, lineHeight: 1.25, color: theme.palette.mode === "dark" ? "#f8fafc" : "#0f172a" }}>
|
||||||
{j.company?.name ?? ""}
|
{j.company?.name ?? ""}
|
||||||
</Typography>
|
</Typography>
|
||||||
<IconButton
|
<IconButton
|
||||||
size="small"
|
size="small"
|
||||||
sx={{ color: "#0f172a" }}
|
sx={{ color: theme.palette.mode === "dark" ? "#e2e8f0" : "#0f172a" }}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setMenuJobId(j.id);
|
setMenuJobId(j.id);
|
||||||
@@ -153,12 +153,12 @@ export default function KanbanBoard() {
|
|||||||
<MoreHorizIcon fontSize="small" />
|
<MoreHorizIcon fontSize="small" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Box>
|
</Box>
|
||||||
<Typography variant="body2" sx={{ color: "#475569" }}>
|
<Typography variant="body2" sx={{ color: theme.palette.mode === "dark" ? "#cbd5e1" : "#475569" }}>
|
||||||
{j.jobTitle}
|
{j.jobTitle}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Box sx={{ display: "flex", gap: 1, mt: 1, flexWrap: "wrap" }}>
|
<Box sx={{ display: "flex", gap: 1, mt: 1, flexWrap: "wrap" }}>
|
||||||
<Chip size="small" label={`${j.daysSince}d`} sx={{ color: "#0f172a", backgroundColor: "rgba(148,163,184,0.18)" }} />
|
<Chip size="small" label={`${j.daysSince}d`} sx={{ color: theme.palette.mode === "dark" ? "#e2e8f0" : "#0f172a", backgroundColor: theme.palette.mode === "dark" ? "rgba(148,163,184,0.18)" : "rgba(148,163,184,0.18)" }} />
|
||||||
{j.location ? <Chip size="small" label={j.location} sx={{ color: "#0f172a", backgroundColor: "rgba(148,163,184,0.18)" }} /> : null}
|
{j.location ? <Chip size="small" label={j.location} sx={{ color: theme.palette.mode === "dark" ? "#e2e8f0" : "#0f172a", backgroundColor: theme.palette.mode === "dark" ? "rgba(148,163,184,0.18)" : "rgba(148,163,184,0.18)" }} /> : null}
|
||||||
</Box>
|
</Box>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
Reference in New Issue
Block a user