diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4a9211cd8b6041..785d1be09efa8a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -76,6 +76,10 @@ jobs: run: | ! fgrep -R 'lt;blockquote' _site + - name: Ensure no poorly rendered FAQs + run: | + ! fgrep -R 'box_type:' _site/ + - name: Ensure no poorly indented code blocks run: | bundle exec ruby bin/check-indent.rb diff --git a/_plugins/feeds.rb b/_plugins/feeds.rb index bcfa54ac3a113e..beb53acdcac7d6 100644 --- a/_plugins/feeds.rb +++ b/_plugins/feeds.rb @@ -2,6 +2,7 @@ require './_plugins/jekyll-topic-filter' require './_plugins/gtn' +require 'json' # TODO: move into a lib somewhere. def collapse_date_pretty(event) @@ -27,74 +28,107 @@ def collapse_date_pretty(event) end end -def generate_topic_feeds(site) - TopicFilter.list_topics(site).each do |topic| - feed_path = File.join(site.dest, 'topics', topic, 'feed.xml') - Jekyll.logger.info "[GTN/Feeds] Generating feed for #{topic}" - - topic_pages = site.pages - .select { |x| x.path =~ %r{^\.?/?topics/#{topic}} } - .select { |x| x.path =~ %r{(tutorial.md|slides.html|faqs/.*.md)} } - .reject { |x| x.path =~ /index.md/ } - .reject { |x| x.data.fetch('draft', '').to_s == 'true' } - .reject { |x| x.url =~ /slides-plain.html/ } - .reject { |x| File.symlink?(x.path) } # Remove symlinks to other faqs/tutorials - .uniq(&:path) - .sort_by { |page| Gtn::PublicationTimes.obtain_time(page.path) } - .reverse - - if topic_pages.empty? - Jekyll.logger.warn "No pages for #{topic}" - next - else - Jekyll.logger.debug "Found #{topic_pages.length} pages for #{topic}" - end +def serialise(site, feed_path, builder) + # The builder won't let you add a processing instruction, so we have to + # serialise it to a string and then parse it again. Ridiculous. + if ! Dir.exist?(File.dirname(feed_path)) + FileUtils.mkdir_p(File.dirname(feed_path)) + end - builder = Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml| - # Set stylesheet - xml.feed(xmlns: 'http://www.w3.org/2005/Atom') do - # Set generator also needs a URI attribute - xml.generator('Jekyll', uri: 'https://jekyllrb.com/') - xml.link(href: "#{site.config['url']}#{site.baseurl}/topics/#{topic}/feed.xml", rel: 'self') - xml.updated(Gtn::ModificationTimes.obtain_time(topic_pages.first.path).to_datetime.rfc3339) - xml.id("#{site.config['url']}#{site.baseurl}/topics/#{topic}/feed.xml") - topic_title = site.data[topic]['title'] - xml.title("Galaxy Training Network - #{topic_title}") - xml.subtitle("Recently added tutorials, slides, and FAQs in the #{topic} topic") - - topic_pages.each do |page| - page_type = if page.path =~ %r{faqs/.*.md} - 'faq' - else - page.path.split('/').last.split('.').first - end + # First the 'default' with explanatory portion + finalised = Nokogiri::XML builder.to_xml + pi = Nokogiri::XML::ProcessingInstruction.new( + finalised, 'xml-stylesheet', + %(type="text/xml" href="#{site.config['url']}#{site.baseurl}/feed.xslt.xml") + ) + finalised.root.add_previous_sibling pi + File.write(feed_path, finalised.to_xml) + + # Then the widget-compatible version with a more minimal representation: + finalised = Nokogiri::XML builder.to_xml + pi = Nokogiri::XML::ProcessingInstruction.new( + finalised, 'xml-stylesheet', + %(type="text/xml" href="#{site.config['url']}#{site.baseurl}/feed-widget.xslt.xml") + ) + finalised.root.add_previous_sibling pi + File.write(feed_path.gsub(/\.xml$/, '.w.xml'), finalised.to_xml) +end + +def markdownify(site, text) + site.find_converter_instance( + Jekyll::Converters::Markdown + ).convert(text.to_s) +end + +ICON_FOR = { + 'contributors' => 'πŸ§‘β€πŸ«', + 'funders' => 'πŸ’°', + 'organisations' => '🏒', + 'events' => 'πŸ“…', + 'tutorials' => 'πŸ“š', + 'slides' => 'πŸ–ΌοΈ', + 'news' => 'πŸ“°', + 'faqs' => '❓', + 'workflows' => 'πŸ› οΈ', +} + +def generate_topic_feeds(site, topic, bucket) + mats = bucket.select { |x| x[3].include?(topic) } + feed_path = File.join(site.dest, 'topics', topic, 'feed.xml') + Jekyll.logger.info "[GTN/Feeds] Generating feed for #{topic} (#{mats.length} items)" + + builder = Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml| + # Set stylesheet + xml.feed(xmlns: 'http://www.w3.org/2005/Atom') do + # Set generator also needs a URI attribute + xml.generator('Jekyll', uri: 'https://jekyllrb.com/') + xml.link(href: "#{site.config['url']}#{site.baseurl}/topics/#{topic}/feed.xml", rel: 'self') + xml.link(rel: 'alternate', href: "#{site.config['url']}#{site.baseurl}/topics/#{topic}/") + xml.updated(mats.first[0].rfc3339) + xml.id("#{site.config['url']}#{site.baseurl}/topics/#{topic}/feed.xml") + topic_title = site.data[topic]['title'] + xml.title("#{topic_title}") + xml.subtitle("Recently added tutorials, slides, FAQs, and events in the #{topic} topic") + xml.logo("#{site.config['url']}#{site.baseurl}/assets/images/GTN-60px.png") + + mats.each do |time, group, page, tags| + xml.entry do + xml.title(ICON_FOR[group] + " " +page.data['title']) + link = "#{site.config['url']}#{site.baseurl}#{page.url}" + xml.link(href: link) + # Our links are (mostly) stable + xml.id(link) + + # This is a feed of only NEW tutorials, so we only include publication times. + # xml.published(Gtn::PublicationTimes.obtain_time(page.path).to_datetime.rfc3339) + xml.updated(time.rfc3339) + + tags.each do |tag| + xml.category(term: tag) + end - xml.entry do - xml.title(page.data['title']) - link = "#{site.config['url']}#{site.baseurl}#{page.url}" - xml.link(href: link) - # Our links are stable - xml.id(link) - - # This is a feed of only NEW tutorials, so we only include publication times. - # xml.published(Gtn::PublicationTimes.obtain_time(page.path).to_datetime.rfc3339) - xml.updated(Gtn::PublicationTimes.obtain_time(page.path).to_datetime.rfc3339) - - # xml.path(page.path) - xml.category(term: "new #{page_type}") - # xml.content(page.content, type: "html") - xml.summary(page.content.strip.split("\n").first, type: 'html') - - Gtn::Contributors.get_authors(page.data).each do |c| - xml.author do - xml.name(Gtn::Contributors.fetch_name(site, c)) + if page.data.key? 'description' + xml.summary(page.data['description']) + else + md = page.content[0..page.content.index("\n")].strip + html = markdownify(site, md) + text = Nokogiri::HTML(html).text + xml.summary(text) + end + + Gtn::Contributors.get_authors(page.data).each do |c| + xml.author do + xml.name(Gtn::Contributors.fetch_name(site, c, warn:false)) + if c !~ / / xml.uri("#{site.config['url']}#{site.baseurl}/hall-of-fame/#{c}/") end end + end - Gtn::Contributors.get_non_authors(page.data).each do |c| - xml.contributor do - xml.name(Gtn::Contributors.fetch_name(site, c)) + Gtn::Contributors.get_non_authors(page.data).each do |c| + xml.contributor do + xml.name(Gtn::Contributors.fetch_name(site, c, warn:false)) + if c !~ / / xml.uri("#{site.config['url']}#{site.baseurl}/hall-of-fame/#{c}/") end end @@ -102,19 +136,9 @@ def generate_topic_feeds(site) end end end - - # The builder won't let you add a processing instruction, so we have to - # serialise it to a string and then parse it again. Ridiculous. - finalised = Nokogiri::XML builder.to_xml - pi = Nokogiri::XML::ProcessingInstruction.new( - finalised, 'xml-stylesheet', - %(type="text/xml" href="#{site.config['url']}#{site.baseurl}/feed.xslt.xml") - ) - finalised.root.add_previous_sibling pi - File.write(feed_path, finalised.to_xml) end - nil + serialise(site, feed_path, builder) end def generate_tag_topic_feeds(_site) @@ -128,6 +152,8 @@ def all_date_sorted_materials(site) events = site.pages.select { |x| x['layout'] == 'event' || x['layout'] == 'event-external' } materials = TopicFilter.list_all_materials(site).reject { |k, _v| k['draft'] } news = site.posts.select { |x| x['layout'] == 'news' } + faqs = site.pages.select { |x| x['layout'] == 'faq' } + workflows = Dir.glob('topics/**/*.ga') bucket = events.map do |e| [Gtn::PublicationTimes.obtain_time(e.path).to_datetime, 'events', e, ['event'] + e.data.fetch('tags', [])] @@ -139,7 +165,7 @@ def all_date_sorted_materials(site) [Gtn::PublicationTimes.obtain_time(t.path).to_datetime, 'tutorials', t, tags] end - bucket += m.fetch('ref_tutorials', []).reject { |s| s.url =~ /-plain.html/ }.map do |s| + bucket += m.fetch('ref_slides', []).reject { |s| s.url =~ /-plain.html/ }.map do |s| [Gtn::PublicationTimes.obtain_time(s.path).to_datetime, 'slides', s, tags] end end @@ -148,6 +174,42 @@ def all_date_sorted_materials(site) [n.date.to_datetime, 'news', n, ['news'] + n.data.fetch('tags', [])] end + bucket += faqs.map do |n| + tag = Gtn::PublicationTimes.clean_path(n.path).split('/')[1] + [Gtn::PublicationTimes.obtain_time(n.path).to_datetime, 'faqs', n, ['faqs', tag]] + end + + bucket += workflows.map do |n| + tag = Gtn::PublicationTimes.clean_path(n).split('/')[1] + wf_data = JSON.parse(File.read(n)) + obj = Hash.new + obj['__path'] = n + obj['title'] = wf_data['name'] + obj['description'] = wf_data['annotation'] + obj['tags'] = wf_data['tags'] + obj['contributors'] = wf_data.fetch('creator', []).map do |c| + p ">> #{c}" + matched = site.data['contributors'].select{|k, v| v.fetch('orcid', nil) == c.fetch('identifier', false)}.first + if matched + matched[0] + else + c['name'] + end + end + # Fake a page. + def obj.data + self + end + def obj.path + self['__path'] + end + def obj.url + '/' + self['__path'][0..self['__path'].rindex('/')] + end + + [Gtn::PublicationTimes.obtain_time(n).to_datetime, 'workflows', obj, ['workflows', tag] + obj['tags']] + end + bucket += site.data['contributors'].map do |k, v| [DateTime.parse("#{v['joined']}-01"), 'contributors', k, ['contributor']] end @@ -236,22 +298,24 @@ def generate_matrix_feed(site, mats, group_by: 'day', filter_by: nil) # Set generator also needs a URI attribute xml.generator('Jekyll', uri: 'https://jekyllrb.com/') xml.link(href: "#{site.config['url']}#{site.baseurl}/#{path}", rel: 'self') + xml.link(href: "#{site.config['url']}#{site.baseurl}/", rel: 'alternate') # convert '2024-01-01' to date xml.updated(DateTime.now.rfc3339) xml.id("#{site.config['url']}#{site.baseurl}/#{path}") - title_parts = ['GTN', filter_title, "#{lookup[group_by]} Updates"].compact + title_parts = [filter_title, "#{lookup[group_by]} Updates"].compact xml.title(title_parts.join(' β€” ')) - xml.subtitle('An RSS feed with the latest materials, events, news in the GTN.') + xml.subtitle('The latest materials, events, news in the GTN.') + xml.logo("#{site.config['url']}#{site.baseurl}/assets/images/GTN-60px.png") bucket.each do |date, parts| xml.entry do case group_by when 'day' - title = "GTN #{lookup[group_by]} updates for #{date.strftime('%B %d, %Y')}" + title = "#{date.strftime('%B %d, %Y')}" when 'week' - title = "GTN #{lookup[group_by]} updates for #{date.strftime('W%W, %Y')}" + title = "#{date.strftime('W%W, %Y')}" when 'month' - title = "GTN #{lookup[group_by]} updates for #{date.strftime('%B %Y')}" + title = "#{date.strftime('%B %Y')}" end xml.title(title) # Our IDs should be stable @@ -266,38 +330,30 @@ def generate_matrix_feed(site, mats, group_by: 'day', filter_by: nil) xml.div(xmlns: 'http://www.w3.org/1999/xhtml') do # xml.h4 title - icon_for = { - 'contributors' => 'πŸ§‘β€πŸ«', - 'funders' => 'πŸ’°', - 'organisations' => '🏒', - 'events' => 'πŸ“…', - 'tutorials' => 'πŸ“š', - 'slides' => 'πŸ–ΌοΈ', - 'news' => 'πŸ“°', - } - - prio = { - 'news' => 0, - 'events' => 1, - 'contributors' => 4, - 'funders' => 5, - 'organisations' => 6, - 'tutorials' => 2, - 'slides' => 3, - } - - parts.group_by { |x| x[1] }.sort_by { |x| prio[x[1]] }.each do |type, items| - xml.h4 "#{icon_for[type]} #{type.capitalize}" + prio = [ + 'news', + 'events', + 'tutorials', + 'slides', + 'faqs', + 'workflows', + 'contributors', + 'funders', + 'organisations' + ].map.with_index { |x, i| [x, i] }.to_h + + parts.group_by { |x| x[1] }.sort_by { |x| prio[x[0]] }.each do |type, items| + xml.h4 "#{ICON_FOR[type]} #{type.capitalize}" if items.length.positive? xml.ul do items.each do |date, _type, page, _tags| xml.li do if page.is_a?(String) - href = "#{site.config['url']}#{site.config['baseurl']}/hall-of-fame/#{page}/" + href = "#{site.config['url']}#{site.config['baseurl']}/hall-of-fame/#{page}/?utm_source=matrix&utm_medium=newsbot&utm_campaign=matrix-news" text = "@#{page}" else text = page.data['title'] - href = "#{site.config['url']}#{site.config['baseurl']}#{page.url}" + href = "#{site.config['url']}#{site.config['baseurl']}#{page.url}?utm_source=matrix&utm_medium=newsbot&utm_campaign=matrix-news" end if group_by != 'day' text += " (#{date.strftime('%B %d, %Y')})" @@ -322,21 +378,14 @@ def generate_matrix_feed(site, mats, group_by: 'day', filter_by: nil) xml.author do xml.name('GTN') xml.uri("#{site.config['url']}#{site.baseurl}/hall-of-fame/") + xml.email('galaxytrainingnetwork@gmail.com') end end end end end - # The builder won't let you add a processing instruction, so we have to - # serialise it to a string and then parse it again. Ridiculous. - finalised = Nokogiri::XML builder.to_xml - pi = Nokogiri::XML::ProcessingInstruction.new( - finalised, 'xml-stylesheet', - %(type="text/xml" href="#{site.config['url']}#{site.baseurl}/feed-html.xslt.xml") - ) - finalised.root.add_previous_sibling pi - File.write(feed_path, finalised.to_xml) + serialise(site, feed_path, builder) end def generate_event_feeds(site) @@ -363,10 +412,12 @@ def generate_event_feeds(site) # Set generator also needs a URI attribute xml.generator('Jekyll', uri: 'https://jekyllrb.com/') xml.link(href: "#{site.config['url']}#{site.baseurl}/events/feed.xml", rel: 'self') + xml.link(href: "#{site.config['url']}#{site.baseurl}/events/", rel: 'alternate') xml.updated(updated.to_datetime.rfc3339) xml.id("#{site.config['url']}#{site.baseurl}/events/feed.xml") - xml.title('Galaxy Training Network - Events') + xml.title('Events') xml.subtitle('Events in the Inter-Galactic Network') + xml.logo("#{site.config['url']}#{site.baseurl}/assets/images/GTN-60px.png") events.each do |page| xml.entry do @@ -400,7 +451,7 @@ def generate_event_feeds(site) Gtn::Contributors.get_organisers(page.data).each do |c| xml.author do - xml.name(Gtn::Contributors.fetch_name(site, c)) + xml.name(Gtn::Contributors.fetch_name(site, c, warn:false)) xml.uri("#{site.config['url']}#{site.baseurl}/hall-of-fame/#{c}/") if page.data['contact_email'] xml.email(page.data['contact_email']) @@ -410,7 +461,7 @@ def generate_event_feeds(site) Gtn::Contributors.get_instructors(page.data).each do |c| xml.contributor do - xml.name(Gtn::Contributors.fetch_name(site, c)) + xml.name(Gtn::Contributors.fetch_name(site, c, warn:false)) xml.uri("#{site.config['url']}#{site.baseurl}/hall-of-fame/#{c}/") end end @@ -419,30 +470,24 @@ def generate_event_feeds(site) end end - # The builder won't let you add a processing instruction, so we have to - # serialise it to a string and then parse it again. Ridiculous. - finalised = Nokogiri::XML builder.to_xml - pi = Nokogiri::XML::ProcessingInstruction.new( - finalised, 'xml-stylesheet', - %(type="text/xml" href="#{site.config['url']}#{site.baseurl}/feed.xslt.xml") - ) - finalised.root.add_previous_sibling pi - File.write(feed_path, finalised.to_xml) + serialise(site, feed_path, builder) end # Basically like `PageWithoutAFile` Jekyll::Hooks.register :site, :post_write do |site| if Jekyll.env == 'production' - generate_topic_feeds(site) generate_event_feeds(site) bucket = all_date_sorted_materials(site) bucket.freeze + + TopicFilter.list_topics(site).each do |topic| + generate_topic_feeds(site, topic, bucket) + generate_matrix_feed(site, bucket, group_by: 'month', filter_by: topic) + end + generate_matrix_feed(site, bucket, group_by: 'day') generate_matrix_feed(site, bucket, group_by: 'week') generate_matrix_feed(site, bucket, group_by: 'month') - generate_matrix_feed(site, bucket, group_by: 'month', filter_by: 'single-cell') - generate_matrix_feed(site, bucket, group_by: 'month', filter_by: 'genome-annotation') - generate_matrix_feed(site, bucket, group_by: 'month', filter_by: 'one-health') end end diff --git a/_plugins/gtn/contributors.rb b/_plugins/gtn/contributors.rb index ff36fb0b572f04..393c005c63d9d2 100644 --- a/_plugins/gtn/contributors.rb +++ b/_plugins/gtn/contributors.rb @@ -118,7 +118,7 @@ def self._load_file(site, category) # Returns: # +Hash+ of contributor information # +String+ type of contributor (e.g. 'contributor', 'organisation', 'funder') - def self.fetch(site, c) + def self.fetch(site, c, warn: false) if _load_file(site, 'contributors').key?(c) return ['contributor', site.data['contributors'][c]] elsif _load_file(site, 'organisations').key?(c) @@ -126,7 +126,9 @@ def self.fetch(site, c) elsif _load_file(site, 'funders').key?(c) return ['funder', site.data['funders'][c]] else - Jekyll.logger.warn "Contributor #{c} not found" + if ! warn + Jekyll.logger.warn "Contributor #{c} not found" + end end ['contributor', { 'name' => c }] @@ -150,8 +152,8 @@ def self.fetch_contributor(site, c) # +c+:: +String+ of contributor ID # Returns: # +String+ of contributor name - def self.fetch_name(site, c) - fetch(site, c)[1].fetch('name', c) + def self.fetch_name(site, c, warn: false) + fetch(site, c, warn: warn)[1].fetch('name', c) end ## diff --git a/_plugins/gtn/mod.rb b/_plugins/gtn/mod.rb index 9176690171c5be..63f9cab9e66417 100644 --- a/_plugins/gtn/mod.rb +++ b/_plugins/gtn/mod.rb @@ -136,7 +136,7 @@ def self.init_cache .map { |x| x.split("\n\n") } .select { |x| x.length > 1 } .each do |date, files| - files.split("\n").grep(/\.(md|html)$/).each do |f| + files.split("\n").grep(/\.(md|html|ga)$/).each do |f| modification_type, path = f.split("\t") if modification_type == 'A' # Chase the renames. diff --git a/_plugins/jekyll-topic-filter.rb b/_plugins/jekyll-topic-filter.rb index c999b810d8020e..52c41351a83202 100644 --- a/_plugins/jekyll-topic-filter.rb +++ b/_plugins/jekyll-topic-filter.rb @@ -199,6 +199,9 @@ def self.list_materials_structured(site, topic_name) # Returns: # +Hash+:: The tutorial material def self.fetch_tutorial_material(site, topic_name, tutorial_name) + if topic_name.nil? + return nil + end fill_cache(site) if site.data['cache_topic_filter'][topic_name].nil? Jekyll.logger.warn "Cannot fetch tutorial material for #{topic_name}" diff --git a/assets/images/GTN-400px.png b/assets/images/GTN-400px.png new file mode 100644 index 00000000000000..cd6c32ce02cdb2 Binary files /dev/null and b/assets/images/GTN-400px.png differ diff --git a/assets/images/GTN-60px.png b/assets/images/GTN-60px.png index 111a7ad358035f..2162f76fab5268 100644 Binary files a/assets/images/GTN-60px.png and b/assets/images/GTN-60px.png differ diff --git a/faqs/galaxy/account_create.md b/faqs/galaxy/account_create.md index 5742ea71e7fee9..2df20758f13f21 100644 --- a/faqs/galaxy/account_create.md +++ b/faqs/galaxy/account_create.md @@ -1,7 +1,5 @@ --- -redirect_from: -- /faqs/galaxy/galaxy_creating_an_account -- /faqs/galaxy/creating_account +redirect_from: [/faqs/galaxy/galaxy_creating_an_account, /faqs/galaxy/creating_account] title: How do I create an account on a public Galaxy instance? area: account layout: faq diff --git a/faqs/galaxy/workflows_run_trs.md b/faqs/galaxy/workflows_run_trs.md index b26f624049f9f6..aab3997280d81e 100644 --- a/faqs/galaxy/workflows_run_trs.md +++ b/faqs/galaxy/workflows_run_trs.md @@ -11,7 +11,6 @@ examples: Incredibly generic box that does not tell you which workflow to import: {} Importing a QC workflow: {path: "topics/assembly/tutorials/largegenome/workflows/Galaxy-Workflow-Data_QC.ga", title:"Galaxy Workflow Data QC" } Importing a pre-treatments workflow: {path: "topics/proteomics/tutorials/metaproteomics/workflows/workflow.ga", title:"Pretreatments"} - --- {% if include.path %} diff --git a/feed-html.xslt.xml b/feed-html.xslt.xml deleted file mode 100644 index 8fbb3735d7bfdc..00000000000000 --- a/feed-html.xslt.xml +++ /dev/null @@ -1,106 +0,0 @@ - - - - - - - - RSS/Atom Feed β€’ <xsl:value-of select="atom:feed/atom:title"/> - - - -
-
-

This is a web feed, also known as an RSS feed. Subscribe by copying the URL from the address bar into your newsreader app.

-
-
-
- -
-
-

Recent Items

- -
- - -
- - -

(Feed Preview)

- -

-
- -

This RSS feed provides the latest posts from the Galaxy Training Network! - - - - - - Visit Website → - - -

- -

What is an RSS feed?

-

An RSS feed is a data format that contains the latest content from a website, blog, or podcast. You can use feeds to subscribe to websites and get the latest content in one place.

-
    -
  • Feeds put you in control. Unlike social media apps, there is no algorithm deciding what you see or read. You always get the latest content from the creators you care about.
  • -
  • Feed are private by design. No one owns web feeds, so no one is harvesting your personal information and profiting by selling it to advertisers.
  • -
  • Feeds are spam-proof. Had enough? Easy, just unsubscribe from the feed.
  • -
-

All you need to do to get started is to add the URL (web address) for this feed to a special app called a newsreader. Visit About Feeds to get started with newsreaders and subscribing. It’s free.

-
- - -
-

- - - - - - -

-

- - - - - - , - - -

- - -

- -

-
- -

- -

-
- - Published:
- Tags: - - - - , - - -
-
-
- -
diff --git a/feed-widget.xslt.xml b/feed-widget.xslt.xml new file mode 100644 index 00000000000000..ced48812006209 --- /dev/null +++ b/feed-widget.xslt.xml @@ -0,0 +1,159 @@ + + + + + + + + <xsl:value-of select="atom:feed/atom:title"/> β€’ GTN News + + + + + + + + + +
+
+

+ + + + + + +

+

+
+ + gtn logo + + + + + +
+
+ +
+ + + +
+ + +
+ + + true + false + + +

+ + + + + + + + + + + + + +

+ + +

+ By: + + + + + , + + +

+
+ +

+ + + + + + + + +

+ + Published:
+ Tags: + + + + , + + +
+ + + + + + + + + + +
+
+
diff --git a/feed.xslt.xml b/feed.xslt.xml index 5f064996631513..9a8056ef451265 100644 --- a/feed.xslt.xml +++ b/feed.xslt.xml @@ -10,67 +10,114 @@ - RSS/Atom Feed β€’ <xsl:value-of select="atom:feed/atom:title"/> + <xsl:value-of select="atom:feed/atom:title"/> β€’ GTN News + + + + + + -
+

This is a web feed, also known as an RSS feed. Subscribe by copying the URL from the address bar into your newsreader app.

-
-
- -
-
+
+

+ + + + + + +

+

+
+

What is an RSS feed?

+

An RSS feed is a data format that contains the latest content from a website, blog, or podcast. You can use feeds to subscribe to websites and get the latest content in one place.

+ +

All you need to do to get started is to add the URL (web address) for this feed to a special app called a newsreader. Visit About Feeds to get started with newsreaders and subscribing. It’s free.

+ +

Recent Items

-
+ + - -

(Feed Preview)

- -

-
- -

This RSS feed provides the latest posts from the Galaxy Training Network! - - - - - - Visit Website → - - -

- -

What is an RSS feed?

-

An RSS feed is a data format that contains the latest content from a website, blog, or podcast. You can use feeds to subscribe to websites and get the latest content in one place.

- -

All you need to do to get started is to add the URL (web address) for this feed to a special app called a newsreader. Visit About Feeds to get started with newsreaders and subscribing. It’s free.

-
-
+ + + true + false + +

- - - - - - + + + + + + + + + + + + +

+ +

- + By: @@ -79,8 +126,17 @@

-

- + + +

+ + + + + + + +

Published:
@@ -94,5 +150,4 @@
- diff --git a/feeds/index.md b/feeds/index.md new file mode 100644 index 00000000000000..7e31c9886607b9 --- /dev/null +++ b/feeds/index.md @@ -0,0 +1,84 @@ +--- +layout: page +title: GTN Feeds +--- + +We offer a wide range of [RSS feeds]({{ site.baseurl }}/news/2024/06/04/gtn-standards-rss.html) to help you keep up to date with the latest training materials and events. You can subscribe to these feeds in your favourite RSS reader, or embed them in your own website. + +## Feed Directory + +{% if jekyll.environment == "production" %} + +- [GTN News]({{ site.baseurl }}/feed.xml) +- [GTN Events]({{ site.baseurl }}/events/feed.xml) +- Topic Feeds, which include all *new* tutorials, slides, FAQs, workflows, and events. + - [Single Cell]({{ site.baseurl }}/topics/single-cell/feed.xml) + - [Admin Training]({{ site.baseurl }}/topics/admin/feed.xml) + - ...and every other topic +- Monthly/Weekly/Daily Rollups, which include all *new* tutorials, slides, workflows, FAQs, events, and contributors. + - [GTN Monthly]({{ site.baseurl }}/feeds/matrix-month.xml) + - [GTN Weekly]({{ site.baseurl }}/feeds/matrix-week.xml) + - [GTN Daily]({{ site.baseurl }}/feeds/matrix-day.xml) +- Per-tag Monthly Rollups + - [Single Cell Month]({{ site.baseurl }}/feeds/single-cell-month.xml) + - [One Health Month]({{ site.baseurl }}/feeds/one-health-month.xml) + - ...and every other topic / tag based topic (i.e. topics linked from the home page) + +{% else %} +GTN Feed listing is not available in development mode. (This is done so we don't need to generate the feed pages or add an exception to our URL checking, while keeping CI times fast.) +{% endif %} + +## Embedding Feeds + +Any[^1] of the above feeds can be embedded anywhere you like. Simply replace +`.xml` with `.w.xml` in the URL and it'll produce a feed preview that is more + +[^1]: minus the main news feed currently as that is produced by a third party plugin +amenable to embedding. + + + + + +```html + + + +``` + +### Rollups + +We created these 'rollups' based on the bot that posted updates to our Matrix channel, they are simply digests of recent changes to help keep community members up to date. + + + + + +These can be embedded like so: + +```html + + + +``` + +### Community Specific Rollups + +Some rollups were created for individual communities: + + + + +These are easily embedded, note the `.w.xml` ending, indicating a widget. (This is simply used to provide an alternate XSLT that renders better in an `iframe`. + +```html + + +``` + +### Differences between feeds + +Having two feeds with the same data might seem a bit odd but we have two separate user stories we want to address: + +- **Feed Reader**: This is the feed you'd subscribe to in your feed reader, and more importantly, the sort of feed that you'd send to someone else if they were curious how to follow updates to the GTN. +- **Feed Widget**: This is the feed you'd embed in your website, or in a widget on a page. It's designed to be more visually appealing and easier to read in a small space. diff --git a/news/_posts/2024-06-04-gtn-standards-rss.md b/news/_posts/2024-06-04-gtn-standards-rss.md index 796aeb950c3eac..b12ce98489dc6f 100644 --- a/news/_posts/2024-06-04-gtn-standards-rss.md +++ b/news/_posts/2024-06-04-gtn-standards-rss.md @@ -15,6 +15,8 @@ contributions: The GTN loves leveraging existing standards for both old and new purposes. One of our favourite standards that we adhere to is providing an RSS/Atom news feed for sharing news and events and updates! +**Update 2024 Jun 18**: We've added a new home page for all of our feeds: [GTN feeds home]({% link feeds/index.md %}) + ## Why RSS/Atom? RSS feeds provide access to the latest news and updates from websites. They are a great way to keep up to date with your favourite websites without having to visit them every day, and without having to sign up for a mailing list or social media account. You can subscribe to feeds using a [feed reader](https://aboutfeeds.com/), which will automatically check for updates and display them for you. diff --git a/topics/assembly/tutorials/vgp_genome_assembly/faqs/dataset_upload_fastqsanger_via_urls.md b/topics/assembly/tutorials/vgp_genome_assembly/faqs/dataset_upload_fastqsanger_via_urls.md index 5459d9706e583e..f6aec5282950db 100644 --- a/topics/assembly/tutorials/vgp_genome_assembly/faqs/dataset_upload_fastqsanger_via_urls.md +++ b/topics/assembly/tutorials/vgp_genome_assembly/faqs/dataset_upload_fastqsanger_via_urls.md @@ -4,8 +4,7 @@ area: data upload box_type: tip layout: faq contributors: [nekrut] -redirect_from: - - /faqs/galaxy/dataset_upload_fastqsanger_via_urls +redirect_from: [/faqs/galaxy/dataset_upload_fastqsanger_via_urls] --- Uploading `fastqsanger` or `fastqsanger.gz` datasets via URL. diff --git a/topics/contributing/tutorials/create-new-tutorial-content/faqs/tutorial_from_workflows.md b/topics/contributing/tutorials/create-new-tutorial-content/faqs/tutorial_from_workflows.md index b99e72ddef2b8c..a0170b334298ea 100644 --- a/topics/contributing/tutorials/create-new-tutorial-content/faqs/tutorial_from_workflows.md +++ b/topics/contributing/tutorials/create-new-tutorial-content/faqs/tutorial_from_workflows.md @@ -4,8 +4,7 @@ area: markdown box_type: tip layout: faq contributors: [shiltemann] -redirect_from: -- /topics/contributing/faqs/tutorial_from_workflows +redirect_from: [/topics/contributing/faqs/tutorial_from_workflows] --- There are two ways to do this: diff --git a/topics/microbiome/faqs/kraken.md b/topics/microbiome/faqs/kraken.md index 012ea790fbb916..9344e09dbe1025 100644 --- a/topics/microbiome/faqs/kraken.md +++ b/topics/microbiome/faqs/kraken.md @@ -4,8 +4,7 @@ area: format box_type: details layout: faq contributors: [bebatut] -redirect_from: -- /topics/metagenomics/faqs/kraken +redirect_from: [/topics/metagenomics/faqs/kraken] --- In the $$k$$-mer approach for taxonomy classification, we use a database containing DNA sequences of genomes whose taxonomy we already know. On a computer, the genome sequences are broken into short pieces of length $$k$$ (called $$k$$-mers), usually 30bp. @@ -16,4 +15,4 @@ In the $$k$$-mer approach for taxonomy classification, we use a database contain __Kraken2__ uses a compact hash table, a probabilistic data structure that allows for faster queries and lower memory requirements. It applies a spaced seed mask of _s_ spaces to the minimizer and calculates a compact hash code, which is then used as a search query in its compact hash table; the lowest common ancestor (LCA) taxon associated with the compact hash code is then assigned to the k-mer. -You can find more information about the __Kraken2__ algorithm in the paper [_Improved metagenomic analysis with Kraken 2_](https://genomebiology.biomedcentral.com/articles/10.1186/s13059-019-1891-0). \ No newline at end of file +You can find more information about the __Kraken2__ algorithm in the paper [_Improved metagenomic analysis with Kraken 2_](https://genomebiology.biomedcentral.com/articles/10.1186/s13059-019-1891-0). diff --git a/topics/microbiome/faqs/taxon.md b/topics/microbiome/faqs/taxon.md index 8e215737a19d8b..f87423e2eced20 100644 --- a/topics/microbiome/faqs/taxon.md +++ b/topics/microbiome/faqs/taxon.md @@ -4,8 +4,7 @@ area: format box_type: details layout: faq contributors: [bebatut] -redirect_from: -- /topics/metagenomics/faqs/taxon +redirect_from: [/topics/metagenomics/faqs/taxon] --- Taxonomy is the method used to naming, defining (circumscribing) and classifying groups of biological organisms based on shared characteristics such as morphological characteristics, phylogenetic characteristics, DNA data, etc. It is founded on the concept that the similarities descend from a common evolutionary ancestor. diff --git a/topics/microbiome/tutorials/mothur-miseq-sop/faqs/input_not_found.md b/topics/microbiome/tutorials/mothur-miseq-sop/faqs/input_not_found.md index d3a7fba9d72516..5a93c6f41b5b46 100644 --- a/topics/microbiome/tutorials/mothur-miseq-sop/faqs/input_not_found.md +++ b/topics/microbiome/tutorials/mothur-miseq-sop/faqs/input_not_found.md @@ -3,10 +3,7 @@ title: The input for a tool is not listed in the dropdown box_type: tip layout: faq contributors: [shiltemann] -redirect_from: - - /topics/metagenomics/tutorials/mothur-miseq-sop/faqs/input_not_found - - /topics/metagenomics/tutorials/mothur-miseq-sop-short/faqs/input_not_found - +redirect_from: [/topics/metagenomics/tutorials/mothur-miseq-sop/faqs/input_not_found, /topics/metagenomics/tutorials/mothur-miseq-sop-short/faqs/input_not_found] --- This tutorial uses collections, some tools will require collections as input (e.g. Taxonomy-to-Krona). To select a collection as in put to a file, click on the {% icon param-collection %} **Dataset collection** button in front of the input parameter you want to supply the collection to. diff --git a/topics/proteomics/tutorials/metaproteomics/faqs/comparing_measurement.md b/topics/proteomics/tutorials/metaproteomics/faqs/comparing_measurement.md index 680e8bb8899fb6..e9d5fb84a9c59a 100644 --- a/topics/proteomics/tutorials/metaproteomics/faqs/comparing_measurement.md +++ b/topics/proteomics/tutorials/metaproteomics/faqs/comparing_measurement.md @@ -3,8 +3,7 @@ title: How does one compare metaproteomics measurements from two experimental co box_type: tip layout: faq contributors: [millen2223] -redirect_from: - - /topics/proteomics/faqs/comparing_measurement +redirect_from: [/topics/proteomics/faqs/comparing_measurement] --- For comparing taxonomy composition or functional content of two conditions in metaproteomics or metatranscriptomics studies, users are recommended to use metaQuantome. GTN tutorials for metaQuantome are available [in the proteomics topic.]({% link topics/proteomics/index.md %}) diff --git a/topics/single-cell/tutorials/scrna-scanpy-pbmc3k/faqs/anndata_not_working.md b/topics/single-cell/tutorials/scrna-scanpy-pbmc3k/faqs/anndata_not_working.md index 102192fbe69cbc..3e1bcada14cd02 100644 --- a/topics/single-cell/tutorials/scrna-scanpy-pbmc3k/faqs/anndata_not_working.md +++ b/topics/single-cell/tutorials/scrna-scanpy-pbmc3k/faqs/anndata_not_working.md @@ -3,8 +3,7 @@ title: AnnData Import/ AnnData Manipulate not working? box_type: tip layout: faq contributors: [nomadscientist, mtekman] -redirect_from: - - /topics/transcriptomics/tutorials/scrna-scanpy-pbmc3k/faqs/anndata_not_working +redirect_from: [/topics/transcriptomics/tutorials/scrna-scanpy-pbmc3k/faqs/anndata_not_working] --- This is a known issue, please do not use version `0.7.4` of the tool, and use version `0.6.2` instead. The Inspect AnnData tool should work fine however. diff --git a/topics/single-cell/tutorials/scrna-umis/faqs/protocol.md b/topics/single-cell/tutorials/scrna-umis/faqs/protocol.md index 082def51038ba4..6aa4062a079e17 100644 --- a/topics/single-cell/tutorials/scrna-umis/faqs/protocol.md +++ b/topics/single-cell/tutorials/scrna-umis/faqs/protocol.md @@ -3,8 +3,7 @@ title: How do I know what protocol my data was sequenced with? layout: faq box_type: question contributors: [nomadscientist,mtekman] -redirect_from: - - /topics/transcriptomics/tutorials/scrna-umis/faqs/protocol +redirect_from: [/topics/transcriptomics/tutorials/scrna-umis/faqs/protocol] --- If you have 10x data, then you just need to count the length of the R1 reads to guess the Chromium version (see [this tutorial]({% link topics/single-cell/tutorials/scrna-preprocessing-tenx/tutorial.md %})). For other types of data, you must know the protocol in advance, and even then you must also know the multiplexing strategy and the list of expected (whitelisted) barcodes. The whitelist may vary from sequencing lab to sequencing lab, so always ask the wetlab people how the FASTQ data was generated.