// SortDashboards sorts a slice of dashboards by a field.
971915
func SortDashboards(by string, ds []*Dashboard) {
	var sorter func(i, j int) bool
	switch by {
	case "CreatedAt":
		sorter = func(i, j int) bool {
			return ds[j].Meta.CreatedAt.After(ds[i].Meta.CreatedAt)
		}
	case "UpdatedAt":
		sorter = func(i, j int) bool {
			return ds[j].Meta.UpdatedAt.After(ds[i].Meta.UpdatedAt)
		}
	case "Name":
		sorter = func(i, j int) bool {
			return ds[i].Name < ds[j].Name
		}
	default:
		sorter = func(i, j int) bool {
			return ds[i].ID < ds[j].ID
		}
	}

	sort.Slice(ds, sorter)
}
581111
func (c *Client) DeleteDashboard(ctx context.Context, id platform.ID) error {
	return c.db.Update(func(tx *bolt.Tx) error {
		if pe := c.deleteDashboard(ctx, tx, id); pe != nil {
			return &platform.Error{
				Err: pe,
				Op:  getOp(platform.OpDeleteDashboard),
			}
		}
		return nil
	})
}
894056
func (ms *multiSorter) Sort(pods []*v1.Pod) {
	ms.pods = pods
	sort.Sort(ms)
}
1288527
func (c *Client) FindDashboardByID(ctx context.Context, id platform.ID) (*platform.Dashboard, error) {
	var d *platform.Dashboard

	err := c.db.View(func(tx *bolt.Tx) error {
		dash, err := c.findDashboardByID(ctx, tx, id)
		if err != nil {
			return err
		}
		d = dash
		return nil
	})

	if err != nil {
		return nil, &platform.Error{
			Op:  getOp(platform.OpFindDashboardByID),
			Err: err,
		}
	}

	return d, nil
}
429434
func (r *Client) SearchDashboards(query string, starred bool, tags ...string) ([]FoundBoard, error) {
	var (
		raw    []byte
		boards []FoundBoard
		code   int
		err    error
	)
	u := url.URL{}
	q := u.Query()
	if query != "" {
		q.Set("query", query)
	}
	if starred {
		q.Set("starred", "true")
	}
	for _, tag := range tags {
		q.Add("tag", tag)
	}
	if raw, code, err = r.get("api/search", q); err != nil {
		return nil, err
	}
	if code != 200 {
		return nil, fmt.Errorf("HTTP error %d: returns %s", code, raw)
	}
	err = json.Unmarshal(raw, &boards)
	return boards, err
}
554967
func (s *DashboardService) CreateDashboard(ctx context.Context, b *influxdb.Dashboard) error {
	p, err := influxdb.NewPermission(influxdb.WriteAction, influxdb.DashboardsResourceType, b.OrganizationID)
	if err != nil {
		return err
	}

	if err := IsAllowed(ctx, *p); err != nil {
		return err
	}

	return s.s.CreateDashboard(ctx, b)
}
906039
func (s *DashboardService) FindDashboards(ctx context.Context, filter influxdb.DashboardFilter, opt influxdb.FindOptions) ([]*influxdb.Dashboard, int, error) {
	// TODO: we'll likely want to push this operation into the database eventually since fetching the whole list of data
	// will likely be expensive.
	bs, _, err := s.s.FindDashboards(ctx, filter, opt)
	if err != nil {
		return nil, 0, err
	}

	// This filters without allocating
	// https://github.com/golang/go/wiki/SliceTricks#filtering-without-allocating
	dashboards := bs[:0]
	for _, b := range bs {
		err := authorizeReadDashboard(ctx, b.OrganizationID, b.ID)
		if err != nil && influxdb.ErrorCode(err) != influxdb.EUnauthorized {
			return nil, 0, err
		}

		if influxdb.ErrorCode(err) == influxdb.EUnauthorized {
			continue
		}

		dashboards = append(dashboards, b)
	}

	return dashboards, len(dashboards), nil
}
229787
func (h *DashboardHandler) handleDeleteDashboard(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()

	req, err := decodeDeleteDashboardRequest(ctx, r)
	if err != nil {
		EncodeError(ctx, err, w)
		return
	}

	if err := h.DashboardService.DeleteDashboard(ctx, req.DashboardID); err != nil {
		EncodeError(ctx, err, w)
		return
	}

	w.WriteHeader(http.StatusNoContent)
}
915558
func (h *DashboardHandler) handleGetDashboards(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	req, err := decodeGetDashboardsRequest(ctx, r)
	if err != nil {
		EncodeError(ctx, err, w)
		return
	}

	if req.ownerID != nil {
		filter := platform.UserResourceMappingFilter{
			UserID:       *req.ownerID,
			UserType:     platform.Owner,
			ResourceType: platform.DashboardsResourceType,
		}

		mappings, _, err := h.UserResourceMappingService.FindUserResourceMappings(ctx, filter)
		if err != nil {
			EncodeError(ctx, &platform.Error{
				Code: platform.EInternal,
				Msg:  "Error loading dashboard owners",
				Err:  err,
			}, w)
			return
		}

		for _, mapping := range mappings {
			req.filter.IDs = append(req.filter.IDs, &mapping.ResourceID)
		}
	}

	dashboards, _, err := h.DashboardService.FindDashboards(ctx, req.filter, req.opts)
	if err != nil {
		EncodeError(ctx, err, w)
		return
	}

	if err := encodeResponse(ctx, w, http.StatusOK, newGetDashboardsResponse(ctx, dashboards, req.filter, req.opts, h.LabelService)); err != nil {
		logEncodingError(h.Logger, r, err)
		return
	}
}
141089
func (s *PutDashboardOutput) SetDashboardValidationMessages(v []*DashboardValidationMessage) *PutDashboardOutput {
	s.DashboardValidationMessages = v
	return s
}
1137056
func SortBy(rows [][]string, lesses ...LessFunc) *MultiSorter {
	return &MultiSorter{
		data: rows,
		less: lesses,
	}
}
517959
func (s *Service) DeleteDashboard(ctx context.Context, id platform.ID) error {
	op := OpPrefix + platform.OpDeleteDashboard
	if _, err := s.FindDashboardByID(ctx, id); err != nil {
		return &platform.Error{
			Err: err,
			Op:  op,
		}
	}
	s.dashboardKV.Delete(id.String())
	err := s.deleteLabel(ctx, platform.LabelFilter{ResourceID: id})
	if err != nil {
		return &platform.Error{
			Err: err,
			Op:  op,
		}
	}
	return nil
}
174707
func DashboardDefaults(d chronograf.Dashboard) (newDash chronograf.Dashboard) {
	newDash.ID = d.ID
	newDash.Templates = d.Templates
	newDash.Name = d.Name
	newDash.Organization = d.Organization
	newDash.Cells = make([]chronograf.DashboardCell, len(d.Cells))

	for i, c := range d.Cells {
		CorrectWidthHeight(&c)
		newDash.Cells[i] = c
	}
	return
}
984721
func (s *Service) FindDashboardByID(ctx context.Context, id platform.ID) (*platform.Dashboard, error) {
	d, pe := s.loadDashboard(ctx, id)
	if pe != nil {
		return nil, &platform.Error{
			Op:  OpPrefix + platform.OpFindDashboardByID,
			Err: pe,
		}
	}
	return d, nil
}
497067
func NewDashboardBackend(b *APIBackend) *DashboardBackend {
	return &DashboardBackend{
		Logger: b.Logger.With(zap.String("handler", "dashboard")),

		DashboardService:             b.DashboardService,
		DashboardOperationLogService: b.DashboardOperationLogService,
		UserResourceMappingService:   b.UserResourceMappingService,
		LabelService:                 b.LabelService,
		UserService:                  b.UserService,
	}
}
423139
func checkDashboard(client *sshClient, network string) (*dashboardInfos, error) {
	// Inspect a possible ethstats container on the host
	infos, err := inspectContainer(client, fmt.Sprintf("%s_dashboard_1", network))
	if err != nil {
		return nil, err
	}
	if !infos.running {
		return nil, ErrServiceOffline
	}
	// Resolve the port from the host, or the reverse proxy
	port := infos.portmap["80/tcp"]
	if port == 0 {
		if proxy, _ := checkNginx(client, network); proxy != nil {
			port = proxy.port
		}
	}
	if port == 0 {
		return nil, ErrNotExposed
	}
	// Resolve the host from the reverse-proxy and configure the connection string
	host := infos.envvars["VIRTUAL_HOST"]
	if host == "" {
		host = client.server
	}
	// Run a sanity check to see if the port is reachable
	if err = checkPort(host, port); err != nil {
		log.Warn("Dashboard service seems unreachable", "server", host, "port", port, "err", err)
	}
	// Container available, assemble and return the useful infos
	return &dashboardInfos{
		host:     host,
		port:     port,
		ethstats: infos.envvars["ETHSTATS_PAGE"],
		explorer: infos.envvars["EXPLORER_PAGE"],
		wallet:   infos.envvars["WALLET_PAGE"],
		faucet:   infos.envvars["FAUCET_PAGE"],
	}, nil
}
1032244
func (s *Service) FindDashboards(ctx context.Context, filter influxdb.DashboardFilter, opts influxdb.FindOptions) ([]*influxdb.Dashboard, int, error) {
	ds := []*influxdb.Dashboard{}
	if len(filter.IDs) == 1 {
		d, err := s.FindDashboardByID(ctx, *filter.IDs[0])
		if err != nil && influxdb.ErrorCode(err) != influxdb.ENotFound {
			return ds, 0, &influxdb.Error{
				Err: err,
			}
		}
		if d == nil {
			return ds, 0, nil
		}
		return []*influxdb.Dashboard{d}, 1, nil
	}
	err := s.kv.View(ctx, func(tx Tx) error {
		dashs, err := s.findDashboards(ctx, tx, filter, opts)
		if err != nil && influxdb.ErrorCode(err) != influxdb.ENotFound {
			return err
		}
		ds = dashs
		return nil
	})

	if err != nil {
		return nil, 0, &influxdb.Error{
			Err: err,
		}
	}

	influxdb.SortDashboards(opts, ds)

	return ds, len(ds), nil
}