├── Staticfile ├── pages ├── home.md ├── 2nd-term-ending.html ├── 1st-term-ending.html ├── 1-1-hiring-needs.html └── projected-hiring-needs.html ├── .gitignore ├── assets ├── img │ └── us_seal.png ├── css │ └── main.css └── js │ └── main.js ├── Gemfile ├── manifest.yml ├── _config.yml ├── _data ├── header.yml ├── navigation.yml └── footer.yml ├── _layouts └── landing.html ├── CONTRIBUTING.md ├── Gemfile.lock ├── LICENSE.md └── README.md /Staticfile: -------------------------------------------------------------------------------- 1 | root: _site 2 | -------------------------------------------------------------------------------- /pages/home.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Home 3 | permalink: / 4 | layout: landing 5 | --- 6 | 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | _site/ 2 | .sass-cache/ 3 | .jekyll-metadata 4 | .DS_Store 5 | Staticfile.auth 6 | *.json 7 | -------------------------------------------------------------------------------- /assets/img/us_seal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18F/18f-capacity-planning/master/assets/img/us_seal.png -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem 'jekyll' 4 | gem 'uswds-jekyll', :git => 'https://github.com/18F/uswds-jekyll.git' 5 | -------------------------------------------------------------------------------- /manifest.yml: -------------------------------------------------------------------------------- 1 | --- 2 | applications: 3 | - name: 18f-capacity-planning 4 | memory: 64M 5 | buildpack: https://github.com/cloudfoundry/staticfile-buildpack.git 6 | env: 7 | FORCE_HTTPS: true 8 | 9 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | title: 18F Capacity Planning 2 | 3 | theme: uswds-jekyll 4 | 5 | styles: 6 | - /assets/uswds/css/uswds.min.css 7 | - /assets/css/main.css 8 | 9 | scripts: 10 | - src: /assets/uswds/js/uswds.min.js 11 | async: true 12 | - src: /assets/js/main.js 13 | async: true 14 | -------------------------------------------------------------------------------- /_data/header.yml: -------------------------------------------------------------------------------- 1 | # This is the configuration for the site header. 2 | 3 | # Uncomment this statement (by removing the leading '# ') to set the 4 | # header title differently from the site's title (as defined in 5 | # _config.yml). 6 | # title: Header title 7 | 8 | primary: 9 | # this is a key into _data/navigation.yml 10 | links: primary 11 | 12 | secondary: 13 | # this is a key into _data/navigation.yml 14 | links: secondary 15 | 16 | # to enable search, change this to an object with 'action' and 17 | # 'param' keys, e.g. 18 | # 19 | # search: 20 | # action: /search/ 21 | # param: q 22 | search: false 23 | -------------------------------------------------------------------------------- /_data/navigation.yml: -------------------------------------------------------------------------------- 1 | primary: 2 | - text: 1st Term Ending 3 | href: /1st-term-ending/ 4 | - text: 2nd Term Ending 5 | href: /2nd-term-ending/ 6 | - text: 1:1 Hiring Needs 7 | href: /1-1-hiring-needs/ 8 | - text: Projected Hiring Needs 9 | href: /projected-hiring-needs/ 10 | 11 | 12 | footer: 13 | - text: Documentation 14 | href: /docs/ 15 | - text: Demo link one 16 | href: /one/ 17 | - text: Demo link two 18 | href: /two/ 19 | 20 | secondary: [] 21 | 22 | docs: 23 | - text: Documentation 24 | href: /docs/ 25 | - text: Installation 26 | href: /docs/install/ 27 | - text: Upgrading 28 | href: /docs/upgrade/ 29 | - text: Help 30 | href: /docs/help/ 31 | -------------------------------------------------------------------------------- /assets/css/main.css: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | /* explicitly hide the tab panel content so all of them show if JS isn't enabled */ 4 | .hidden { 5 | display: none; 6 | } 7 | 8 | .tabs__tab { 9 | margin: 0; 10 | padding: 0 1.1rem 0.5rem 1rem; 11 | border-right: 1px solid #5b616b; 12 | text-align: left; 13 | font-size: 2rem; 14 | } 15 | 16 | .tabs__tab:first-child { 17 | padding-left: 0; 18 | } 19 | 20 | .tabs__tab:last-child { 21 | border-right: none; 22 | } 23 | 24 | .tabs__tab.active { 25 | font-weight: 700; 26 | } 27 | 28 | a.tabs__tab:visited { 29 | color: #0071bc; 30 | } 31 | 32 | a.tabs__tab:visited:hover, 33 | a.tabs__tab:visited:active { 34 | color: #205493; 35 | } 36 | 37 | .select-year-label { 38 | font-weight: 700; 39 | font-size: 2rem; 40 | } 41 | -------------------------------------------------------------------------------- /_data/footer.yml: -------------------------------------------------------------------------------- 1 | # Whether to show the "Return to top" link; can also be 2 | # configured as an object with 'text' and 'href' properties. 3 | top: true 4 | 5 | # Which links to show at the top of the footer. 6 | # This can key into _data/navigation.yml or a list of link objects 7 | # with 'text' and 'href' properties. 8 | links: footer 9 | 10 | # The optional heading for the footer. 11 | heading: Name of agency 12 | 13 | # An array of agency logos to show, side by side, in the lower left 14 | # of the footer on large screens. 15 | logos: 16 | - src: /assets/img/us_seal.png 17 | alt: Your agency name 18 | 19 | contact: 20 | heading: Contact us 21 | address: | 22 | This is formatted as **markdown**. 23 | 24 | Lines separated by an empty line will each be marked up as paragraphs. 25 | 26 | You can make links [like this](https://usa.gov). 27 | -------------------------------------------------------------------------------- /_layouts/landing.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: base 3 | --- 4 | 5 |
6 |
7 |
8 | {{ content }} 9 |
10 |
11 |
12 | 44 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Welcome! 2 | 3 | We're so glad you're thinking about contributing to an 18F open source project! If you're unsure about anything, just ask -- or submit the issue or pull request anyway. The worst that can happen is you'll be politely asked to change something. We love all friendly contributions. 4 | 5 | We want to ensure a welcoming environment for all of our projects. Our staff follow the [18F Code of Conduct](https://github.com/18F/code-of-conduct/blob/master/code-of-conduct.md) and all contributors should do the same. 6 | 7 | We encourage you to read this project's CONTRIBUTING policy (you are here), its [LICENSE](LICENSE.md), and its [README](README.md). 8 | 9 | If you have any questions or want to read more, check out the [18F Open Source Policy GitHub repository](https://github.com/18f/open-source-policy), or just [shoot us an email](mailto:18f@gsa.gov). 10 | 11 | ## Public domain 12 | 13 | This project is in the public domain within the United States, and 14 | copyright and related rights in the work worldwide are waived through 15 | the [CC0 1.0 Universal public domain dedication](https://creativecommons.org/publicdomain/zero/1.0/). 16 | 17 | All contributions to this project will be released under the CC0 18 | dedication. By submitting a pull request, you are agreeing to comply 19 | with this waiver of copyright interest. 20 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GIT 2 | remote: https://github.com/18F/uswds-jekyll.git 3 | revision: 1a8a3d68729282992249d55b25fe67d6ac0e9c6d 4 | specs: 5 | uswds-jekyll (1.1.1) 6 | jekyll (~> 3.4) 7 | 8 | GEM 9 | remote: https://rubygems.org/ 10 | specs: 11 | addressable (2.5.1) 12 | public_suffix (~> 2.0, >= 2.0.2) 13 | colorator (1.1.0) 14 | ffi (1.9.18) 15 | forwardable-extended (2.6.0) 16 | jekyll (3.4.3) 17 | addressable (~> 2.4) 18 | colorator (~> 1.0) 19 | jekyll-sass-converter (~> 1.0) 20 | jekyll-watch (~> 1.1) 21 | kramdown (~> 1.3) 22 | liquid (~> 3.0) 23 | mercenary (~> 0.3.3) 24 | pathutil (~> 0.9) 25 | rouge (~> 1.7) 26 | safe_yaml (~> 1.0) 27 | jekyll-sass-converter (1.5.0) 28 | sass (~> 3.4) 29 | jekyll-watch (1.5.0) 30 | listen (~> 3.0, < 3.1) 31 | kramdown (1.13.2) 32 | liquid (3.0.6) 33 | listen (3.0.8) 34 | rb-fsevent (~> 0.9, >= 0.9.4) 35 | rb-inotify (~> 0.9, >= 0.9.7) 36 | mercenary (0.3.6) 37 | pathutil (0.14.0) 38 | forwardable-extended (~> 2.6) 39 | public_suffix (2.0.5) 40 | rb-fsevent (0.9.8) 41 | rb-inotify (0.9.8) 42 | ffi (>= 0.5.0) 43 | rouge (1.11.1) 44 | safe_yaml (1.0.4) 45 | sass (3.4.23) 46 | 47 | PLATFORMS 48 | ruby 49 | 50 | DEPENDENCIES 51 | jekyll 52 | uswds-jekyll! 53 | 54 | BUNDLED WITH 55 | 1.14.6 56 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | As a work of the United States government, this project is in the 2 | public domain within the United States. 3 | 4 | Additionally, we waive copyright and related rights in the work 5 | worldwide through the CC0 1.0 Universal public domain dedication. 6 | 7 | ## CC0 1.0 Universal summary 8 | 9 | This is a human-readable summary of the [Legal Code (read the full text)](https://creativecommons.org/publicdomain/zero/1.0/legalcode). 10 | 11 | ### No copyright 12 | 13 | The person who associated a work with this deed has dedicated the work to 14 | the public domain by waiving all rights to the work worldwide 15 | under copyright law, including all related and neighboring rights, to the 16 | extent allowed by law. 17 | 18 | You can copy, modify, distribute and perform the work, even for commercial 19 | purposes, all without asking permission. 20 | 21 | ### Other information 22 | 23 | In no way are the patent or trademark rights of any person affected by CC0, 24 | nor are the rights that other persons may have in the work or in how the 25 | work is used, such as publicity or privacy rights. 26 | 27 | Unless expressly stated otherwise, the person who associated a work with 28 | this deed makes no warranties about the work, and disclaims liability for 29 | all uses of the work, to the fullest extent permitted by applicable law. 30 | When using or citing the work, you should not imply endorsement by the 31 | author or the affirmer. 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 18F Capacity Planning Tool 2 | 3 | This is a prototype of how 18F could get a view into employee turnover and therefore develop a plan for consistent staffing levels. 4 | 5 | ## Updating 6 | 7 | This site is hosted on cloud.gov. Before you push updates to it, contact Heather for the `Staticfile` that powers the password protection. *If you deploy without the Staticfile, the password protection will be automatically disabled.* 8 | 9 | To push new updates, first [log in to Cloud Foundry]. 10 | 11 | Target the org/space: `cf target -o sandbox-gsa -s heather.battaglia`. 12 | 13 | Push the app: `cf push 18f-capacity-planning` 14 | 15 | Note: The site is powered with a `roster.json` file containing the information of every current 18F employee. This file should never be committed (it is in the `.gitignore`); only pushed to cloud.gov. 16 | 17 | ## The template 18 | 19 | This is a Federalist site template that incorporates the [U.S. Web Design 20 | Standards] [Jekyll theme]. 21 | 22 | View the [theme documentation] for more info on available [layouts] and 23 | [customization] options. 24 | 25 | [log in to Cloud Foundry]: https://cloud.gov/docs/getting-started/setup/#quick-reference 26 | [U.S. Web Design Standards]: https://standards.usa.gov 27 | [Jekyll theme]: https://jekyllrb.com/docs/themes/ 28 | [theme documentation]: https://github.com/18F/jekyll-uswds/#readme 29 | [layouts]: https://github.com/18F/jekyll-uswds/#layouts 30 | [customization]: https://github.com/18F/jekyll-uswds/#customization 31 | -------------------------------------------------------------------------------- /pages/2nd-term-ending.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: 2nd Term Ending 3 | permalink: /2nd-term-ending/ 4 | layout: landing 5 | --- 6 | 7 | {% assign monthnames = 'Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec' | split: ' ' %} 8 | {% assign monthvals = '01 02 03 04 05 06 07 08 09 10 11 12' | split: ' ' %} 9 | 10 | {% assign year = '2017' %} 11 | {% assign term2 = site.data.roster | sort: "term_end_date" | where: "term", "Term 2" | where: "exit_date", "" %} 12 | {% assign years = term2 | group_by_exp: 'teammate', 'teammate.term_end_date | slice: 0,4' | sort: 'name' %} 13 | 14 |

{{ page.title }}

15 |

Select calendar year:

16 |
17 | {% for year in years %} 18 | {{ year.name }} 19 | {% endfor %} 20 |
21 | 22 | {% for year in years %} 23 | {% assign months = year.items | group_by_exp: 'teammate', 'teammate.term_end_date | slice: 5,2' | sort: 'name' %} 24 | {% assign teams = year.items | group_by_exp: 'teammate', 'teammate.team' %} 25 |
26 |

{{ year.name }}

27 |
Filter By Team
28 | 34 | 35 | 36 | 37 | {% for month in monthnames %} 38 | 39 | {% endfor %} 40 | 41 | 42 | 43 | 44 | 45 | {% assign yearly_total = 0 %} 46 | {% for month in monthnames %} 47 | {% assign pattern = year.name | append: '-' | append: monthvals[forloop.index0] %} 48 | {% assign where = 'teammate.term_end_date contains "%"' | replace: '%', pattern %} 49 | {% assign items = year.items | where_exp: 'teammate', where %} 50 | 51 | {% assign yearly_total = yearly_total | plus: items.size %} 52 | {% endfor %} 53 | 54 | 55 | 56 |
{{ month }}Total
{{ items.size }}{{ yearly_total }}
57 | 58 | {% for group in months %} 59 | {% if group.name == '01' %} 60 | {% assign month = 'January' %} 61 | {% elsif group.name == '02' %} 62 | {% assign month = 'February' %} 63 | {% elsif group.name == '03' %} 64 | {% assign month = 'March' %} 65 | {% elsif group.name == '04' %} 66 | {% assign month = 'April' %} 67 | {% elsif group.name == '05' %} 68 | {% assign month = 'May' %} 69 | {% elsif group.name == '06' %} 70 | {% assign month = 'June' %} 71 | {% elsif group.name == '07' %} 72 | {% assign month = 'July' %} 73 | {% elsif group.name == '08' %} 74 | {% assign month = 'August' %} 75 | {% elsif group.name == '09' %} 76 | {% assign month = 'September' %} 77 | {% elsif group.name == '10' %} 78 | {% assign month = 'October' %} 79 | {% elsif group.name == '11' %} 80 | {% assign month = 'November' %} 81 | {% elsif group.name == '12' %} 82 | {% assign month = 'December' %} 83 | {% endif %} 84 | 85 |
86 |

{{ month }} {{ year.name }} - {{ group.size }} Billable Employees Ending 2nd Term

87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | {% for teammate in group.items %} 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | {% endfor %} 107 | 108 |
NameChapterRoleBillable statusEnd of term date
{{ teammate.email }}{{ teammate.team }}{{ teammate.role }}{{ teammate.billable_status }}{{ teammate.term_end_date | date: "%b %d, %Y"}}
109 |
110 | {% endfor %} 111 |
112 | {% endfor %} 113 | -------------------------------------------------------------------------------- /pages/1st-term-ending.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: 1st Term Ending 3 | permalink: /1st-term-ending/ 4 | layout: landing 5 | --- 6 | {% assign monthnames = 'Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec' | split: ' ' %} 7 | {% assign monthvals = '01 02 03 04 05 06 07 08 09 10 11 12' | split: ' ' %} 8 | 9 | {% assign year = '2017' %} 10 | {% assign term1 = site.data.roster | sort: "term_end_date" | where: "term", "Term 1" | where: "exit_date", "" %} 11 | {% assign years = term1 | group_by_exp: 'teammate', 'teammate.term_end_date | slice: 0,4' | sort: 'name' %} 12 | 13 |

{{ page.title }}

14 |

Select calendar year:

15 |
16 | {% for year in years %} 17 | {{ year.name }} 18 | {% endfor %} 19 |
20 | {% for year in years %} 21 | {% assign months = year.items | group_by_exp: 'teammate', 'teammate.term_end_date | slice: 5,2' | sort: 'name' %} 22 | {% assign teams = year.items | group_by_exp: 'teammate', 'teammate.team' %} 23 |
24 |

{{ year.name }}

25 |
Filter By Team
26 | 32 | 33 | 34 | 35 | {% for month in monthnames %} 36 | 37 | {% endfor %} 38 | 39 | 40 | 41 | 42 | 43 | {% assign yearly_total = 0 %} 44 | {% for month in monthnames %} 45 | {% assign pattern = year.name | append: '-' | append: monthvals[forloop.index0] %} 46 | {% assign where = 'teammate.term_end_date contains "%"' | replace: '%', pattern %} 47 | {% assign items = year.items | where_exp: 'teammate', where %} 48 | 49 | {% assign yearly_total = yearly_total | plus: items.size %} 50 | {% endfor %} 51 | 52 | 53 | 54 |
{{ month }}Total
{{ items.size }}{{ yearly_total }}
55 | 56 | {% for group in months %} 57 | {% if group.name == '01' %} 58 | {% assign month = 'January' %} 59 | {% elsif group.name == '02' %} 60 | {% assign month = 'February' %} 61 | {% elsif group.name == '03' %} 62 | {% assign month = 'March' %} 63 | {% elsif group.name == '04' %} 64 | {% assign month = 'April' %} 65 | {% elsif group.name == '05' %} 66 | {% assign month = 'May' %} 67 | {% elsif group.name == '06' %} 68 | {% assign month = 'June' %} 69 | {% elsif group.name == '07' %} 70 | {% assign month = 'July' %} 71 | {% elsif group.name == '08' %} 72 | {% assign month = 'August' %} 73 | {% elsif group.name == '09' %} 74 | {% assign month = 'September' %} 75 | {% elsif group.name == '10' %} 76 | {% assign month = 'October' %} 77 | {% elsif group.name == '11' %} 78 | {% assign month = 'November' %} 79 | {% elsif group.name == '12' %} 80 | {% assign month = 'December' %} 81 | {% endif %} 82 | 83 |
84 |

{{ month }} {{ year.name }} - {{ group.size }} Billable Employees Ending 1st Term

85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | {% for teammate in group.items %} 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | {% endfor %} 105 | 106 |
NameChapterRoleBillable statusEnd of term date
{{ teammate.email | downcase }}{{ teammate.team }}{{ teammate.role }}{{ teammate.billable_status }}{{ teammate.term_end_date | date: "%b %d, %Y"}}
107 |
108 | {% endfor %} 109 |
110 | {% endfor %} 111 | -------------------------------------------------------------------------------- /assets/js/main.js: -------------------------------------------------------------------------------- 1 | function initTabs(year){ 2 | var tabs = document.getElementsByClassName("tabs__tab"); 3 | for (var i=0; i