-
-
Notifications
You must be signed in to change notification settings - Fork 11
Automate jobs board with schema validation #360
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 6 commits
937757a
b941db1
bf8c2c5
d6f7765
c6f022f
3980ea3
3e6b9d6
5859815
542e662
2d0361c
96237a1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -24,6 +24,17 @@ repos: | |||||
| - id: ruff | ||||||
| args: ["--fix", "--show-fixes"] | ||||||
|
|
||||||
| # Jobs board validation (schema-based) | ||||||
| - repo: https://github.com/python-jsonschema/check-jsonschema | ||||||
| rev: 0.33.3 | ||||||
|
||||||
| rev: 0.33.3 | |
| rev: 0.36.0 |
Is there a reason for using 0.33.3 instead of the latest release available? https://github.com/python-jsonschema/check-jsonschema
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed, used the latest version
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It looks like the code in this file was generated with AI. While we are okay with the use of AI-written code, we consider it your responsibility to thoroughly review it and address any potential mistakes. Could you please remove the comments indicative of AI and remove the redundant CSS rules from here? Also, these styles will apply to the entire website, so we must ensure that they affect only the jobs page.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. addressed and applied the requested clean up and scoping |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -44,3 +44,57 @@ content-container class */ | |
| .news-container, .hero-container { | ||
| width: 100%; | ||
| } | ||
|
|
||
| /* Admonitions | ||
|
|
||
| Rely on the theme's admonition styling. Only apply minimal readability fixes | ||
| so content remains accessible in dark mode across themes. | ||
| */ | ||
| .adm { opacity: 1; } | ||
| .adm a { text-decoration: underline; } | ||
|
|
||
| @media (prefers-color-scheme: dark) { | ||
| /* Ensure admonitions stay readable even if the theme uses light backgrounds */ | ||
| .article .adm, .article .adm *, | ||
| .content .adm, .content .adm *, | ||
| .markdown .adm, .markdown .adm * { | ||
| color: var(--text, #f1f5f9) !important; | ||
| } | ||
| .adm a { color: var(--primary, #9ae6b4) !important; } | ||
| /* Provide a gentle dark surface without hardcoding brand colors */ | ||
| .adm { background: var(--surface-2, rgba(255,255,255,0.06)) !important; } | ||
| } | ||
|
Comment on lines
56
to
61
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. addressed, removed !important and used selector specificity as advised |
||
|
|
||
| /* Jobs board styles | ||
|
|
||
| Use theme variables where available and avoid hardcoded colors. | ||
| */ | ||
| .job-card { | ||
| border: 1px solid var(--border, rgba(0,0,0,0.15)); | ||
| padding: 1rem; | ||
| border-radius: 6px; | ||
| margin: 1rem 0; | ||
| background: var(--surface, transparent); | ||
| } | ||
| .job-card__header { display: flex; justify-content: space-between; align-items: baseline; gap: .5rem; } | ||
| .job-card__title { margin: 0; font-size: 1.15rem; } | ||
| .job-card__entity { color: var(--text-muted, inherit); font-weight: 600; } | ||
| .job-card__meta, .job-card__dates { display: flex; flex-wrap: wrap; gap: .5rem .5rem; margin: .5rem 0; } | ||
| /* Make badges robust against missing flex-gap support and theme overrides */ | ||
| .job-badge { | ||
| display: inline-flex; | ||
| align-items: center; | ||
| background: var(--surface-2, rgba(0,0,0,0.04)); | ||
| border: 1px solid var(--border, rgba(0,0,0,0.15)); | ||
| padding: .15rem .4rem; | ||
| border-radius: 999px; | ||
| font-size: .85rem; | ||
| color: var(--text, inherit); | ||
| margin-right: .5rem; /* fallback spacing if gap isn't honored */ | ||
| margin-bottom: .5rem; /* wrap spacing */ | ||
| } | ||
| .job-card__dates span { margin-right: .75rem; } | ||
| .job-card__description { margin: .5rem 0; color: inherit; line-height: 1.55; } | ||
| .job-card__description ul, .job-card__description ol { margin: .5rem 0 .5rem 1.25rem; } | ||
| .job-card__apply .button { display: inline-block; } | ||
| .job-card--archived { opacity: .85; } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,10 +4,14 @@ title: "PyBaMM" # site title | |
| theme: scientific-python-hugo-theme | ||
| relativeURLs: true | ||
| DefaultContentLanguage: en | ||
| disableKinds: ["term", "taxonomy"] | ||
| disableKinds: ["term", "taxonomy", "404"] | ||
| enableEmoji: true | ||
| enableInlineShortcodes: true | ||
|
|
||
| # Suppress legacy GetJSON errors originating from theme code | ||
| ignoreLogs: | ||
| - error-remote-getjson | ||
|
|
||
|
||
| markup: | ||
| highlight: | ||
| noClasses: true | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,34 +4,13 @@ shortcutDepth: 0 | |
| summary: "Current job openings related to PyBaMM and battery modeling" | ||
| --- | ||
|
|
||
| Welcome to the PyBaMM Jobs Board! Here you can find current job openings related to PyBaMM and battery modeling. If you're interested in contributing to the future of battery simulation and modeling, check out the opportunities below. | ||
| Welcome to the PyBaMM Jobs Board! This page is generated from simple YAML files under data/jobs/. | ||
|
||
|
|
||
| ### Ionworks Open Position | ||
|
|
||
| **Location:** Remote (US- or UK-based) | ||
| </br> | ||
| **Type:** Full-time | ||
|
|
||
| Ionworks is always interested in connecting with talented individuals in the field of battery modeling and simulation. While we may not have specific positions open at the moment, we welcome expressions of interest from potential candidates who are passionate about advancing battery technology. | ||
|
|
||
| **Areas of Interest:** | ||
|
|
||
| - Battery modeling and simulation | ||
| - Software development for scientific applications | ||
|
|
||
| **Ideal Background:** | ||
|
|
||
| - Advanced degree (Masters or higher) in a relevant field (e.g., Chemical Engineering, Applied Mathematics, Physics) | ||
| - Experience with battery modeling software, preferably including PyBaMM | ||
| - Proficiency in Python programming | ||
| - Strong analytical and problem-solving skills | ||
| - Excellent communication and collaboration abilities | ||
|
|
||
| If you're excited about the prospect of contributing to cutting-edge battery simulation projects and shaping the future of energy storage technology, we encourage you to reach out. Your expression of interest will be kept on file for future opportunities that may arise. | ||
| {{< admonition tip >}} | ||
| To post a job, open a PR adding a file under data/jobs/ using the template at data/jobs/_TEMPLATE.yaml. See instructions below. | ||
| {{< /admonition >}} | ||
|
|
||
| <div style="border: 2px solid #000; text-align: center; padding: 10px; margin: 20px auto; max-width: 300px; background-color: #3776AB;"> | ||
| <a href="mailto:hr@ionworks.com?subject=Ionworks%20open%20position%20(from%20PyBaMM%20jobs%20board)" class="button" style="color: white;">Express Interest</a> | ||
| </div> | ||
| {{< jobs-list >}} | ||
|
|
||
| --- | ||
|
|
||
|
|
@@ -48,13 +27,14 @@ Do you have an open position in battery modeling or simulation? By posting in th | |
| - Increase visibility within the PyBaMM community and broader battery modeling ecosystem | ||
| - Support the open-source PyBaMM project and its community | ||
|
|
||
| Jobs can be posted by companies, research institutions, or individuals looking to hire for positions related to battery modeling and simulation. All fees collected for job postings will be used to support the development and maintenance of PyBaMM. | ||
| Jobs can be posted by companies, research institutions, or individuals looking to hire for positions related to battery modeling and simulation. | ||
|
|
||
| ### How to Post a Job | ||
|
|
||
| 1. [Email us](mailto:pybamm@pybamm.org) the job description (preferably as an editable document) or open a pull request adding your post. | ||
| 2. Make the payment through [this link](https://app.hubspot.com/payments/purchase/hscs_lIGxEAJy1ZF1nSDuOswBBtgYJ2lqdM7yi40DttGAC8TMh9c8BUIptnqJAYMmllfq). | ||
| 3. Optionally, add a **suggested donation** to further support PyBaMM’s mission. | ||
| 1. Open a pull request adding a YAML file at data/jobs/ following data/jobs/_TEMPLATE.yaml. | ||
| 2. Ensure dates are in YYYY-MM-DD and include a working https:// or http:// URL. | ||
| 3. Optionally, also [email us](mailto:pybamm@pybamm.org) for visibility. | ||
| 4. If applicable, make a payment or donation as per our policy. | ||
|
||
|
|
||
| {{< admonition important >}} | ||
| For details, please review our [Terms & Conditions](/jobs-t-and-c/). | ||
|
|
||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's use the existing Ionworks example here and include it, instead of Example Company.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. addressed, replaced the example with Ionworks example |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| entity: Example Company | ||
| title: Battery Modeling Engineer (PyBaMM) | ||
| url: https://example.com/careers/battery-modeling-engineer-pybamm | ||
| percentTime: 100 | ||
| percentOSS: 50 | ||
| deadline: 2026-01-31 | ||
| expires: 2026-02-28 | ||
| location: Remote | ||
| tags: [full-time, modeling, PyBaMM, Python] | ||
| description: | | ||
| We are hiring a Battery Modeling Engineer to build physics-based models using PyBaMM. | ||
|
|
||
| Responsibilities: | ||
| - Develop and validate battery models using PyBaMM | ||
| - Support model parameterisation, simulation, and analysis | ||
| - Contribute improvements back to PyBaMM where appropriate | ||
|
|
||
| Requirements: | ||
| - Strong Python experience | ||
| - Familiarity with battery modelling and numerical methods |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| { | ||
| "$schema": "https://json-schema.org/draft/2020-12/schema", | ||
| "title": "PyBaMM Jobs Board Posting", | ||
| "type": "object", | ||
| "additionalProperties": false, | ||
| "required": [ | ||
| "entity", | ||
| "title", | ||
| "url", | ||
| "percentTime", | ||
| "percentOSS", | ||
| "deadline", | ||
| "expires", | ||
| "location", | ||
| "description" | ||
| ], | ||
| "properties": { | ||
| "entity": { | ||
| "type": "string", | ||
| "minLength": 1 | ||
| }, | ||
| "title": { | ||
| "type": "string", | ||
| "minLength": 1 | ||
| }, | ||
| "url": { | ||
| "type": "string", | ||
| "minLength": 1, | ||
| "pattern": "^https?://" | ||
| }, | ||
| "percentTime": { | ||
| "type": "integer", | ||
| "minimum": 1, | ||
| "maximum": 100 | ||
| }, | ||
| "percentOSS": { | ||
| "type": "integer", | ||
| "minimum": 0, | ||
| "maximum": 100 | ||
| }, | ||
| "deadline": { | ||
| "type": "string", | ||
| "pattern": "^\\d{4}-\\d{2}-\\d{2}$" | ||
| }, | ||
| "expires": { | ||
| "type": "string", | ||
| "pattern": "^\\d{4}-\\d{2}-\\d{2}$" | ||
| }, | ||
| "author_date": { | ||
| "type": "string", | ||
| "pattern": "^\\d{4}-\\d{2}-\\d{2}$" | ||
| }, | ||
| "location": { | ||
| "type": "string", | ||
| "minLength": 1 | ||
| }, | ||
| "tags": { | ||
| "type": "array", | ||
| "items": { | ||
| "type": "string", | ||
| "minLength": 1 | ||
| }, | ||
| "uniqueItems": true | ||
| }, | ||
| "description": { | ||
| "type": "string", | ||
| "minLength": 1 | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| {{/* Renders a single job card. Expects dict with keys: job, now */}} | ||
| {{- $job := .job -}} | ||
| {{- $now := .now -}} | ||
| {{- $open := or (not $job.expires) (ge (time $job.expires) $now) -}} | ||
|
|
||
| <div class="job-card {{ if not $open }}job-card--archived{{ end }}"> | ||
| <div class="job-card__header"> | ||
| <h3 class="job-card__title">{{ $job.title }}</h3> | ||
| <div class="job-card__entity">{{ $job.entity }}</div> | ||
| </div> | ||
| <div class="job-card__meta"> | ||
| {{ with $job.location }}<span class="job-badge job-badge--location">{{ . }}</span>{{ end }} | ||
| {{ with $job.percentTime }}<span class="job-badge">{{ . }}% time</span>{{ end }} | ||
| {{ with $job.percentOSS }}<span class="job-badge">{{ . }}% OSS</span>{{ end }} | ||
| {{ with $job.tags }} | ||
| {{ range . }}<span class="job-badge job-badge--tag">{{ . }}</span>{{ end }} | ||
| {{ end }} | ||
| </div> | ||
| <div class="job-card__dates"> | ||
| {{ with $job.deadline }}<span>Deadline: {{ . }}</span>{{ end }} | ||
| {{ with $job.expires }}<span>Visible until: {{ . }}</span>{{ end }} | ||
| </div> | ||
| <div class="job-card__description"> | ||
| {{ with $job.description }}{{ . | markdownify }}{{ end }} | ||
| </div> | ||
| {{ with $job.url }} | ||
| <p class="job-card__apply"><a class="button" href="{{ . }}" rel="nofollow noopener" target="_blank">Apply / Learn more</a></p> | ||
| {{ end }} | ||
| </div> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| {{/* | ||
| Lists jobs from data/jobs. Splits into open and archived by expires date. | ||
| Sorts open by deadline asc; archived by expires desc. | ||
| */}} | ||
| {{- $now := now -}} | ||
| {{- $jobs := slice -}} | ||
|
|
||
| {{/* | ||
| Load only YAML postings from data/jobs/*.yaml. | ||
| Avoid reading data/jobs/schema.json (used only for validation). | ||
| */}} | ||
|
||
| {{- range (readDir "data/jobs") -}} | ||
| {{- if and (not .IsDir) (hasSuffix .Name ".yaml") (ne .Name "_TEMPLATE.yaml") -}} | ||
| {{- $path := printf "data/jobs/%s" .Name -}} | ||
| {{- $data := (readFile $path | transform.Unmarshal) -}} | ||
| {{- $key := replaceRE "\\.yaml$" "" .Name -}} | ||
| {{- $job := dict "key" $key | merge $data -}} | ||
| {{- $jobs = $jobs | append $job -}} | ||
| {{- end -}} | ||
| {{- end -}} | ||
|
|
||
| {{/* partition */}} | ||
| {{- $open := slice -}} | ||
| {{- $archived := slice -}} | ||
| {{- range $jobs -}} | ||
| {{- $exp := .expires -}} | ||
| {{- if or (not $exp) (ge (time $exp) $now) -}} | ||
| {{- $open = $open | append . -}} | ||
| {{- else -}} | ||
| {{- $archived = $archived | append . -}} | ||
| {{- end -}} | ||
| {{- end -}} | ||
|
Comment on lines
9
to
29
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this can be simplified – see https://stackoverflow.com/a/33233395 for an example?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. addressed. refactored the layouts/partials/jobs/list.html to simplify data loading using hugo’s built-in data mechanism, per the review suggestion |
||
|
|
||
| {{- $sortedOpen := sort $open "deadline" "asc" -}} | ||
|
|
||
| <h2 id="open-roles">Open roles</h2> | ||
| {{- if gt (len $sortedOpen) 0 -}} | ||
| {{- range $sortedOpen -}} | ||
| {{ partial "jobs/card.html" (dict "job" . "now" $now) }} | ||
| {{- end -}} | ||
| {{- else -}} | ||
| <p>No open roles at the moment.</p> | ||
| {{- end -}} | ||
|
|
||
| <hr/> | ||
|
|
||
| <details> | ||
| <summary><h2 id="archived-roles" style="display:inline">Archived roles</h2></summary> | ||
| {{- $sortedArchived := sort $archived "expires" "desc" -}} | ||
| {{- if gt (len $sortedArchived) 0 -}} | ||
| {{- range $sortedArchived -}} | ||
| {{ partial "jobs/card.html" (dict "job" . "now" $now) }} | ||
| {{- end -}} | ||
| {{- else -}} | ||
| <p>No archived roles yet.</p> | ||
| {{- end -}} | ||
| </details> | ||
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| {{/* Shortcode to render the jobs list from data/jobs */}} | ||
| {{ partial "jobs/list.html" . }} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code is self-explanatory, so this doesn't need a comment