Skip to content
Open

1.1.9 #676

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
491311a
Change immediate from true to false for document downloads
Dec 10, 2025
0138baa
Remove responseType blob from downloadDocumentSaga and downloadDocume…
Dec 10, 2025
6d43734
js-yaml has prototype pollution fix (#642)
henrihaapalasiili Dec 10, 2025
3fb0b8b
glob CLI: Command injection fix (#650)
henrihaapalasiili Dec 10, 2025
a26c9c9
KAAV-3495 add temporary fix for the empty space at the top of the pag…
MinnaSiili Dec 11, 2025
70bf4da
KAAV-3495 add temporary exclusion for hidden lautakunta fieldset in a…
MinnaSiili Dec 11, 2025
cdfc6aa
Merge pull request #651 from City-of-Helsinki/KAAV-3495
MinnaSiili Dec 11, 2025
4ffd9ab
Merge remote-tracking branch 'origin/master' into development
eemeli-kukkonen-siili Dec 11, 2025
c2508b9
KAAV-3377 add further timeUtils unit tests (#653)
eemeli-kukkonen-siili Dec 11, 2025
95a16e0
KAAV-3377 compareAndUpdateDates tests (#654)
eemeli-kukkonen-siili Dec 17, 2025
28a1a74
KAAV-3377 unit tests for various utility classes (#656)
eemeli-kukkonen-siili Dec 18, 2025
77bca77
KAPI-190 Prevent manually selected lausunnot_viimeistaan date from ge…
eemeli-kukkonen-siili Jan 21, 2026
fb67ab8
KAAV-3504 Restrict drag handle to center dot, fix tooltip hover prior…
MinnaSiili Jan 26, 2026
7d1e115
KAAV-3504 Add fixes for SonarCloud issues
MinnaSiili Jan 26, 2026
0269142
KAAV-3504 Add more fixes for SonarCloud issues
MinnaSiili Jan 26, 2026
c343920
KAPI-190 disable manual selection of lausunnot_viimeistaan
eemeli-kukkonen-siili Jan 27, 2026
ab7745b
KAPI-192 Fix last saved time in an error situation
eemeli-kukkonen-siili Jan 27, 2026
871fdef
KAAV-3518 convert header navigation items to buttons for accessibilit…
eemeli-kukkonen-siili Jan 27, 2026
b07bdc6
KAAV-3652 Add confirmed-icon to 'dates confirmed, past-time' element …
MinnaSiili Jan 28, 2026
e1a49bb
Merge pull request #667 from City-of-Helsinki/KAAV-3562
MinnaSiili Jan 28, 2026
6445053
Merge pull request #664 from City-of-Helsinki/KAAV-3504
MinnaSiili Jan 28, 2026
a29bcdb
KAAV-3519 revert back to hds for adCombobox due to accessibility conc…
eemeli-kukkonen-siili Feb 5, 2026
ff7b4fc
KAAV-3519 fix tab navigation & spacebar select on CustomADUserCombobox
eemeli-kukkonen-siili Feb 11, 2026
a988e70
Bump axios from 1.12.1 to 1.13.5 (#673)
dependabot[bot] Feb 16, 2026
309b18e
Bump tar from 7.4.3 to 7.5.7 (#668)
dependabot[bot] Feb 16, 2026
6d9292e
KAAV-3518 Implement manual accessibility features for user menu navig…
eemeli-kukkonen-siili Feb 16, 2026
7d28556
Merge remote-tracking branch 'origin/development' into development
eemeli-kukkonen-siili Feb 16, 2026
a1858b0
KAAV-3492 Validoinnin nopeutus ja Seuraavat elementit eivät siirry et…
henrihaapalasiili Feb 19, 2026
3b67545
Bump tar from 7.5.7 to 7.5.9 (#675)
dependabot[bot] Feb 19, 2026
963df69
KAAV-3518 Enhance keyboard accessibility for user menu navigation
eemeli-kukkonen-siili Feb 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
},
"dependencies": {
"@sentry/browser": "^7.119.1",
"axios": "^1.12.0",
"axios": "^1.13.5",
"axios-retry": "^4.0.0",
"connected-react-router": "^6.9.1",
"core-js": "^3.33.1",
Expand Down Expand Up @@ -87,14 +87,15 @@
"lint-fix": "eslint . --fix",
"codecov": "codecov",
"precommit": "yarn test && yarn run lint",
"test-coverage": "vitest run --coverage"
"test-coverage": "vitest run --coverage",
"regenerate-mock-data": "node scripts/regenerate-mock-data.mjs"
},
"devDependencies": {
"@testing-library/dom": "^9.0.1",
"@testing-library/react": "^14.0.0",
"@testing-library/user-event": "^14.4.3",
"@vitejs/plugin-react": "^4.6.0",
"@vitest/coverage-c8": "^0.33.0",
"@vitest/coverage-v8": "^4.0.0",
"babel-eslint": "^10.1.0",
"codecov": "^3.8.3",
"deep-freeze": "0.0.1",
Expand All @@ -113,7 +114,7 @@
"sass-embedded": "^1.89.2",
"vite": "^7.1.3",
"vite-plugin-svgr": "^4.3.0",
"vitest": "^3.2.4",
"vitest": "^4.0.0",
"vitest-dom": "^0.1.1"
},
"proxy": "http://localhost:8000",
Expand Down
2 changes: 1 addition & 1 deletion public/locales/fi/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"documents-menu-back": "Palaa takaisin projektin muokkaukseen",
"edit-menu-no-save":"Ei tallentamattomia tietoja",
"edit-menu-saved":"Tallennettu: ",
"edit-menu-save-fail":"Tallennus epäonnistui: ",
"edit-menu-save-fail":"Tallennus epäonnistui",
"latest-save":"Viimeisin tallennus: "
},
"document-loading": {
Expand Down
325 changes: 325 additions & 0 deletions scripts/regenerate-mock-data.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,325 @@
#!/usr/bin/env node
/**
* Mock Data Regeneration Script
*
* This script regenerates test mock data from the real Kaavapino API.
* It ensures tests use realistic data that matches the current database state.
*
* Usage:
* node scripts/regenerate-mock-data.mjs [--api-url URL] [--output-dir DIR]
*
* Options:
* --api-url Base URL of the Kaavapino API (default: http://localhost:8000)
* --output-dir Directory to write mock data files (default: src/__tests__/utils)
* --dry-run Print what would be generated without writing files
*
* Environment Variables:
* KAAVAPINO_API_URL Alternative way to set the API URL
* KAAVAPINO_API_TOKEN Bearer token for API authentication
*
* Prerequisites:
* - Kaavapino backend running locally or accessible via network
* - API token with read access to project schemas and date types
*/

import fs from 'fs/promises';
import path from 'path';
import { fileURLToPath } from 'url';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

// Parse command line arguments
const args = process.argv.slice(2);
const getArg = (name) => {
const index = args.indexOf(name);
return index !== -1 ? args[index + 1] : null;
};

const API_URL = getArg('--api-url') || process.env.KAAVAPINO_API_URL || 'http://localhost:8000';
const OUTPUT_DIR = getArg('--output-dir') || path.join(__dirname, '..', 'src', '__tests__', 'utils');
const DRY_RUN = args.includes('--dry-run');
const API_TOKEN = process.env.KAAVAPINO_API_TOKEN || '';

console.log('🔄 Mock Data Regeneration Script');
console.log('================================');
console.log(`API URL: ${API_URL}`);
console.log(`Output Directory: ${OUTPUT_DIR}`);
console.log(`Dry Run: ${DRY_RUN}`);
console.log('');

/**
* Fetch data from the API with authentication
*/
async function fetchFromApi(endpoint) {
const headers = {
'Content-Type': 'application/json',
};

if (API_TOKEN) {
headers['Authorization'] = `Bearer ${API_TOKEN}`;
}

try {
const response = await fetch(`${API_URL}${endpoint}`, { headers });

if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}

return await response.json();
} catch (error) {
console.error(`❌ Failed to fetch ${endpoint}: ${error.message}`);
return null;
}
}

/**
* Generate date type arrays (arkipäivät, työpäivät, lautakuntapäivät)
* These are generated algorithmically to match the backend's date type logic
*/
function generateDateTypes() {
const startYear = new Date().getFullYear();
const endYear = startYear + 5;

const arkipäivät = [];
const työpäivät = [];
const lautakuntapäivät = [];
const esilläolopäivät = [];

const startDate = new Date(`${startYear}-01-01`);
const endDate = new Date(`${endYear}-12-31`);

for (let d = startDate.getTime(); d <= endDate.getTime(); d += 86400000) {
const currentDate = new Date(d);
const day = currentDate.getDay();
const month = currentDate.getMonth() + 1;
const date = currentDate.getDate();
const year = currentDate.getFullYear();
const dateStr = `${year}-${String(month).padStart(2, '0')}-${String(date).padStart(2, '0')}`;

// Arkipäivät: Weekdays (Mon-Fri)
if (day !== 0 && day !== 6) {
arkipäivät.push(dateStr);

// Työpäivät: Weekdays excluding July and Christmas period
const isJuly = month === 7;
const isChristmasPeriod = (month === 12 && date >= 24) || (month === 1 && date <= 6);

if (!isJuly && !isChristmasPeriod) {
työpäivät.push(dateStr);

// Esilläolopäivät: Työpäivät excluding weeks 8 and 42
const weekNumber = getWeekNumber(currentDate);
if (weekNumber !== 8 && weekNumber !== 42) {
esilläolopäivät.push(dateStr);
}
}
}

// Lautakuntapäivät: Tuesdays excluding July
if (day === 2 && month !== 7) {
lautakuntapäivät.push(dateStr);
}
}

return { arkipäivät, työpäivät, lautakuntapäivät, esilläolopäivät };
}

/**
* Get ISO week number for a date
*/
function getWeekNumber(date) {
const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
const dayNum = d.getUTCDay() || 7;
d.setUTCDate(d.getUTCDate() + 4 - dayNum);
const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
return Math.ceil((((d - yearStart) / 86400000) + 1) / 7);
}

/**
* Fetch deadline distances from the API
*/
async function fetchDeadlineDistances() {
console.log('📡 Fetching deadline distances from API...');

// Try to fetch from the deadline distances endpoint
const distances = await fetchFromApi('/v1/deadline-distances/');

if (distances) {
console.log(`✅ Fetched ${distances.length || 'unknown'} deadline distance rules`);
return distances;
}

console.log('⚠️ Could not fetch deadline distances, using static data');
return null;
}

/**
* Fetch project schema to get deadline field definitions
*/
async function fetchProjectSchema() {
console.log('📡 Fetching project schema from API...');

const schema = await fetchFromApi('/v1/projects/schema/');

if (schema) {
console.log(`✅ Fetched project schema`);
return schema;
}

console.log('⚠️ Could not fetch project schema');
return null;
}

/**
* Generate the checkForDecreasingValues_test_data.js file content
*/
function generateTestDataFile(dateTypes, deadlineDistances) {
const { arkipäivät, työpäivät, lautakuntapäivät, esilläolopäivät } = dateTypes;

let content = `/**
* Auto-generated mock data for checkForDecreasingValues tests
*
* Generated at: ${new Date().toISOString()}
*
* This file contains:
* - Date type arrays (arkipäivät, työpäivät, lautakuntapäivät, esilläolopäivät)
* - Sample deadline timeline array with distance rules
*
* To regenerate: node scripts/regenerate-mock-data.mjs
*/

const generateMockArkipäivät = () => {
const dates = [];
let currentDate = new Date("${arkipäivät[0]}");
const endDate = new Date("${arkipäivät[arkipäivät.length - 1]}");

while (currentDate <= endDate) {
const day = currentDate.getDay();
if (day !== 0 && day !== 6) { // Exclude Sundays (0) and Saturdays (6)
const year = currentDate.getFullYear();
const month = String(currentDate.getMonth() + 1).padStart(2, '0');
const date = String(currentDate.getDate()).padStart(2, '0');
dates.push(\`\${year}-\${month}-\${date}\`);
}
currentDate.setDate(currentDate.getDate() + 1);
}
return dates;
}

const generateMockTyöpäivät = () => {
const dates = [];
let currentDate = new Date("${työpäivät[0]}");
const endDate = new Date("${työpäivät[työpäivät.length - 1]}");

// Exclude weekends, all july dates, and dates from 24.12 to 6.1
while (currentDate <= endDate) {
const day = currentDate.getDay();
const month = String(currentDate.getMonth() + 1).padStart(2, '0');
const date = String(currentDate.getDate()).padStart(2, '0');
if (day !== 0 && day !== 6 && month !== '07' &&
!(month === '12' && date >= '24') && !(month === '01' && date <= '06')) {
const year = currentDate.getFullYear();
dates.push(\`\${year}-\${month}-\${date}\`);
}
currentDate.setDate(currentDate.getDate() + 1);
}
return dates;
}

const generateMockLautakuntapäivät = () => {
const dates = [];
let currentDate = new Date("${lautakuntapäivät[0]}");
const endDate = new Date("${lautakuntapäivät[lautakuntapäivät.length - 1]}");

while (currentDate <= endDate) {
const day = currentDate.getDay();
const month = String(currentDate.getMonth() + 1).padStart(2, '0');
if (day === 2 && month !== '07') { // Tuesdays (2) excluding July
const year = currentDate.getFullYear();
const date = String(currentDate.getDate()).padStart(2, '0');
dates.push(\`\${year}-\${month}-\${date}\`);
}
currentDate.setDate(currentDate.getDate() + 1);
}
return dates;
}

const generateMockEsillaolopaivat = () => {
const base_dates = generateMockTyöpäivät();
return base_dates.filter(date => {
const dateObj = new Date(date)
const weekNumber = Math.ceil((((dateObj - new Date(dateObj.getFullYear(),0,1)) / 86400000) + dateObj.getDay()+1)/7);
return !(weekNumber === 8 || weekNumber === 42);
});
}

`;

// If we have deadline distances from the API, include them
if (deadlineDistances && Array.isArray(deadlineDistances)) {
content += `// Deadline distances fetched from API
const deadline_distances = ${JSON.stringify(deadlineDistances, null, 2)};

`;
}

// Add the sample test array (this would be fetched from a real project in production)
content += `// Sample decreasing test array - regenerate from real project data as needed
// Use: node scripts/regenerate-mock-data.mjs --project-id <id>
`;

return content;
}

/**
* Main execution
*/
async function main() {
try {
// Generate date types
console.log('📅 Generating date type arrays...');
const dateTypes = generateDateTypes();
console.log(`✅ Generated ${dateTypes.arkipäivät.length} arkipäivät`);
console.log(`✅ Generated ${dateTypes.työpäivät.length} työpäivät`);
console.log(`✅ Generated ${dateTypes.lautakuntapäivät.length} lautakuntapäivät`);
console.log(`✅ Generated ${dateTypes.esilläolopäivät.length} esilläolopäivät`);

// Try to fetch from API
const deadlineDistances = await fetchDeadlineDistances();
const projectSchema = await fetchProjectSchema();

// Generate file content
const content = generateTestDataFile(dateTypes, deadlineDistances);

if (DRY_RUN) {
console.log('\n📝 Would generate the following content:');
console.log('---');
console.log(content.substring(0, 2000) + '...');
console.log('---');
console.log('\n✅ Dry run complete. No files written.');
} else {
// Write to file
const outputPath = path.join(OUTPUT_DIR, 'mock_date_types.generated.js');
await fs.writeFile(outputPath, content, 'utf-8');
console.log(`\n✅ Written mock data to: ${outputPath}`);
}

// Summary
console.log('\n📊 Summary:');
console.log('- Date types: Generated algorithmically');
console.log(`- Deadline distances: ${deadlineDistances ? 'Fetched from API' : 'Not available'}`);
console.log(`- Project schema: ${projectSchema ? 'Fetched from API' : 'Not available'}`);

if (!deadlineDistances || !projectSchema) {
console.log('\n💡 Tip: Start the backend server and set KAAVAPINO_API_TOKEN to fetch live data');
}

} catch (error) {
console.error('\n❌ Error:', error.message);
process.exit(1);
}
}

main();
Loading