Skip to content

Commit e1a6099

Browse files
committed
Merge branch 'feature/role-system-not-tagged'
2 parents edcc842 + 5cb2623 commit e1a6099

25 files changed

+1054
-106
lines changed

.eleventy.js

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,17 @@ module.exports = function (eleventyConfig) {
104104
return content;
105105
});
106106

107+
// Add UTF-8 BOM to CSV files for proper Excel encoding
108+
eleventyConfig.addTransform("csvUtf8Bom", function (content, outputPath) {
109+
if (outputPath && outputPath.endsWith(".csv")) {
110+
// For Excel compatibility, we need to ensure the content is properly encoded
111+
// Try a different approach with UTF-8 BOM and ensure content is UTF-8
112+
const utf8Bom = '\uFEFF'; // Use Unicode BOM character instead of bytes
113+
return utf8Bom + content;
114+
}
115+
return content;
116+
});
117+
107118
eleventyConfig.addFilter("localeMatch", function (collection) {
108119
const { locale } = this.ctx; // avoid retrieving it for each item
109120
return collection.filter((item) => item.data.locale === locale);
@@ -195,11 +206,65 @@ module.exports = function (eleventyConfig) {
195206
return changedPages; // Returning the changed URLs, titles, and locales for the template
196207
});
197208

209+
// Get the role keys that belong to a given group
210+
eleventyConfig.addFilter("roleKeysForGroup", function (groupKey, rolesData) {
211+
if (!groupKey || !rolesData || !rolesData.roles) return [];
212+
return Object.entries(rolesData.roles)
213+
.filter(([, meta]) => meta.group === groupKey)
214+
.map(([key]) => key);
215+
});
216+
217+
// Given a list of role keys, return all pages that match ANY of them
218+
eleventyConfig.addFilter("byAnyRole", function (collection, roleKeys) {
219+
if (!collection || !roleKeys || !roleKeys.length) return [];
220+
return collection.filter((item) => {
221+
const r = item.data.role;
222+
if (!r) return false;
223+
const arr = Array.isArray(r) ? r : [r];
224+
return arr.some((k) => roleKeys.includes(k));
225+
});
226+
});
227+
228+
// Collection of all pages that have at least one role
229+
eleventyConfig.addCollection("rolePages", (api) =>
230+
api.getAll().filter((item) => !!item.data.role)
231+
);
232+
233+
// Custom collection for role groups to work around pagination tag issues
234+
eleventyConfig.addCollection("roleGroup", (api) => {
235+
// Find all pages generated from the roles-group.njk template OR
236+
// pages with URLs matching role group patterns
237+
return api.getAll().filter((item) => {
238+
// Check if the page was generated from the roles-group template
239+
const fromRoleGroupTemplate = item.inputPath && item.inputPath.includes('roles-group.njk');
240+
241+
// Check if URL matches role group pattern (e.g., /en/roles/business/, /fr/roles/design/)
242+
const matchesRoleGroupPattern = item.url && item.url.match(/^\/(en|fr)\/roles\/(administration|author|business|design|development|testing)\/$/);
243+
244+
return fromRoleGroupTemplate || matchesRoleGroupPattern;
245+
});
246+
});
247+
198248
// Add custom Markdown filter for Nunjucks
199249
eleventyConfig.addNunjucksFilter("markdown", function (value) {
200250
return md.render(value);
201251
});
202252

253+
// Add split filter for Nunjucks
254+
eleventyConfig.addNunjucksFilter("split", function (str, separator) {
255+
if (typeof str !== 'string') return [];
256+
return str.split(separator || ' ');
257+
});
258+
259+
// Add wordCount filter for convenience
260+
eleventyConfig.addNunjucksFilter("wordCount", function (content) {
261+
if (!content) return 0;
262+
const text = typeof content === 'string' ? content : String(content);
263+
const stripped = stripHtml(text).result;
264+
const words = stripped.trim().split(/\s+/);
265+
return words.length === 1 && words[0] === '' ? 0 : words.length;
266+
});
267+
203268
let changedFilesMap = new Map();
204269
let changedFilePaths = new Set();
205270
let gitChangedUrls = [];
@@ -331,6 +396,26 @@ module.exports = function (eleventyConfig) {
331396
gitChangedUrls = [];
332397
});
333398

399+
// Add computed data for git creation dates
400+
eleventyConfig.addGlobalData("eleventyComputed", {
401+
gitCreated: (data) => {
402+
if (data.page && data.page.inputPath) {
403+
try {
404+
const gitCommand = `git log --format="%ai" --reverse "${data.page.inputPath}" | head -1`;
405+
const result = execSync(gitCommand, { encoding: 'utf8' }).trim();
406+
407+
if (result) {
408+
return new Date(result);
409+
}
410+
} catch (error) {
411+
// Silently handle errors - some files might not have git history
412+
// console.error(`Error getting git creation date for ${data.page.inputPath}:`, error.message);
413+
}
414+
}
415+
return null;
416+
}
417+
});
418+
334419
// Ignore template files from being built
335420
eleventyConfig.ignores.add("src/pages/_template.md");
336421
eleventyConfig.ignores.add("src/links/_template.md");

src/_data/alerts.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ module.exports = {
2121
"Les liens qui ne fonctionnent que derrière le pare-feu du gouvernement du Canada sont marqués avec ",
2222
icon: "icône ",
2323
hiddenTextLink: "lien interne",
24+
25+
// Role content coming soon alert, appears on role pages when no content is tagged with that role
26+
roleContentComingSoon: "Bientôt disponible !",
27+
roleContentComingSoonText: "Actuellement, aucun contenu n'a été assigné à ce rôle. Une fois que le contenu sera étiqueté avec ce rôle, il sera listé sur cette page.",
28+
roleContentComingSoonTextGroup: "Actuellement, aucun contenu n'a été assigné à ce rôle. Une fois que le contenu sera étiqueté avec ce rôle, il sera listé ici.",
2429
},
2530

2631
en: {
@@ -43,5 +48,10 @@ module.exports = {
4348
"Links that only work within the Government of Canada firewall are marked with ",
4449
icon: "icon ",
4550
hiddenTextLink: "internal link",
51+
52+
// Role content coming soon alert, appears on role pages when no content is tagged with that role
53+
roleContentComingSoon: "Coming soon!",
54+
roleContentComingSoonText: "Currently no content has been assigned to this role. Once content is tagged with this role, it will be listed on this page.",
55+
roleContentComingSoonTextGroup: "Currently no content has been assigned to this role. Once content is tagged with this role, it will be listed here.",
4656
},
4757
};

src/_data/groupPairsEn.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
module.exports = () => {
2+
const roles = require("./roles.js");
3+
return Object.entries(roles.groups.en).map(([key, name]) => {
4+
// Get all role keys that belong to this group
5+
const roleKeysInGroup = Object.entries(roles.roles)
6+
.filter(([, meta]) => meta.group === key)
7+
.map(([roleKey]) => roleKey);
8+
9+
// Get the translated labels for these roles
10+
const roleLabels = roleKeysInGroup.map(roleKey => roles.labels.en[roleKey]);
11+
12+
return [
13+
key,
14+
name,
15+
roles.descriptions.en[key],
16+
roleLabels
17+
];
18+
}).sort();
19+
};

src/_data/groupPairsFr.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
module.exports = () => {
2+
const roles = require("./roles.js");
3+
return Object.entries(roles.groups.fr).map(([key, name]) => {
4+
// Get all role keys that belong to this group
5+
const roleKeysInGroup = Object.entries(roles.roles)
6+
.filter(([, meta]) => meta.group === key)
7+
.map(([roleKey]) => roleKey);
8+
9+
// Get the translated labels for these roles
10+
const roleLabels = roleKeysInGroup.map(roleKey => roles.labels.fr[roleKey]);
11+
12+
return [
13+
key,
14+
name,
15+
roles.descriptions.fr[key],
16+
roleLabels
17+
];
18+
}).sort();
19+
};

src/_data/rolePairs.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Build an array of [roleKey, roleMeta] tuples from roles.roles
2+
module.exports = () => {
3+
const rolesData = require("./roles.js"); // same folder as this file
4+
// rolesData.roles is an object like { contentAuthoring: { group: "author" }, ... }
5+
return Object.entries(rolesData.roles).sort(([a], [b]) => a.localeCompare(b));
6+
};

0 commit comments

Comments
 (0)