Fix workflow YAML and improve CV section editing
This commit is contained in:
@@ -76,12 +76,17 @@ jobs:
|
|||||||
APP_BUILD_STAMP="$(date -u +'%Y-%m-%d %H:%M UTC')" \
|
APP_BUILD_STAMP="$(date -u +'%Y-%m-%d %H:%M UTC')" \
|
||||||
./deploy/deploy.sh
|
./deploy/deploy.sh
|
||||||
docker compose ps
|
docker compose ps
|
||||||
docker compose exec -T ai-service python -c "import time, urllib.request; deadline=time.time()+60; last=None
|
docker compose exec -T ai-service python - <<'PY'
|
||||||
for _ in range(30):
|
import time
|
||||||
|
import urllib.request
|
||||||
|
|
||||||
|
last = None
|
||||||
|
for _ in range(30):
|
||||||
try:
|
try:
|
||||||
urllib.request.urlopen('http://127.0.0.1:8001/health', timeout=5).read()
|
urllib.request.urlopen('http://127.0.0.1:8001/health', timeout=5).read()
|
||||||
raise SystemExit(0)
|
raise SystemExit(0)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
last=exc
|
last = exc
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
raise last"
|
raise last
|
||||||
|
PY
|
||||||
|
|||||||
@@ -211,6 +211,7 @@ export const translations = {
|
|||||||
profileCvSectionDraft: "Section draft",
|
profileCvSectionDraft: "Section draft",
|
||||||
profileCvSectionDraftPlaceholder: "Your rewritten section will appear here.",
|
profileCvSectionDraftPlaceholder: "Your rewritten section will appear here.",
|
||||||
profileCvSectionAppend: "Append to CV text",
|
profileCvSectionAppend: "Append to CV text",
|
||||||
|
profileCvSectionReplace: "Replace matching section",
|
||||||
profileSaveChanges: "Save changes",
|
profileSaveChanges: "Save changes",
|
||||||
profileUpdated: "Profile updated.",
|
profileUpdated: "Profile updated.",
|
||||||
profileUpdateFailed: "Failed to update profile.",
|
profileUpdateFailed: "Failed to update profile.",
|
||||||
@@ -984,6 +985,7 @@ export const translations = {
|
|||||||
profileCvSectionDraft: "Seksjonsutkast",
|
profileCvSectionDraft: "Seksjonsutkast",
|
||||||
profileCvSectionDraftPlaceholder: "Den omskrevne seksjonen vises her.",
|
profileCvSectionDraftPlaceholder: "Den omskrevne seksjonen vises her.",
|
||||||
profileCvSectionAppend: "Legg til i CV-teksten",
|
profileCvSectionAppend: "Legg til i CV-teksten",
|
||||||
|
profileCvSectionReplace: "Erstatt matchende seksjon",
|
||||||
profileSaveChanges: "Lagre endringer",
|
profileSaveChanges: "Lagre endringer",
|
||||||
profileUpdated: "Profil oppdatert.",
|
profileUpdated: "Profil oppdatert.",
|
||||||
profileUpdateFailed: "Kunne ikke oppdatere profil.",
|
profileUpdateFailed: "Kunne ikke oppdatere profil.",
|
||||||
|
|||||||
@@ -46,6 +46,28 @@ function initialsFrom(values: Array<string | undefined>) {
|
|||||||
return (joined[0][0] + joined[1][0]).toUpperCase();
|
return (joined[0][0] + joined[1][0]).toUpperCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function replaceCvSection(source: string, sectionName: string, sectionDraft: string) {
|
||||||
|
const trimmedSource = source.trim();
|
||||||
|
const trimmedDraft = sectionDraft.trim();
|
||||||
|
if (!trimmedDraft) return source;
|
||||||
|
if (!trimmedSource) return `${sectionName}\n${trimmedDraft}`;
|
||||||
|
|
||||||
|
const headingPattern = /^([A-Z][A-Za-z &/]+):?\s*$/gm;
|
||||||
|
const matches = Array.from(trimmedSource.matchAll(headingPattern));
|
||||||
|
const normalizedTarget = sectionName.trim().toLowerCase();
|
||||||
|
const targetIndex = matches.findIndex((match) => match[1].trim().toLowerCase() === normalizedTarget);
|
||||||
|
|
||||||
|
if (targetIndex === -1) {
|
||||||
|
return `${trimmedSource}\n\n${sectionName}\n${trimmedDraft}`.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
const start = matches[targetIndex].index ?? 0;
|
||||||
|
const end = targetIndex + 1 < matches.length ? (matches[targetIndex + 1].index ?? trimmedSource.length) : trimmedSource.length;
|
||||||
|
const before = trimmedSource.slice(0, start).trimEnd();
|
||||||
|
const after = trimmedSource.slice(end).trimStart();
|
||||||
|
return [before, `${sectionName}\n${trimmedDraft}`, after].filter(Boolean).join("\n\n").trim();
|
||||||
|
}
|
||||||
|
|
||||||
export default function ProfilePage() {
|
export default function ProfilePage() {
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
@@ -376,6 +398,7 @@ export default function ProfilePage() {
|
|||||||
<Box sx={{ mt: 1, display: "flex", justifyContent: "flex-end", gap: 1, flexWrap: "wrap" }}>
|
<Box sx={{ mt: 1, display: "flex", justifyContent: "flex-end", gap: 1, flexWrap: "wrap" }}>
|
||||||
<Button variant="text" disabled={!cvSectionDraft.trim()} onClick={() => navigator.clipboard.writeText(cvSectionDraft)}>{t("profileCopyCvText")}</Button>
|
<Button variant="text" disabled={!cvSectionDraft.trim()} onClick={() => navigator.clipboard.writeText(cvSectionDraft)}>{t("profileCopyCvText")}</Button>
|
||||||
<Button variant="outlined" disabled={!cvSectionDraft.trim()} onClick={() => setProfileCvText((prev) => `${prev.trim()}\n\n${cvSection}\n${cvSectionDraft.trim()}`.trim())}>{t("profileCvSectionAppend")}</Button>
|
<Button variant="outlined" disabled={!cvSectionDraft.trim()} onClick={() => setProfileCvText((prev) => `${prev.trim()}\n\n${cvSection}\n${cvSectionDraft.trim()}`.trim())}>{t("profileCvSectionAppend")}</Button>
|
||||||
|
<Button variant="contained" disabled={!cvSectionDraft.trim()} onClick={() => setProfileCvText((prev) => replaceCvSection(prev, cvSection, cvSectionDraft))}>{t("profileCvSectionReplace")}</Button>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
<Box sx={{ mt: 1, display: "flex", justifyContent: "space-between", gap: 1, flexWrap: "wrap" }}>
|
<Box sx={{ mt: 1, display: "flex", justifyContent: "space-between", gap: 1, flexWrap: "wrap" }}>
|
||||||
|
|||||||
Reference in New Issue
Block a user