<commit_before>import * as ko from 'knockout'
import * as io from 'socket.io-client'
import { Image, Container, ConciergeEvent, Stats } from './types'
import updateContainer from './update'

export {
  Image,
  Container,
}

const socket = io()

class StateManager {
  images = ko.observableArray<Image>([])
  containers = ko.observableArray<Container>([])
  hosts = ko.observableArray<Concierge.Host>([])
  concierges = ko.observableArray<Concierge.Concierge>([])
  registries = ko.observableArray<Concierge.Registry>([])
  applications = ko.observableArray<Concierge.Application>([])

  toasts = ko.observableArray<{ msg: string, cls: string, remove: () => void }>([])
  toast = {
    primary: (msg: string) => this.showToast('toast-primary', msg),
    error: (msg: string) => this.showToast('toast-error', msg),
    warn: (msg: string) => this.showToast('toast-warning', msg),
    success: (msg: string) => this.showToast('toast-success', msg)
  }

  constructor() {
    this.getContainers()
    this.getHosts()
    this.getImages()
    this.getApplications()

    setInterval(() => this.getContainers(), 5000)

    socket.on('stats', (event: ConciergeEvent) => {
      const container = this.containers().find(container => container.Id === event.name)
      if (!container) {
        return
      }

      const newContainer = updateContainer(container, event)
      this.containers.replace(container, newContainer)

    })
  }

  showToast = (cls: string, msg: string, duration: number = 5000) => {
    const toast = { msg, cls, remove: () => this.toasts.remove(toast) }
    this.toasts.push(toast)
    setTimeout(toast.remove, duration)
  }

  getContainers = () =>
    fetch('/api/hosts/containers')
      .then(res => res.json())
      .then(containers => {
        const seenContainers: string[] = []
        const stateContainers = this.containers()
        containers.forEach(container => {
          seenContainers.push(container.Id)
          const existing = stateContainers.find(c => c.Id === container.Id)
          if (existing) {
            const newContainer = { ...existing }
            newContainer.State = container.State
            newContainer.Status = container.Status
            newContainer.stats = existing.stats
            this.containers.replace(existing, newContainer)
            return
          }

          const stats: Stats = {
            cpu: '...',
            memory: '...',
            mbIn: '...',
            mbOut: '...'
          }

          container.stats = stats
          this.containers.push(container)
        })

        // Remove every unseen container as it's probably been deleted
        this.containers.remove(c => seenContainers.every(s => s !== c.Id))
      })

  getHosts = () => {
    fetch('/api/hosts')
      .then(res => res.json())
      .then(hosts => {
        this.hosts.destroyAll()
        this.hosts.push(...hosts)
      })
  }

  getImages = () => {
    fetch('/api/images')
      .then(res => res.json())
      .then(images => {
        this.images.destroyAll()

        for (const image of images) {
          image.name = getTag(image.RepoTags)
        }

        this.images.push(...images.filter(image => image.name !== undefined))
      })
  }

  getApplications = () => {
    fetch('/api/applications')
      .then(res => res.json())
      .then(applications => {
        this.applications.destroyAll()
        this.applications.push(...applications)
      })
  }
}

function getTag(tags: string[]) {
  const tag = tags.find(tag => tag !== '<none>:<none>')
  return tag
}

const state = new StateManager()

export default state<commit_msg>State: Handle images with no repo tags<commit_after>import * as ko from 'knockout'
import * as io from 'socket.io-client'
import { Image, Container, ConciergeEvent, Stats } from './types'
import updateContainer from './update'

export {
  Image,
  Container,
}

const socket = io()

class StateManager {
  images = ko.observableArray<Image>([])
  containers = ko.observableArray<Container>([])
  hosts = ko.observableArray<Concierge.Host>([])
  concierges = ko.observableArray<Concierge.Concierge>([])
  registries = ko.observableArray<Concierge.Registry>([])
  applications = ko.observableArray<Concierge.Application>([])

  toasts = ko.observableArray<{ msg: string, cls: string, remove: () => void }>([])
  toast = {
    primary: (msg: string) => this.showToast('toast-primary', msg),
    error: (msg: string) => this.showToast('toast-error', msg),
    warn: (msg: string) => this.showToast('toast-warning', msg),
    success: (msg: string) => this.showToast('toast-success', msg)
  }

  constructor() {
    this.getContainers()
    this.getHosts()
    this.getImages()
    this.getApplications()

    setInterval(() => this.getContainers(), 5000)

    socket.on('stats', (event: ConciergeEvent) => {
      const container = this.containers().find(container => container.Id === event.name)
      if (!container) {
        return
      }

      const newContainer = updateContainer(container, event)
      this.containers.replace(container, newContainer)

    })
  }

  showToast = (cls: string, msg: string, duration: number = 5000) => {
    const toast = { msg, cls, remove: () => this.toasts.remove(toast) }
    this.toasts.push(toast)
    setTimeout(toast.remove, duration)
  }

  getContainers = () =>
    fetch('/api/hosts/containers')
      .then(res => res.json())
      .then(containers => {
        const seenContainers: string[] = []
        const stateContainers = this.containers()
        containers.forEach(container => {
          seenContainers.push(container.Id)
          const existing = stateContainers.find(c => c.Id === container.Id)
          if (existing) {
            const newContainer = { ...existing }
            newContainer.State = container.State
            newContainer.Status = container.Status
            newContainer.stats = existing.stats
            this.containers.replace(existing, newContainer)
            return
          }

          const stats: Stats = {
            cpu: '...',
            memory: '...',
            mbIn: '...',
            mbOut: '...'
          }

          container.stats = stats
          this.containers.push(container)
        })

        // Remove every unseen container as it's probably been deleted
        this.containers.remove(c => seenContainers.every(s => s !== c.Id))
      })

  getHosts = () => {
    fetch('/api/hosts')
      .then(res => res.json())
      .then(hosts => {
        this.hosts.destroyAll()
        this.hosts.push(...hosts)
      })
  }

  getImages = () => {
    fetch('/api/images')
      .then(res => res.json())
      .then(images => {
        this.images.destroyAll()

        for (const image of images) {
          image.name = getTag(image.RepoTags || [])
        }

        this.images.push(...images.filter(image => image.name !== undefined))
      })
  }

  getApplications = () => {
    fetch('/api/applications')
      .then(res => res.json())
      .then(applications => {
        this.applications.destroyAll()
        this.applications.push(...applications)
      })
  }
}

function getTag(tags: string[]) {
  const tag = tags.find(tag => tag !== '<none>:<none>')
  return tag
}

const state = new StateManager()

export default state
{'fraction_non_alphanumeric': 0.15533580552121962, 'fraction_numerical': 0.002197500343359429, 'mean_word_length': 2.495919347095535, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 77, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1662061', 'n_tokens_mistral': 2242, 'n_tokens_neox': 2183, 'n_words': 433}