<commit_before>/**
 * test for table view
 */
describe("tableview", function() {

  describe("headerview", function() {
    var view;
    var model = new cdb.admin.CartoDBTableMetadata({
        name: 'test'
    });
    beforeEach(function() {
      view = new cdb.admin.HeaderView({
        el: $('<div>'),
        column: ['name', 'type'],
        table: model
      });
    });

    it('should render', function() {
      view.render();
      expect(view.$('label > a').html().trim()).toEqual('name');
      expect(view.$('p > a').html()).toEqual('type');
    });

    it("when click on column name a menu should be opened", function() {
      runs(function() {
        view.render();
        view.$('.coloptions').trigger('click');
      });
      //WTF i need to wait this time to click to be triggered? <- in fact it probably doesn't have anything to do with time, but with the way the Browser UI thread choose what's going to execute next
      waits(400);
      runs(function() {
        expect(cdb.admin.HeaderView.colOptions.$el.css('display')).toEqual('block');
      });
    });

    it("when click on column type a menu should be opened", function() {
      runs(function() {
        view.render();
        view.$('.coltype').trigger('click');
      });
      waits(800);
      runs(function() {
        expect(cdb.admin.HeaderView.colTypeOptions.$el.css('display')).toEqual('block');
      });
    });

    it("when click on column type, being in a SQL view should not open anything", function() {
      runs(function() {
        view.render();
        var sqlView = new cdb.admin.SQLViewData(null, { sql: 'select * from a' });
        model.useSQLView(sqlView);
        view.$('.coltype').trigger('click');
      });
      waits(800);
      runs(function() {
        expect(cdb.admin.HeaderView.colTypeOptions.$el.css('display')).toEqual('none');
      });
    });
  });

  describe('TableView', function() {
    var tview;
    var model;
    var globalErrorDummy;
    beforeEach(function() {
      this.server = sinon.fakeServer.create();

      globalErrorDummy = {
        "showError": function(a,b,c) {
          this.params = {
            "first": a,
            "second": b,
            "third": c
          }
          return true;
        }
      }

      model = new cdb.admin.CartoDBTableMetadata({
        name: 'test',
        schema: [
          ['id', 'integer'],
          ['col1', 'integer'],
          ['col2', 'integer'],
          ['col3', 'integer'],
          ['the_geom', 'geometry']
        ]
      });

      tview = new cdb.admin.TableView({
        el: $('<table>'),
        dataModel: model.data(),
        model: model,
        row_header: true,
        globalError: globalErrorDummy
      });
      model.data().reset([
        {'id': 1, 'col1': 1, 'col2': 2, 'col3': 3, 'the_geom': null},
        {'id': 2, 'col1': 4, 'col2': 5, 'col3': 6, 'the_geom': null}
      ]);
    });

    it('should render a table', function() {
      model.set({
        columns: [['test', 'integer']]
      });
      tview.render();
      expect(tview.$('thead').length).toEqual(1);
    });

    it("should edit cell", function() {
      spyOn(tview, '_getEditor');
      tview.render();
      tview.getCell(0, 0).trigger('dblclick');
      expect(tview._getEditor).toHaveBeenCalled();
    });

    it("should show the point info when the_Geom is a point", function() {
      model.data().reset([
        {'id': 1, 'col1': 1, 'col2': 2, 'col3': 3, 'the_geom':
          '{"type":"Point", "coordinates": [1,1]}'}
      ]);
      tview.render();

      expect(tview.$('td .cell').eq(5).html()).toEqual("1, 1");

    })

    it("should be able to add an empty row", function() {
      var prevSize = tview._models[0].table.data().length;
      tview.addEmptyRow();
      this.server.requests[0].respond(200,{ "Content-Type": "application/json" },"");
      expect(prevSize+1).toEqual(tview._models[0].table.data().length);
    })

    it("should show the empty table layout when there's no data", function() {
      model.data().reset();
      //model.data().trigger('dataLoaded');

      expect(tview.$('.placeholder.noRows').length).toBe(2);
      expect(tview.$('.placeholder.noRows.decoration').length).toBe(1);
      expect(tview.$('tfoot').length).toBe(1);

    })

    it("should NOT show a notice when nothing happens", function() {
      expect(globalErrorDummy.params).toBeFalsy();
    });

    it("should show a notice when a row is being saved", function() {
      tview.rowSaving();
      expect(globalErrorDummy.params).toBeTruthy();
    });

    it("should show a notice when the model when a row is synched", function() {
      tview.rowSynched();
      expect(globalErrorDummy.params).toBeTruthy();
    });

    it("should show a notice the model when a row synch fails", function() {
      tview.rowFailed();
      expect(globalErrorDummy.params).toBeTruthy();
    });

    it("should show a notice the model when a row is deleted", function() {
      tview.rowDestroyed();
      expect(globalErrorDummy.params).toBeTruthy();
    });

    it("should not show the empty table layout after an empty row insertion", function() {
      model.data().reset();
      tview.render();
      tview.addEmptyRow()
      expect(tview.$('.placeholder.noRows').length).toBe(0);
      expect(tview.$('.placeholder.noRows.decoration').length).toBe(0);
      expect(tview.$('tfoot').length).toBe(0);
    })

    xit("should show the empty table layout after the deletion of the last row", function() {
      // @todo (Xabel) this is not working, I'm not sure why, because in the app everything goes fine
      model.data().reset();
      tview = new cdb.admin.TableView({
        el: $('<table>'),
        dataModel: model.data(),
        model: model,
        row_header: true
      });
      tview.render();
      tview.addEmptyRow();
      spyOn(tview, 'rowDestroyed');
      spyOn(tview, 'emptyTable');
      var rowOptions =  tview.rowViews[0]._getRowOptions();
      rowOptions.setRow(tview.rowViews[0].model);
      rowOptions.deleteRow();

      waits(100);

      expect(tview.emptyTable).toHaveBeenCalled();
      expect(tview.$('.placeholder.noRows').length).toBe(2);
      expect(tview.$('.placeholder.noRows.decoration').length).toBe(1);
      expect(tview.$('tfoot').length).toBe(1);
    })

  });

  describe('TableTab', function() {
    var tview;
    var model;
    beforeEach(function() {
      model = new cdb.admin.CartoDBTableMetadata({
        name: 'test'
      });

      tview = new cdb.admin.TableTab({
        model: model
      });
    });

    it('should render a div', function() {
      tview.render();
      expect(tview.$el.hasClass('table')).toBeTruthy();
    });

  });

  describe('HeaderColumnOptionsDropdown', function() {
    var view;
    var model;

    beforeEach(function() {
      model = new cdb.admin.CartoDBTableMetadata({
        name: 'test'
      });
      view = new cdb.admin.HeaderDropdown({
        position: 'position',
        template_base: "table/views/table_header_options"
      });
    });

    it("should render all options for normal fields", function() {
      view.setTable(model, 'normal');
      expect(view.$('li').length).toEqual(7);
    });

    it("should not render all options for reserved column", function() {
      view.setTable(model, 'cartodb_id');
      expect(view.$('li').length).toEqual(2);
      view.setTable(model, 'normal');
      expect(view.$('li').length).toEqual(7);
    });

    it("should not render all options for read only data", function() {
      var sqlView = new cdb.admin.SQLViewData(null, { sql: 'select * from a' });
      model.useSQLView(sqlView);

      view.setTable(model, 'cartodb_id');
      expect(view.$('li').length).toEqual(2);
      view.setTable(model, 'normal');
      expect(view.$('li').length).toEqual(2);
    });

  });

  describe('HeaderColumnTypeDropdown', function() {
    var view;
    var model;

    beforeEach(function() {
      model = new cdb.admin.CartoDBTableMetadata({
        name: 'test'
      });
      view = new cdb.admin.ColumntypeDropdown({
        position: 'position',
        template_base: "table/views/table_column_type_options"
      });
    });

    it("should render all available column types", function() {
      view.setTable(model, 'normal');
      expect(view.render().$el.find('li').length).toEqual(4);
    });
  });

});
<commit_msg>tests updated & added<commit_after>/**
 * test for table view
 */
describe("tableview", function() {

  describe("headerview", function() {
    var view;
    var model = new cdb.admin.CartoDBTableMetadata({
        name: 'test'
    });
    beforeEach(function() {
      view = new cdb.admin.HeaderView({
        el: $('<div>'),
        column: ['name', 'type'],
        table: model
      });
    });

    it('should render', function() {
      view.render();
      expect(view.$('label > a').html().trim()).toEqual('name');
      expect(view.$('p > a').html()).toEqual('type');
    });

    it("when click on column name a menu should be opened", function() {
      runs(function() {
        view.render();
        view.$('.coloptions').trigger('click');
      });
      //WTF i need to wait this time to click to be triggered? <- in fact it probably doesn't have anything to do with time, but with the way the Browser UI thread choose what's going to execute next
      waits(400);
      runs(function() {
        expect(cdb.admin.HeaderView.colOptions.$el.css('display')).toEqual('block');
      });
    });

    it("when click on column type a menu should be opened", function() {
      runs(function() {
        view.render();
        view.$('.coltype').trigger('click');
      });
      waits(800);
      runs(function() {
        expect(cdb.admin.HeaderView.colTypeOptions.$el.css('display')).toEqual('block');
      });
    });

    it("when click on column type, being in a SQL view should not open anything", function() {
      runs(function() {
        view.render();
        var sqlView = new cdb.admin.SQLViewData(null, { sql: 'select * from a' });
        model.useSQLView(sqlView);
        view.$('.coltype').trigger('click');
      });
      waits(800);
      runs(function() {
        expect(cdb.admin.HeaderView.colTypeOptions.$el.css('display')).toEqual('none');
      });
    });
  });

  describe('TableView', function() {
    var tview;
    var model;
    var globalErrorDummy;
    beforeEach(function() {
      this.server = sinon.fakeServer.create();

      globalErrorDummy = {
        "showError": function(a,b,c) {
          this.params = {
            "first": a,
            "second": b,
            "third": c
          }
          return true;
        }
      }

      model = new cdb.admin.CartoDBTableMetadata({
        name: 'test',
        schema: [
          ['id', 'integer'],
          ['col1', 'integer'],
          ['col2', 'integer'],
          ['col3', 'integer'],
          ['the_geom', 'geometry']
        ]
      });

      tview = new cdb.admin.TableView({
        el: $('<table>'),
        dataModel: model.data(),
        model: model,
        row_header: true,
        globalError: globalErrorDummy
      });
      model.data().reset([
        {'id': 1, 'col1': 1, 'col2': 2, 'col3': 3, 'the_geom': null},
        {'id': 2, 'col1': 4, 'col2': 5, 'col3': 6, 'the_geom': null}
      ]);
    });

    it('should render a table', function() {
      model.set({
        columns: [['test', 'integer']]
      });
      tview.render();
      expect(tview.$('thead').length).toEqual(1);
    });

    it("should edit cell", function() {
      spyOn(tview, '_getEditor');
      tview.render();
      tview.getCell(0, 0).trigger('dblclick');
      expect(tview._getEditor).toHaveBeenCalled();
    });

    it("should show the type when the_Geom is a point", function() {
      model.data().reset([
        {'id': 1, 'col1': 1, 'col2': 2, 'col3': 3, 'the_geom':
          '{"type":"Point", "coordinates": [1,1]}'}
      ]);
      model.set('geometry_types', ["st_point"]);
      tview.render();

      expect(tview.$('td .cell').eq(5).html()).toEqual("point");

    })

    it("should show the type when the_Geom is a line", function() {
      model.data().reset([
        {'id': 1, 'col1': 1, 'col2': 2, 'col3': 3, 'the_geom':
          '{"type":"Point", "coordinates": [[1,1],[2,3],[6,6]]}'}
      ]);
      model.set('geometry_types', ["st_linestring"]);
      tview.render();

      expect(tview.$('td .cell').eq(5).html()).toEqual("line");

    })

    it("should show 'geojson' on the_Geom is  cell when we don't know the geometry type yet", function() {
      model.data().reset([
        {'id': 1, 'col1': 1, 'col2': 2, 'col3': 3, 'the_geom':
          '{"type":"Point", "coordinates": [[1,1],[2,3],[6,6]]}'}
      ]);
      model.table.set('geometry_types', ["st_linestring"]);
      tview.render();

      expect(tview.$('td .cell').eq(5).html()).toEqual("GeoJSON");

    })

    it("should be able to add an empty row", function() {
      var prevSize = tview._models[0].table.data().length;
      tview.addEmptyRow();
      this.server.requests[0].respond(200,{ "Content-Type": "application/json" },"");
      expect(prevSize+1).toEqual(tview._models[0].table.data().length);
    })

    it("should show the empty table layout when there's no data", function() {
      model.data().reset();
      //model.data().trigger('dataLoaded');

      expect(tview.$('.placeholder.noRows').length).toBe(2);
      expect(tview.$('.placeholder.noRows.decoration').length).toBe(1);
      expect(tview.$('tfoot').length).toBe(1);

    })

    it("should NOT show a notice when nothing happens", function() {
      expect(globalErrorDummy.params).toBeFalsy();
    });

    it("should show a notice when a row is being saved", function() {
      tview.rowSaving();
      expect(globalErrorDummy.params).toBeTruthy();
    });

    it("should show a notice when the model when a row is synched", function() {
      tview.rowSynched();
      expect(globalErrorDummy.params).toBeTruthy();
    });

    it("should show a notice the model when a row synch fails", function() {
      tview.rowFailed();
      expect(globalErrorDummy.params).toBeTruthy();
    });

    it("should show a notice the model when a row is deleted", function() {
      tview.rowDestroyed();
      expect(globalErrorDummy.params).toBeTruthy();
    });

    it("should not show the empty table layout after an empty row insertion", function() {
      model.data().reset();
      tview.render();
      tview.addEmptyRow()
      expect(tview.$('.placeholder.noRows').length).toBe(0);
      expect(tview.$('.placeholder.noRows.decoration').length).toBe(0);
      expect(tview.$('tfoot').length).toBe(0);
    })

    xit("should show the empty table layout after the deletion of the last row", function() {
      // @todo (Xabel) this is not working, I'm not sure why, because in the app everything goes fine
      model.data().reset();
      tview = new cdb.admin.TableView({
        el: $('<table>'),
        dataModel: model.data(),
        model: model,
        row_header: true
      });
      tview.render();
      tview.addEmptyRow();
      spyOn(tview, 'rowDestroyed');
      spyOn(tview, 'emptyTable');
      var rowOptions =  tview.rowViews[0]._getRowOptions();
      rowOptions.setRow(tview.rowViews[0].model);
      rowOptions.deleteRow();

      waits(100);

      expect(tview.emptyTable).toHaveBeenCalled();
      expect(tview.$('.placeholder.noRows').length).toBe(2);
      expect(tview.$('.placeholder.noRows.decoration').length).toBe(1);
      expect(tview.$('tfoot').length).toBe(1);
    })

  });

  describe('TableTab', function() {
    var tview;
    var model;
    beforeEach(function() {
      model = new cdb.admin.CartoDBTableMetadata({
        name: 'test'
      });

      tview = new cdb.admin.TableTab({
        model: model
      });
    });

    it('should render a div', function() {
      tview.render();
      expect(tview.$el.hasClass('table')).toBeTruthy();
    });

  });

  describe('HeaderColumnOptionsDropdown', function() {
    var view;
    var model;

    beforeEach(function() {
      model = new cdb.admin.CartoDBTableMetadata({
        name: 'test'
      });
      view = new cdb.admin.HeaderDropdown({
        position: 'position',
        template_base: "table/views/table_header_options"
      });
    });

    it("should render all options for normal fields", function() {
      view.setTable(model, 'normal');
      expect(view.$('li').length).toEqual(7);
    });

    it("should not render all options for reserved column", function() {
      view.setTable(model, 'cartodb_id');
      expect(view.$('li').length).toEqual(2);
      view.setTable(model, 'normal');
      expect(view.$('li').length).toEqual(7);
    });

    it("should not render all options for read only data", function() {
      var sqlView = new cdb.admin.SQLViewData(null, { sql: 'select * from a' });
      model.useSQLView(sqlView);

      view.setTable(model, 'cartodb_id');
      expect(view.$('li').length).toEqual(2);
      view.setTable(model, 'normal');
      expect(view.$('li').length).toEqual(2);
    });

  });

  describe('HeaderColumnTypeDropdown', function() {
    var view;
    var model;

    beforeEach(function() {
      model = new cdb.admin.CartoDBTableMetadata({
        name: 'test'
      });
      view = new cdb.admin.ColumntypeDropdown({
        position: 'position',
        template_base: "table/views/table_column_type_options"
      });
    });

    it("should render all available column types", function() {
      view.setTable(model, 'normal');
      expect(view.render().$el.find('li').length).toEqual(4);
    });
  });

});
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2013 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * @fileoverview Object representing an icon on a block.
 * @author fraser@google.com (Neil Fraser)
 */
'use strict';

goog.provide('Blockly.Icon');

goog.require('Blockly.browserEvents');
goog.require('Blockly.utils');
goog.require('Blockly.utils.Coordinate');
goog.require('Blockly.utils.dom');
goog.require('Blockly.utils.Size');
goog.require('Blockly.utils.Svg');

goog.requireType('Blockly.BlockSvg');
goog.requireType('Blockly.Bubble');

/**
 * Class for an icon.
 * @param {Blockly.BlockSvg} block The block associated with this icon.
 * @constructor
 * @abstract
 */
Blockly.Icon = function(block) {
  /**
   * The block this icon is attached to.
   * @type {Blockly.BlockSvg}
   * @protected
   */
  this.block_ = block;

  /**
   * The icon SVG group.
   * @type {?SVGGElement}
   */
  this.iconGroup_ = null;
};

/**
 * Does this icon get hidden when the block is collapsed.
 */
Blockly.Icon.prototype.collapseHidden = true;

/**
 * Height and width of icons.
 */
Blockly.Icon.prototype.SIZE = 17;

/**
 * Bubble UI (if visible).
 * @type {?Blockly.Bubble}
 * @protected
 */
Blockly.Icon.prototype.bubble_ = null;

/**
 * Absolute coordinate of icon's center.
 * @type {?Blockly.utils.Coordinate}
 * @protected
 */
Blockly.Icon.prototype.iconXY_ = null;

/**
 * Create the icon on the block.
 */
Blockly.Icon.prototype.createIcon = function() {
  if (this.iconGroup_) {
    // Icon already exists.
    return;
  }
  /* Here's the markup that will be generated:
  <g class="blocklyIconGroup">
    ...
  </g>
  */
  this.iconGroup_ = Blockly.utils.dom.createSvgElement(
      Blockly.utils.Svg.G,
      {'class': 'blocklyIconGroup'}, null);
  if (this.block_.isInFlyout) {
    Blockly.utils.dom.addClass(
        /** @type {!Element} */ (this.iconGroup_), 'blocklyIconGroupReadonly');
  }
  this.drawIcon_(this.iconGroup_);

  this.block_.getSvgRoot().appendChild(this.iconGroup_);
  Blockly.browserEvents.conditionalBind(
      this.iconGroup_, 'mouseup', this, this.iconClick_);
  this.updateEditable();
};

/**
 * Dispose of this icon.
 */
Blockly.Icon.prototype.dispose = function() {
  // Dispose of and unlink the icon.
  Blockly.utils.dom.removeNode(this.iconGroup_);
  this.iconGroup_ = null;
  // Dispose of and unlink the bubble.
  this.setVisible(false);
  this.block_ = null;
};

/**
 * Add or remove the UI indicating if this icon may be clicked or not.
 */
Blockly.Icon.prototype.updateEditable = function() {
  // No-op on the base class.
};

/**
 * Is the associated bubble visible?
 * @return {boolean} True if the bubble is visible.
 */
Blockly.Icon.prototype.isVisible = function() {
  return !!this.bubble_;
};

/**
 * Clicking on the icon toggles if the bubble is visible.
 * @param {!Event} e Mouse click event.
 * @protected
 */
Blockly.Icon.prototype.iconClick_ = function(e) {
  if (this.block_.workspace.isDragging()) {
    // Drag operation is concluding.  Don't open the editor.
    return;
  }
  if (!this.block_.isInFlyout && !Blockly.utils.isRightButton(e)) {
    this.setVisible(!this.isVisible());
  }
};

/**
 * Change the colour of the associated bubble to match its block.
 */
Blockly.Icon.prototype.applyColour = function() {
  if (this.isVisible()) {
    this.bubble_.setColour(this.block_.style.colourPrimary);
  }
};

/**
 * Notification that the icon has moved.  Update the arrow accordingly.
 * @param {!Blockly.utils.Coordinate} xy Absolute location in workspace coordinates.
 */
Blockly.Icon.prototype.setIconLocation = function(xy) {
  this.iconXY_ = xy;
  if (this.isVisible()) {
    this.bubble_.setAnchorLocation(xy);
  }
};

/**
 * Notification that the icon has moved, but we don't really know where.
 * Recompute the icon's location from scratch.
 */
Blockly.Icon.prototype.computeIconLocation = function() {
  // Find coordinates for the centre of the icon and update the arrow.
  var blockXY = this.block_.getRelativeToSurfaceXY();
  var iconXY = Blockly.utils.getRelativeXY(
      /** @type {!SVGElement} */ (this.iconGroup_));
  var newXY = new Blockly.utils.Coordinate(
      blockXY.x + iconXY.x + this.SIZE / 2,
      blockXY.y + iconXY.y + this.SIZE / 2);
  if (!Blockly.utils.Coordinate.equals(this.getIconLocation(), newXY)) {
    this.setIconLocation(newXY);
  }
};

/**
 * Returns the center of the block's icon relative to the surface.
 * @return {?Blockly.utils.Coordinate} Object with x and y properties in
 *     workspace coordinates.
 */
Blockly.Icon.prototype.getIconLocation = function() {
  return this.iconXY_;
};

/**
 * Get the size of the icon as used for rendering.
 * This differs from the actual size of the icon, because it bulges slightly
 * out of its row rather than increasing the height of its row.
 * @return {!Blockly.utils.Size} Height and width.
 */
// TODO (#2562): Remove getCorrectedSize.
Blockly.Icon.prototype.getCorrectedSize = function() {
  return new Blockly.utils.Size(
      Blockly.Icon.prototype.SIZE, Blockly.Icon.prototype.SIZE - 2);
};

/**
 * Draw the icon.
 * @param {!Element} group The icon group.
 * @protected
 */
Blockly.Icon.prototype.drawIcon_;

/**
 * Show or hide the icon.
 * @param {boolean} visible True if the icon should be visible.
 */
Blockly.Icon.prototype.setVisible;
<commit_msg>Migrate core/icon.js to ES6 const/let<commit_after>/**
 * @license
 * Copyright 2013 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * @fileoverview Object representing an icon on a block.
 * @author fraser@google.com (Neil Fraser)
 */
'use strict';

goog.provide('Blockly.Icon');

goog.require('Blockly.browserEvents');
goog.require('Blockly.utils');
goog.require('Blockly.utils.Coordinate');
goog.require('Blockly.utils.dom');
goog.require('Blockly.utils.Size');
goog.require('Blockly.utils.Svg');

goog.requireType('Blockly.BlockSvg');
goog.requireType('Blockly.Bubble');

/**
 * Class for an icon.
 * @param {Blockly.BlockSvg} block The block associated with this icon.
 * @constructor
 * @abstract
 */
Blockly.Icon = function(block) {
  /**
   * The block this icon is attached to.
   * @type {Blockly.BlockSvg}
   * @protected
   */
  this.block_ = block;

  /**
   * The icon SVG group.
   * @type {?SVGGElement}
   */
  this.iconGroup_ = null;
};

/**
 * Does this icon get hidden when the block is collapsed.
 */
Blockly.Icon.prototype.collapseHidden = true;

/**
 * Height and width of icons.
 */
Blockly.Icon.prototype.SIZE = 17;

/**
 * Bubble UI (if visible).
 * @type {?Blockly.Bubble}
 * @protected
 */
Blockly.Icon.prototype.bubble_ = null;

/**
 * Absolute coordinate of icon's center.
 * @type {?Blockly.utils.Coordinate}
 * @protected
 */
Blockly.Icon.prototype.iconXY_ = null;

/**
 * Create the icon on the block.
 */
Blockly.Icon.prototype.createIcon = function() {
  if (this.iconGroup_) {
    // Icon already exists.
    return;
  }
  /* Here's the markup that will be generated:
  <g class="blocklyIconGroup">
    ...
  </g>
  */
  this.iconGroup_ = Blockly.utils.dom.createSvgElement(
      Blockly.utils.Svg.G,
      {'class': 'blocklyIconGroup'}, null);
  if (this.block_.isInFlyout) {
    Blockly.utils.dom.addClass(
        /** @type {!Element} */ (this.iconGroup_), 'blocklyIconGroupReadonly');
  }
  this.drawIcon_(this.iconGroup_);

  this.block_.getSvgRoot().appendChild(this.iconGroup_);
  Blockly.browserEvents.conditionalBind(
      this.iconGroup_, 'mouseup', this, this.iconClick_);
  this.updateEditable();
};

/**
 * Dispose of this icon.
 */
Blockly.Icon.prototype.dispose = function() {
  // Dispose of and unlink the icon.
  Blockly.utils.dom.removeNode(this.iconGroup_);
  this.iconGroup_ = null;
  // Dispose of and unlink the bubble.
  this.setVisible(false);
  this.block_ = null;
};

/**
 * Add or remove the UI indicating if this icon may be clicked or not.
 */
Blockly.Icon.prototype.updateEditable = function() {
  // No-op on the base class.
};

/**
 * Is the associated bubble visible?
 * @return {boolean} True if the bubble is visible.
 */
Blockly.Icon.prototype.isVisible = function() {
  return !!this.bubble_;
};

/**
 * Clicking on the icon toggles if the bubble is visible.
 * @param {!Event} e Mouse click event.
 * @protected
 */
Blockly.Icon.prototype.iconClick_ = function(e) {
  if (this.block_.workspace.isDragging()) {
    // Drag operation is concluding.  Don't open the editor.
    return;
  }
  if (!this.block_.isInFlyout && !Blockly.utils.isRightButton(e)) {
    this.setVisible(!this.isVisible());
  }
};

/**
 * Change the colour of the associated bubble to match its block.
 */
Blockly.Icon.prototype.applyColour = function() {
  if (this.isVisible()) {
    this.bubble_.setColour(this.block_.style.colourPrimary);
  }
};

/**
 * Notification that the icon has moved.  Update the arrow accordingly.
 * @param {!Blockly.utils.Coordinate} xy Absolute location in workspace coordinates.
 */
Blockly.Icon.prototype.setIconLocation = function(xy) {
  this.iconXY_ = xy;
  if (this.isVisible()) {
    this.bubble_.setAnchorLocation(xy);
  }
};

/**
 * Notification that the icon has moved, but we don't really know where.
 * Recompute the icon's location from scratch.
 */
Blockly.Icon.prototype.computeIconLocation = function() {
  // Find coordinates for the centre of the icon and update the arrow.
  const blockXY = this.block_.getRelativeToSurfaceXY();
  const iconXY = Blockly.utils.getRelativeXY(
      /** @type {!SVGElement} */ (this.iconGroup_));
  const newXY = new Blockly.utils.Coordinate(
      blockXY.x + iconXY.x + this.SIZE / 2,
      blockXY.y + iconXY.y + this.SIZE / 2);
  if (!Blockly.utils.Coordinate.equals(this.getIconLocation(), newXY)) {
    this.setIconLocation(newXY);
  }
};

/**
 * Returns the center of the block's icon relative to the surface.
 * @return {?Blockly.utils.Coordinate} Object with x and y properties in
 *     workspace coordinates.
 */
Blockly.Icon.prototype.getIconLocation = function() {
  return this.iconXY_;
};

/**
 * Get the size of the icon as used for rendering.
 * This differs from the actual size of the icon, because it bulges slightly
 * out of its row rather than increasing the height of its row.
 * @return {!Blockly.utils.Size} Height and width.
 */
// TODO (#2562): Remove getCorrectedSize.
Blockly.Icon.prototype.getCorrectedSize = function() {
  return new Blockly.utils.Size(
      Blockly.Icon.prototype.SIZE, Blockly.Icon.prototype.SIZE - 2);
};

/**
 * Draw the icon.
 * @param {!Element} group The icon group.
 * @protected
 */
Blockly.Icon.prototype.drawIcon_;

/**
 * Show or hide the icon.
 * @param {boolean} visible True if the icon should be visible.
 */
Blockly.Icon.prototype.setVisible;
<|endoftext|>


<commit_before>import React from 'react'
import PropTypes from 'prop-types'
import Immutable from 'immutable'
import classnames from 'classnames'
import { TextareaItem } from 'antd-mobile'
import { createForm } from 'rc-form'
import { RadioGroup, Radio } from 'components'
import styles from './Content.less'

const Title = ({ cur, inner, text, errors }) => (

    {cur}{ inner && '. ' }
    {text}

)
Title.propTypes = {
  cur: PropTypes.number.isRequired,
  inner: PropTypes.bool,
  text: PropTypes.string.isRequired,
  errors: PropTypes.bool,
}

const RadioStar = ({ onChange, children }) => {
  return (
    <RadioGroup onChange={onChange} field={children}>
      <Radio type="satisfy" value="4">很满意</Radio>
      <Radio type="good" value="3">满意</Radio>
      <Radio type="soso" value="2">不太满意</Radio>
      <Radio type="bad" value="1">不满意</Radio>
    </RadioGroup>
  )
}
RadioStar.propTypes = {
  onChange: PropTypes.func.isRequired,
  children: PropTypes.any.isRequired,
}

const Content = ({
    form: { getFieldProps, validateFields, getFieldError, setFieldsValue },
    readOnly,
    lessonId,
    item,
    onFeedback,
  }) => {
    console.log(readOnly)
  const submit = (e) => {
    validateFields((errors, value) => {
      if (errors) {
        e.preventDefault()
          // for (let index in errors) {
          //   console.log(errors[index].errors[0].message)
          // }
      } else {
        onFeedback.submitFeedback({ ...value, lessonid: lessonId }).then((res) => {
          console.log(res)
        })
      }
    })
  }

  const handleChangeChecked = field => (value) => {
    setFieldsValue({ [field]: value })
  }

  return (

      <Title cur={1} text="老师满意度" />

          <Title cur={1} inner text="老师课前教学准备充分度" errors={!!getFieldError('lesson_prepare_score')} />
          <RadioStar onChange={handleChangeChecked('lesson_prepare_score')}>
            <input
              style={{ display: 'none' }}
              {...getFieldProps('lesson_prepare_score', {
                initialValue: item.get('lesson_prepare_score'),
                rules: [
                  {
                    required: true,
                    message: '请填写老师课前教学准备充分度',
                  },
                ],
              })}
            />
          </RadioStar>

          <Title cur={2} inner text="本课内容设计满意度" errors={!!getFieldError('lesson_content_score')} />
          <RadioStar onChange={handleChangeChecked('lesson_content_score')}>
            <input
              style={{ display: 'none' }}
              {...getFieldProps('lesson_content_score', {
                initialValue: item.get('lesson_content_score'),
                rules: [
                  {
                    required: true,
                    message: '请填写本课内容设计满意度',
                  },
                ],
              })}
            />
          </RadioStar>

          <Title cur={3} inner text="老师课堂形象满意度" errors={!!getFieldError('teacher_appearance_score')} />
          <RadioStar onChange={handleChangeChecked('teacher_appearance_score')}>
            <input
              style={{ display: 'none' }}
              {...getFieldProps('teacher_appearance_score', {
                initialValue: item.get('teacher_appearance_score'),
                rules: [
                  {
                    required: true,
                    message: '请填写老师课堂形象满意度',
                  },
                ],
              })}
            />
          </RadioStar>

          <Title cur={4} inner text="与老师有良好的互动" errors={!!getFieldError('lesson_interaction_score')} />
          <RadioStar onChange={handleChangeChecked('lesson_interaction_score')}>
            <input
              style={{ display: 'none' }}
              {...getFieldProps('lesson_interaction_score', {
                initialValue: item.get('lesson_interaction_score'),
                rules: [
                  {
                    required: true,
                    message: '请填写与老师有良好的互动',
                  },
                ],
              })}
            />
          </RadioStar>

          <Title cur={5} inner text="老师讲课表达能力" errors={!!getFieldError('teacher_expression_score')} />
          <RadioStar onChange={handleChangeChecked('teacher_expression_score')}>
            <input
              style={{ display: 'none' }}
              {...getFieldProps('teacher_expression_score', {
                initialValue: item.get('teacher_expression_score'),
                rules: [
                  {
                    required: true,
                    message: '请填写与老师有良好的互动',
                  },
                ],
              })}
            />
          </RadioStar>

      <Title cur={2} text="建议与意见(针对教学内容)" errors={!!getFieldError('lesson_suggestion')} />

        <TextareaItem
          {...getFieldProps('lesson_suggestion', {
            initialValue: item.get('lesson_suggestion'),
            rules: [
              {
                required: true,
                message: '请填写建议与意见(针对教学内容)',
              },
            ],
          })}
          editable
          placeholder="写下你对教学内容的建议与意见"
          rows={3}
          count={150}
        />

      <Title cur={3} text="对老师的评价(针对老师)" errors={!!getFieldError('teacher_suggestion')} />

        <TextareaItem
          {...getFieldProps('teacher_suggestion', {
            initialValue: item.get('teacher_suggestion'),
            rules: [
              {
                required: true,
                message: '请填写对老师的评价(针对老师)',
              },
            ],
          })}
          placeholder="写下你对导师的建议与意见"
          rows={3}
          count={150}
        />

        提交反馈

  )
}

Content.propTypes = {
  form: PropTypes.object.isRequired,
  readOnly: PropTypes.bool.isRequired,
  lessonId: PropTypes.string.isRequired,
  item: PropTypes.instanceOf(Immutable.Map).isRequired,
  onFeedback: PropTypes.object.isRequired,
}

export default createForm()(Content)
<commit_msg>fix feedback<commit_after>import React from 'react'
import PropTypes from 'prop-types'
import Immutable from 'immutable'
import classnames from 'classnames'
import { TextareaItem } from 'antd-mobile'
import { createForm } from 'rc-form'
import { RadioGroup, Radio } from 'components'
import styles from './Content.less'

const Title = ({ cur, inner, text, errors }) => (

    {cur}{ inner && '. ' }
    {text}

)
Title.propTypes = {
  cur: PropTypes.number.isRequired,
  inner: PropTypes.bool,
  text: PropTypes.string.isRequired,
  errors: PropTypes.bool,
}

const RadioStar = ({ onChange, children }) => {
  return (
    <RadioGroup onChange={onChange} field={children}>
      <Radio type="satisfy" value="4">很满意</Radio>
      <Radio type="good" value="3">满意</Radio>
      <Radio type="soso" value="2">不太满意</Radio>
      <Radio type="bad" value="1">不满意</Radio>
    </RadioGroup>
  )
}
RadioStar.propTypes = {
  onChange: PropTypes.func.isRequired,
  children: PropTypes.any.isRequired,
}

const Content = ({
    form: { getFieldProps, validateFields, getFieldError, setFieldsValue },
    readOnly,
    lessonId,
    item,
    onFeedback,
  }) => {
  console.log(readOnly)
  const submit = (e) => {
    validateFields((errors, value) => {
      if (errors) {
        e.preventDefault()
          // for (let index in errors) {
          //   console.log(errors[index].errors[0].message)
          // }
      } else {
        onFeedback.submitFeedback({ ...value, lessonid: lessonId }).then((res) => {
          console.log(res)
        })
      }
    })
  }

  const handleChangeChecked = field => (value) => {
    setFieldsValue({ [field]: value })
  }

  return (

      <Title cur={1} text="老师满意度" />

          <Title cur={1} inner text="老师课前教学准备充分度" errors={!!getFieldError('lesson_prepare_score')} />
          <RadioStar onChange={handleChangeChecked('lesson_prepare_score')}>
            <input
              style={{ display: 'none' }}
              {...getFieldProps('lesson_prepare_score', {
                initialValue: item.get('lesson_prepare_score'),
                rules: [
                  {
                    required: true,
                    message: '请填写老师课前教学准备充分度',
                  },
                ],
              })}
            />
          </RadioStar>

          <Title cur={2} inner text="本课内容设计满意度" errors={!!getFieldError('lesson_content_score')} />
          <RadioStar onChange={handleChangeChecked('lesson_content_score')}>
            <input
              style={{ display: 'none' }}
              {...getFieldProps('lesson_content_score', {
                initialValue: item.get('lesson_content_score'),
                rules: [
                  {
                    required: true,
                    message: '请填写本课内容设计满意度',
                  },
                ],
              })}
            />
          </RadioStar>

          <Title cur={3} inner text="老师课堂形象满意度" errors={!!getFieldError('teacher_appearance_score')} />
          <RadioStar onChange={handleChangeChecked('teacher_appearance_score')}>
            <input
              style={{ display: 'none' }}
              {...getFieldProps('teacher_appearance_score', {
                initialValue: item.get('teacher_appearance_score'),
                rules: [
                  {
                    required: true,
                    message: '请填写老师课堂形象满意度',
                  },
                ],
              })}
            />
          </RadioStar>

          <Title cur={4} inner text="与老师有良好的互动" errors={!!getFieldError('lesson_interaction_score')} />
          <RadioStar onChange={handleChangeChecked('lesson_interaction_score')}>
            <input
              style={{ display: 'none' }}
              {...getFieldProps('lesson_interaction_score', {
                initialValue: item.get('lesson_interaction_score'),
                rules: [
                  {
                    required: true,
                    message: '请填写与老师有良好的互动',
                  },
                ],
              })}
            />
          </RadioStar>

          <Title cur={5} inner text="老师讲课表达能力" errors={!!getFieldError('teacher_expression_score')} />
          <RadioStar onChange={handleChangeChecked('teacher_expression_score')}>
            <input
              style={{ display: 'none' }}
              {...getFieldProps('teacher_expression_score', {
                initialValue: item.get('teacher_expression_score'),
                rules: [
                  {
                    required: true,
                    message: '请填写与老师有良好的互动',
                  },
                ],
              })}
            />
          </RadioStar>

      <Title cur={2} text="建议与意见(针对教学内容)" errors={!!getFieldError('lesson_suggestion')} />

        <TextareaItem
          {...getFieldProps('lesson_suggestion', {
            initialValue: item.get('lesson_suggestion'),
            rules: [
              {
                required: true,
                message: '请填写建议与意见(针对教学内容)',
              },
            ],
          })}
          editable
          placeholder="写下你对教学内容的建议与意见"
          rows={3}
          count={150}
        />

      <Title cur={3} text="对老师的评价(针对老师)" errors={!!getFieldError('teacher_suggestion')} />

        <TextareaItem
          {...getFieldProps('teacher_suggestion', {
            initialValue: item.get('teacher_suggestion'),
            rules: [
              {
                required: true,
                message: '请填写对老师的评价(针对老师)',
              },
            ],
          })}
          placeholder="写下你对导师的建议与意见"
          rows={3}
          count={150}
        />

        提交反馈

  )
}

Content.propTypes = {
  form: PropTypes.object.isRequired,
  readOnly: PropTypes.bool.isRequired,
  lessonId: PropTypes.string.isRequired,
  item: PropTypes.instanceOf(Immutable.Map).isRequired,
  onFeedback: PropTypes.object.isRequired,
}

export default createForm()(Content)
<|endoftext|>


<commit_before>var app = angular.module('app', ['ngRoute', 'ngResource','ui.router','oc.lazyLoad','ui.bootstrap']);

/**
app.config(['$routeProvider', '$httpProvider', function ($route) {
    $route
        .when('/', {templateUrl: '/home'})
        .when('/system/user', {templateUrl: '/system/user'})
        .when('/console/context', {templateUrl: '/console/context', controller: 'ConsoleContextCtrl'})
        .when('/console/memory', {templateUrl: '/console/memory', controller: 'MemoryContextCtrl'})
        .when('/search/sqlDefine', {templateUrl: '/search/sqlDefine', controller: 'sqlDefineContextCtrl'})
        ;
}]);**/

app.config(['$stateProvider', '$httpProvider', function ($stateProvider) {

	$stateProvider
	.state('blank',{url:"",templateUrl:"/home"})
	.state('index',{url:"/",templateUrl:"/home"})
    .state('authorize', {
        // 这里设置了url参数
        url: "/:module/:controller/:mapping",
        templateUrl: function(param){
        	 return "/"+param.module+"/"+param.controller+"/"+param.mapping;
        },
        resolve:{
        	deps:function($ocLazyLoad,$stateParams,$log){

        		var promise =  $ocLazyLoad.load("templates/"+$stateParams.module+"/"+$stateParams.controller+"/"+$stateParams.mapping+".js");

        		promise.then(function(res){//success

        		},function(error){//error

        			$.error(error)
        		},function(info){//notify

        		}).catch(function(ex){

                }).finally(function(res){

                })
        		return promise;
        	}
        }
    })
}]);

//定义一个 Service ，稍等将会把它作为 Interceptors 的处理函数
app.factory('httpInterceptor', ['$q', httpInterceptor]);

function httpInterceptor($q,$log) {
  return {
    request: function(config){
      return config;
    },
    requestError: function(err){
      return $q.reject(err);
    },
    response: function(res){

      if(res.status == 200){

  		  if(!_.isUndefined(res.data.code)){

  			  if(res.data.code == 1)
  				  $.error(res.data.message);
  		  }
  	  }
      return res;
    },
    responseError: function(err){

      $.error(err.statusText);
      return $q.reject(err);
    }
  };
}

// 添加对应的 Interceptors
app.config(['$httpProvider', function($httpProvider){
  $httpProvider.interceptors.push(httpInterceptor);
}]);
<commit_msg>url也可以用:module标识<commit_after>var app = angular.module('app', ['ngRoute', 'ngResource','ui.router','oc.lazyLoad','ui.bootstrap']);

/**
app.config(['$routeProvider', '$httpProvider', function ($route) {
    $route
        .when('/', {templateUrl: '/home'})
        .when('/system/user', {templateUrl: '/system/user'})
        .when('/console/context', {templateUrl: '/console/context', controller: 'ConsoleContextCtrl'})
        .when('/console/memory', {templateUrl: '/console/memory', controller: 'MemoryContextCtrl'})
        .when('/search/sqlDefine', {templateUrl: '/search/sqlDefine', controller: 'sqlDefineContextCtrl'})
        ;
}]);**/

app.config(['$stateProvider', '$httpProvider', function ($stateProvider) {

	$stateProvider
	.state('blank',{url:"",templateUrl:"/home"})
	.state('index',{url:"/",templateUrl:"/home"})
    .state('authorize', {
        // 这里设置了url参数
        url: "/{module}/{controller}/{mapping}",
        templateUrl: function(param){
        	 return "/"+param.module+"/"+param.controller+"/"+param.mapping;
        },
        resolve:{
        	deps:function($ocLazyLoad,$stateParams,$log){

        		var promise =  $ocLazyLoad.load("templates/"+$stateParams.module+"/"+$stateParams.controller+"/"+$stateParams.mapping+".js");

        		promise.then(function(res){//success

        		},function(error){//error

        			$.error(error)
        		},function(info){//notify

        		}).catch(function(ex){

                }).finally(function(res){

                })
        		return promise;
        	}
        }
    })
}]);

//定义一个 Service ，稍等将会把它作为 Interceptors 的处理函数
app.factory('httpInterceptor', ['$q', httpInterceptor]);

function httpInterceptor($q,$log) {
  return {
    request: function(config){
      return config;
    },
    requestError: function(err){
      return $q.reject(err);
    },
    response: function(res){

      if(res.status == 200){

  		  if(!_.isUndefined(res.data.code)){

  			  if(res.data.code == 1)
  				  $.error(res.data.message);
  		  }
  	  }
      return res;
    },
    responseError: function(err){

      $.error(err.statusText);
      return $q.reject(err);
    }
  };
}

// 添加对应的 Interceptors
app.config(['$httpProvider', function($httpProvider){
  $httpProvider.interceptors.push(httpInterceptor);
}]);
<|endoftext|>


<commit_before>// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

import { reaction } from "mobx";
import PlaybackState, { PlaybackStates } from "../../stores/view/PlaybackState";
import UiState from "../../stores/view/UiState";
const { ExtCommand, isExtCommand } = window;

const extCommand = new ExtCommand();
window.extCommand = extCommand;
const xlateArgument = window.xlateArgument;
let baseUrl = "";

function play(currUrl) {
  baseUrl = currUrl;
  prepareToPlay()
    .then(executionLoop)
    .then(finishPlaying)
    .catch(catchPlayingError);
}

function playAfterConnectionFailed() {
  prepareToPlayAfterConnectionFailed()
    .then(executionLoop)
    .then(finishPlaying)
    .catch(catchPlayingError);
}

function executionLoop() {
  (PlaybackState.currentPlayingIndex < 0) ? PlaybackState.setPlayingIndex(0) : PlaybackState.setPlayingIndex(PlaybackState.currentPlayingIndex + 1);
  if ((PlaybackState.currentPlayingIndex >= PlaybackState.runningQueue.length && PlaybackState.isPlaying) || (!PlaybackState.isPlaying || PlaybackState.paused)) return false;
  const { id, command, target, value } = PlaybackState.runningQueue[PlaybackState.currentPlayingIndex];
  PlaybackState.setCommandState(id, PlaybackStates.Pending);
  if (isExtCommand(command)) {
    let upperCase = command.charAt(0).toUpperCase() + command.slice(1);
    const parsedTarget = command === "open" ? new URL(target, baseUrl).href : target;
    return (extCommand["do" + upperCase](parsedTarget, value))
      .then(() => {
        PlaybackState.setCommandState(id, PlaybackStates.Passed);
        return executionLoop();
      });
  } else if (isImplicitWait(command)) {
    notifyWaitDeprecation(command);
    return executionLoop();
  } else {
    return doPreparation()
      .then(doPrePageWait)
      .then(doPageWait)
      .then(doAjaxWait)
      .then(doDomWait)
      .then(doCommand)
      .then(doDelay)
      .then(executionLoop);
  }
}

function prepareToPlay() {
  PlaybackState.setPlayingIndex(PlaybackState.currentPlayingIndex - 1);
  return extCommand.init();
}

function prepareToPlayAfterConnectionFailed() {
  return Promise.resolve(true);
}

function finishPlaying() {
  if (!PlaybackState.paused) PlaybackState.finishPlaying();
}

function catchPlayingError(message) {
  if (isReceivingEndError(message)) {
    setTimeout(function() {
      PlaybackState.setPlayingIndex(PlaybackState.currentPlayingIndex - 1);
      playAfterConnectionFailed();
    }, 100);
  } else {
    reportError(message instanceof Error ? message.message : message);
    finishPlaying();
  }
}

function reportError(error) {
  const { id } = PlaybackState.runningQueue[PlaybackState.currentPlayingIndex];
  let message = error;
  if (error.message === "this.playingFrameLocations[this.currentPlayingTabId] is undefined") {
    message = "The current tab is invalid for testing (e.g. about:home), surf to a webpage before using the extension";
  }
  PlaybackState.setCommandState(id, PlaybackStates.Failed, message);
}

reaction(
  () => PlaybackState.isPlaying,
  isPlaying => {
    if (isPlaying) {
      play(UiState.baseUrl);
    }
  }
);

reaction(
  () => PlaybackState.paused,
  paused => {
    if (!paused) {
      PlaybackState.setPlayingIndex(PlaybackState.currentPlayingIndex - 1);
      playAfterConnectionFailed();
    }
  }
);

function doPreparation() {
  return extCommand.sendMessage("waitPreparation", "", "")
    .then(function() {
      return true;
    });
}

function doPrePageWait() {
  return extCommand.sendMessage("prePageWait", "", "")
    .then(function(response) {
      if (response && response.new_page) {
        return doPrePageWait();
      } else {
        return true;
      }
    });
}

function doPageWait(res, pageTime, pageCount = 0) {
  return extCommand.sendMessage("pageWait", "", "")
    .then(function(response) {
      if (pageTime && (Date.now() - pageTime) > 30000) {
        reportError("Page Wait timed out after 30000ms");
        return true;
      } else if (response && response.page_done) {
        return true;
      } else {
        pageCount++;
        if (pageCount == 1) {
          pageTime = Date.now();
        }
        return doPageWait(false, pageTime, pageCount);
      }
    });
}

function doAjaxWait(res, ajaxTime, ajaxCount = 0) {
  return extCommand.sendMessage("ajaxWait", "", "")
    .then(function(response) {
      if (ajaxTime && (Date.now() - ajaxTime) > 30000) {
        reportError("Ajax Wait timed out after 30000ms");
        return true;
      } else if (response && response.ajax_done) {
        return true;
      } else {
        ajaxCount++;
        if (ajaxCount == 1) {
          ajaxTime = Date.now();
        }
        return doAjaxWait(false, ajaxTime, ajaxCount);
      }
    });
}

function doDomWait(res, domTime, domCount = 0) {
  return extCommand.sendMessage("domWait", "", "")
    .then(function(response) {
      if (domTime && (Date.now() - domTime) > 30000) {
        reportError("DOM Wait timed out after 30000ms");
        return true;
      } else if (response && (Date.now() - response.dom_time) < 400) {
        domCount++;
        if (domCount == 1) {
          domTime = Date.now();
        }
        return doDomWait(false, domTime, domCount);
      } else {
        return true;
      }
    });
}

function doCommand(res, implicitTime = Date.now(), implicitCount = 0) {
  const { id, command, target, value } = PlaybackState.runningQueue[PlaybackState.currentPlayingIndex];

  let p = new Promise(function(resolve, reject) {
    let count = 0;
    let interval = setInterval(function() {
      if (count > 60) {
        reportError("Timed out after 30000ms");
        reject("Window not Found");
        clearInterval(interval);
      }
      if (!extCommand.getPageStatus()) {
        count++;
      } else {
        resolve();
        clearInterval(interval);
      }
    }, 500);
  });

  return p.then(() => (
    extCommand.sendMessage(command, xlateArgument(target), xlateArgument(value), isWindowMethodCommand(command))
  ))
    .then(function(result) {
      if (result.result !== "success") {
        // implicit
        if (result.result.match(/Element[\s\S]*?not found/)) {
          if (implicitTime && (Date.now() - implicitTime > 30000)) {
            reportError("Implicit Wait timed out after 30000ms");
            implicitCount = 0;
            implicitTime = "";
          } else {
            implicitCount++;
            if (implicitCount == 1) {
              implicitTime = Date.now();
            }
            PlaybackState.setCommandState(id, PlaybackStates.Pending, `Trying to find ${target}...`);
            return doCommand(false, implicitTime, implicitCount);
          }
        }

        PlaybackState.setCommandState(id, PlaybackStates.Failed, result.result);
      } else {
        PlaybackState.setCommandState(id, PlaybackStates.Passed);
      }
    });
}

function doDelay() {
  return new Promise((res) => {
    if (PlaybackState.currentPlayingIndex + 1 === PlaybackState.runningQueue.length) {
      return res(true);
    } else {
      setTimeout(() => {
        return res(true);
      }, PlaybackState.delay);
    }
  });
}

function notifyWaitDeprecation(command) {
  reportError(`${command} is deprecated, Selenium IDE waits automatically instead`);
}

function isReceivingEndError(reason) {
  return (reason == "TypeError: response is undefined" ||
    reason == "Error: Could not establish connection. Receiving end does not exist." ||
    // Below message is for Google Chrome
    reason.message == "Could not establish connection. Receiving end does not exist." ||
    // Google Chrome misspells "response"
    reason.message == "The message port closed before a reponse was received." ||
    reason.message == "The message port closed before a response was received." );
}

function isWindowMethodCommand(command) {
  return (command == "answerOnNextPrompt"
    || command == "chooseCancelOnNextPrompt"
    || command == "assertPrompt"
    || command == "chooseOkOnNextConfirmation"
    || command == "chooseCancelOnNextConfirmation"
    || command == "assertConfirmation"
    || command == "assertAlert");
}

function isImplicitWait(command) {
  return (command == "waitForPageToLoad"
    || command == "waitForElementPresent");
}
<commit_msg>improve abort mechanism<commit_after>// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

import { reaction } from "mobx";
import PlaybackState, { PlaybackStates } from "../../stores/view/PlaybackState";
import UiState from "../../stores/view/UiState";
const { ExtCommand, isExtCommand } = window;

const extCommand = new ExtCommand();
window.extCommand = extCommand;
const xlateArgument = window.xlateArgument;
let baseUrl = "";

function play(currUrl) {
  baseUrl = currUrl;
  prepareToPlay()
    .then(executionLoop)
    .then(finishPlaying)
    .catch(catchPlayingError);
}

function playAfterConnectionFailed() {
  prepareToPlayAfterConnectionFailed()
    .then(executionLoop)
    .then(finishPlaying)
    .catch(catchPlayingError);
}

function executionLoop() {
  (PlaybackState.currentPlayingIndex < 0) ? PlaybackState.setPlayingIndex(0) : PlaybackState.setPlayingIndex(PlaybackState.currentPlayingIndex + 1);
  if ((PlaybackState.currentPlayingIndex >= PlaybackState.runningQueue.length && PlaybackState.isPlaying) || (!PlaybackState.isPlaying || PlaybackState.paused)) return false;
  const { id, command, target, value } = PlaybackState.runningQueue[PlaybackState.currentPlayingIndex];
  PlaybackState.setCommandState(id, PlaybackStates.Pending);
  if (isExtCommand(command)) {
    let upperCase = command.charAt(0).toUpperCase() + command.slice(1);
    const parsedTarget = command === "open" ? new URL(target, baseUrl).href : target;
    return (extCommand["do" + upperCase](parsedTarget, value))
      .then(() => {
        PlaybackState.setCommandState(id, PlaybackStates.Passed);
        return executionLoop();
      });
  } else if (isImplicitWait(command)) {
    notifyWaitDeprecation(command);
    return executionLoop();
  } else {
    return doPreparation()
      .then(doPrePageWait)
      .then(doPageWait)
      .then(doAjaxWait)
      .then(doDomWait)
      .then(doCommand)
      .then(doDelay)
      .then(executionLoop);
  }
}

function prepareToPlay() {
  PlaybackState.setPlayingIndex(PlaybackState.currentPlayingIndex - 1);
  return extCommand.init();
}

function prepareToPlayAfterConnectionFailed() {
  return Promise.resolve(true);
}

function finishPlaying() {
  if (!PlaybackState.paused) PlaybackState.finishPlaying();
}

function catchPlayingError(message) {
  if (isReceivingEndError(message)) {
    setTimeout(function() {
      PlaybackState.setPlayingIndex(PlaybackState.currentPlayingIndex - 1);
      playAfterConnectionFailed();
    }, 100);
  } else {
    reportError(message instanceof Error ? message.message : message);
    finishPlaying();
  }
}

function reportError(error) {
  const { id } = PlaybackState.runningQueue[PlaybackState.currentPlayingIndex];
  let message = error;
  if (error.message === "this.playingFrameLocations[this.currentPlayingTabId] is undefined") {
    message = "The current tab is invalid for testing (e.g. about:home), surf to a webpage before using the extension";
  }
  PlaybackState.setCommandState(id, PlaybackStates.Failed, message);
}

reaction(
  () => PlaybackState.isPlaying,
  isPlaying => {
    if (isPlaying) {
      play(UiState.baseUrl);
    }
  }
);

reaction(
  () => PlaybackState.paused,
  paused => {
    if (!paused) {
      PlaybackState.setPlayingIndex(PlaybackState.currentPlayingIndex - 1);
      playAfterConnectionFailed();
    }
  }
);

function doPreparation() {
  return extCommand.sendMessage("waitPreparation", "", "")
    .then(function() {
      return true;
    });
}

function doPrePageWait() {
  return extCommand.sendMessage("prePageWait", "", "")
    .then(function(response) {
      if (response && response.new_page) {
        return doPrePageWait();
      } else {
        return true;
      }
    });
}

function doPageWait(res, pageTime, pageCount = 0) {
  return extCommand.sendMessage("pageWait", "", "")
    .then(function(response) {
      if (pageTime && (Date.now() - pageTime) > 30000) {
        reportError("Page Wait timed out after 30000ms");
        return true;
      } else if (response && response.page_done) {
        return true;
      } else {
        pageCount++;
        if (pageCount == 1) {
          pageTime = Date.now();
        }
        return doPageWait(false, pageTime, pageCount);
      }
    });
}

function doAjaxWait(res, ajaxTime, ajaxCount = 0) {
  return extCommand.sendMessage("ajaxWait", "", "")
    .then(function(response) {
      if (ajaxTime && (Date.now() - ajaxTime) > 30000) {
        reportError("Ajax Wait timed out after 30000ms");
        return true;
      } else if (response && response.ajax_done) {
        return true;
      } else {
        ajaxCount++;
        if (ajaxCount == 1) {
          ajaxTime = Date.now();
        }
        return doAjaxWait(false, ajaxTime, ajaxCount);
      }
    });
}

function doDomWait(res, domTime, domCount = 0) {
  return extCommand.sendMessage("domWait", "", "")
    .then(function(response) {
      if (domTime && (Date.now() - domTime) > 30000) {
        reportError("DOM Wait timed out after 30000ms");
        return true;
      } else if (response && (Date.now() - response.dom_time) < 400) {
        domCount++;
        if (domCount == 1) {
          domTime = Date.now();
        }
        return doDomWait(false, domTime, domCount);
      } else {
        return true;
      }
    });
}

function doCommand(res, implicitTime = Date.now(), implicitCount = 0) {
  if (!PlaybackState.isPlaying || PlaybackState.paused) return;
  const { id, command, target, value } = PlaybackState.runningQueue[PlaybackState.currentPlayingIndex];

  let p = new Promise(function(resolve, reject) {
    let count = 0;
    let interval = setInterval(function() {
      if (count > 60) {
        reportError("Timed out after 30000ms");
        reject("Window not Found");
        clearInterval(interval);
      }
      if (!extCommand.getPageStatus()) {
        count++;
      } else {
        resolve();
        clearInterval(interval);
      }
    }, 500);
  });

  return p.then(() => (
    extCommand.sendMessage(command, xlateArgument(target), xlateArgument(value), isWindowMethodCommand(command))
  ))
    .then(function(result) {
      if (result.result !== "success") {
        // implicit
        if (result.result.match(/Element[\s\S]*?not found/)) {
          if (implicitTime && (Date.now() - implicitTime > 30000)) {
            reportError("Implicit Wait timed out after 30000ms");
            implicitCount = 0;
            implicitTime = "";
          } else {
            implicitCount++;
            if (implicitCount == 1) {
              implicitTime = Date.now();
            }
            PlaybackState.setCommandState(id, PlaybackStates.Pending, `Trying to find ${target}...`);
            return doCommand(false, implicitTime, implicitCount);
          }
        }

        PlaybackState.setCommandState(id, PlaybackStates.Failed, result.result);
      } else {
        PlaybackState.setCommandState(id, PlaybackStates.Passed);
      }
    });
}

function doDelay() {
  return new Promise((res) => {
    if (PlaybackState.currentPlayingIndex + 1 === PlaybackState.runningQueue.length) {
      return res(true);
    } else {
      setTimeout(() => {
        return res(true);
      }, PlaybackState.delay);
    }
  });
}

function notifyWaitDeprecation(command) {
  reportError(`${command} is deprecated, Selenium IDE waits automatically instead`);
}

function isReceivingEndError(reason) {
  return (reason == "TypeError: response is undefined" ||
    reason == "Error: Could not establish connection. Receiving end does not exist." ||
    // Below message is for Google Chrome
    reason.message == "Could not establish connection. Receiving end does not exist." ||
    // Google Chrome misspells "response"
    reason.message == "The message port closed before a reponse was received." ||
    reason.message == "The message port closed before a response was received." );
}

function isWindowMethodCommand(command) {
  return (command == "answerOnNextPrompt"
    || command == "chooseCancelOnNextPrompt"
    || command == "assertPrompt"
    || command == "chooseOkOnNextConfirmation"
    || command == "chooseCancelOnNextConfirmation"
    || command == "assertConfirmation"
    || command == "assertAlert");
}

function isImplicitWait(command) {
  return (command == "waitForPageToLoad"
    || command == "waitForElementPresent");
}
<|endoftext|>


<commit_before>/**
* Copyright (c) Microsoft.  All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/*
* You can test powerbi embedded commands get loaded by xplat by following steps:
* a. Copy the folder to '<repository root>\lib\commands\arm'
* b. Under <repository root>, run 'node bin/azure config mode arm'
* c. Run 'node bin/azure', you should see 'powerbiembedded' listed as a command set
* d. Run 'node bin/azure', you should see 'create', "delete", etc
      showing up in the help text
*/

'use strict';

var util = require('util');

var profile = require('../../../util/profile');
var tagUtils = require('../tag/tagUtils');
var utils = require('../../../util/utils');

var powerbiembeddedUtils = require('./powerbiembeddedUtils');

var $ = utils.getLocaleString;

exports.init = function (cli) {
  var log = cli.output;

  var powerbiembeddedcli = cli.category('powerbi')
    .description($('Commands to manage your Azure Power BI Embedded Workspace Collections'));

  /**
   * Create new workspace collection
   */
  powerbiembeddedcli.command('create <resourceGroup> <name> [location] [tags]')
    .description($('Create a new workspace collection'))
    .option('-g --resource-group <resourceGroup>', $('Name of the resource group'))
    .option('-n --name <name>', $('The name of the new workspace collection'))
    .option('-l --location [location]', $('The location (azure region/datacenter) where the workspace collection will be provisioned'))
    .option('-t --tags [tags]', $('Tags to set to the resource group. Can be multiple. ' +
        'In the format of \'name=value\'. Name is required and value is optional. ' +
        'For example, -t \'tag1=value1;tag2\'. Providing an empty string \'\' will delete the tags.'))
    .option('-s --subscription [subscription]', $('The subscription identifier'))
    .execute(function (resourceGroup, name, options, _) {
      /** Validate parameters */
      if (!resourceGroup) {
        return cli.missingArgument('resourceGroup');
      }
      if (!name) {
        return cli.missingArgument('name');
      }

      /** Create client */
      var subscription = profile.current.getSubscription(options.subscription);
      var client = utils.createPowerbiManagementClient(subscription);

      /** Invoke client method */
      var tags = {};
      tags = tagUtils.buildTagsParameter(tags, options);

      var workspaceCollectionCreationOptions = {
        location: options.location || "southcentral",
        tags: tags,
        sku: {
          name: "S1",
          tier: "Standard"
        }
      };

      var progress = cli.interaction.progress(util.format($('Creating workspace collection: %s'), name));
      var workspaceCollection;
      try {
        console.log('creation parameters: ', name, workspaceCollectionCreationOptions);
        workspaceCollection = client.workspaceCollections.create(resourceGroup, name, workspaceCollectionCreationOptions, _);
      } finally {
        progress.end();
      }

      log.info('WorkspaceCollection ' + workspaceCollection.name + ' has been created.');
      log.info('Id: ' + workspaceCollection.id);
      log.info('Location: ' + workspaceCollection.location);
    });

  /**
   * Update existing workspace collection
   */
  powerbiembeddedcli.command('set <resourceGroup> <name> <tags>')
    .description($('Update a workspace collection\'s tags'))
    .option('-g --resource-group <resourceGroup>', $('Name of the resource group'))
    .option('-n --name <name>', $('Name of workspace collection'))
    .option('-t --tags <tags>', $('Tags to set to the resource group. Can be multiple. ' +
        'In the format of \'name=value\'. Name is required and value is optional. ' +
        'For example, -t \'tag1=value1;tag2\'. Providing an empty string \'\' will delete the tags.'))
    .option('-s --subscription [subscription]', $('The subscription identifier'))
    .execute(function (resourceGroup, name, tags, options, _) {
      /** Validate parameters */
      if (!resourceGroup) {
        return cli.missingArgument('resourceGroup');
      }
      if (!name) {
        return cli.missingArgument('name');
      }
      if (!tags) {
        return cli.missingArgument('tags');
      }

      var tagsObject = {};
      tagsObject = tagUtils.buildTagsParameter(tags, {tags: tags});

      /** Create client */
      var subscription = profile.current.updateSubscription(options.subscription);
      var client = utils.createPowerbiManagementClient(subscription);

      /** Invoke client method */
      var body = {
        tags: tagsObject,
        sku: {
          name: "S1"
        }
      };

      var progress = cli.interaction.progress(util.format($('Udating workspace collection: %s'), name));
      var workspaceCollection;
      try {
        workspaceCollection = client.workspaceCollections.update(resourceGroup, name, body, _);
      } finally {
        progress.end();
      }

      /** Display output */
      log.info('WorkspaceCollection updated!');
    });

  /**
   * Delete existing workspace collection
   */
  powerbiembeddedcli.command('delete [resourceGroup] [name]')
    .description($('Create a sample'))
    .option('-g --resource-group <resourceGroup>', $('Name of the resource group'))
    .option('-n --name <name>', $('Name of workspace collection'))
    .option('--subscription [subscription]', $('The subscription identifier'))
    .execute(function (resourceGroup, name, options, _) {
      /** Validate parameters */
      if (!resourceGroup) {
        return cli.missingArgument('resourceGroup');
      }
      if (!name) {
        return cli.missingArgument('name');
      }

      /** Create client */
      var subscription = profile.current.getSubscription(options.subscription);
      var client = utils.getSampleClient(subscription);

      /** Invoke client method */
      var progress = cli.interaction.progress(util.format($('Deleting workspace collection %s'), name));

      var result;
      try {
        result = client.workspaceCollections.delete(resourceGroup, name, _);
      } finally {
        progress.end();
      }
    });

  /**
   * List by Subscription or by Resource Group
   */
  powerbiembeddedcli.command('list [resourceGroup]')
    .description($('List workspace collections within subscription or within resource group'))
    .option('-g --resource-group [resourceGroup]', $('Name of the resource group'))
    .option('-s --subscription [subscription]', $('The subscription identifier'))
    .execute(function (options, _) {
      /** Create client */
      var subscription = profile.current.getSubscription(options.subscription);
      var client = utils.createPowerbiManagementClient(subscription);

      /** Invoke client method */
      var workspaceCollections;
      if(options.resourceGroup) {
        var progress = cli.interaction.progress($('Getting workspace collections in subscription ' + subscription + ' resource group: ' + options.resourceGroup));
        try {
          workspaceCollections = client.workspaceCollections.listByResourceGroup(options.resourceGroup);
        } finally {
          progress.end();
        }
      }
      else {
        var progress = cli.interaction.progress($('Getting workspace collections in subscription: ' + subscription));
        try {
          workspaceCollections = client.workspaceCollections.listBySubscription();
        } finally {
          progress.end();
        }
      }

      /** Output result */
      log.info('WorkspaceCollections:');
      var logString = workspaceCollections
        .reduce(function (s, workspaceCollection, i) {
          s += i + '. ' + workspaceCollection.name + ' : ' + workspaceCollection.id;
          return s;
        }, '')

      log.info(logString);
    });

  /**
   * Get access keys for workspace collection
   */
  powerbiembeddedcli.command('get-keys <resourceGroup> <name>')
    .description($('Get access keys for a workspace collection'))
    .option('-g --resource-group <resourceGroup>', $('Name of the resource group'))
    .option('-n --name <name>', $('Name of workspace collection'))
    .option('-s --subscription [subscription]', $('The subscription identifier'))
    .execute(function (resourceGroup, name, options, _) {
      /** Validate parameters */
      if (!resourceGroup) {
        return cli.missingArgument('resourceGroup');
      }
      if (!name) {
        return cli.missingArgument('name');
      }

      /** Create client */
      var subscription = profile.current.getSubscription(options.subscription);
      var client = utils.createPowerbiManagementClient(subscription);

      /** Invoke client method */
      var progress = cli.interaction.progress($('Getting workspace collection access keys...'));
      var accessKeys;
      try {
        accessKeys = client.workspaceCollections.getAccessKeys(resourceGroup, name);
      } finally {
        progress.end();
      }

      /** Output result */
      log.info('AccessKeys:');
      log.info('Key1: ' + accessKeys.key1);
      log.info('Key2: ' + accessKeys.key2);
    });

  /**
   * Regenerage access key
   */
  powerbiembeddedcli.command('regenerate-key <resourceGroup> <name> <keyName>')
    .description($('Get access keys for a workspace collection'))
    .option('-g --resource-group <resourceGroup>', $('Name of the resource group'))
    .option('-n --name <name>', $('Name of workspace collection'))
    .option('-k --keyName <keyName>', $('Name of key you would like to regenerate. Accepted values: "key1" (Primary) or "key2" (Secondary)'))
    .option('-s --subscription [subscription]', $('The subscription identifier'))
    .execute(function (resourceGroup, name, keyName, options, _) {
      /** Validate parameters */
      if (!resourceGroup) {
        return cli.missingArgument('resourceGroup');
      }
      if (!name) {
        return cli.missingArgument('name');
      }
      if (!keyName) {
        return cli.missingArgument('keyName');
      }

      /** Create client */
      var subscription = profile.current.getSubscription(options.subscription);
      var client = utils.createPowerbiManagementClient(subscription);

      /** Invoke client method */
      var progress = cli.interaction.progress($('Regenerate workspace collection access key: ' + keyName));
      var accessKeys;

      var body = {
        keyName: keyName
      };
      try {
        accessKeys = client.workspaceCollections.regenerateKey(resourceGroup, name, body);
      } finally {
        progress.end();
      }

      /** Output result */
      var key1string = 'key1';
      if(keyName === "key1") {
        key1string += ' (Regenerated)';
      }
      key1string += ': ' + accessKeys.key1;

      var key2string = 'key2';
      if(keyName === "key2") {
        key2string += ' (Regenerated)';
      }
      key2string += ': ' + accessKeys.key2;

      log.info('AccessKeys:');
      log.info(key1string);
      log.info(key2string);
    });

    /**
     * List workspaces within workspace collection
     */
    powerbiembeddedcli.command('list-workspaces <resourceGroup> <name>')
    .description($('Get workspaces within given workspace collection'))
    .option('-g --resource-group <resourceGroup>', $('Name of the resource group'))
    .option('-n --name <name>', $('Name of workspace collection'))
    .option('-s --subscription [subscription]', $('The subscription identifier'))
    .execute(function (resourceGroup, name, options, _) {
      /** Validate parameters */
      if (!resourceGroup) {
        return cli.missingArgument('resourceGroup');
      }
      if (!name) {
        return cli.missingArgument('name');
      }

      /** Create client */
      var subscription = profile.current.getSubscription(options.subscription);
      var client = utils.createPowerbiManagementClient(subscription);

      /** Invoke client method */
      var progress = cli.interaction.progress($('Fetching workspaces...'));
      var workspaces;

      try {
        workspaces = client.workspaces.list(resourceGroup, name, _);
      } finally {
        progress.end();
      }

      /** Output result */
      log.info('Workspaces:');
      workspaces.forEach(function (workspace, i) {
        log.info(i + ': ' + workspace.id);
      });
    });
};
<commit_msg>Fix help comment with accurate commands<commit_after>/**
* Copyright (c) Microsoft.  All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/*
* You can test powerbi embedded commands get loaded by xplat by following steps:
* a. Copy the folder to '<repository root>\lib\commands\arm'
* b. Under <repository root>, run 'node bin/azure config mode arm'
* c. Run 'node bin/azure', you should see 'powerbi' listed as a command set
* d. Run 'node bin/azure powerbi', you should see 'create', "delete", etc
      showing up in the help text
*/

'use strict';

var util = require('util');

var profile = require('../../../util/profile');
var tagUtils = require('../tag/tagUtils');
var utils = require('../../../util/utils');

var powerbiembeddedUtils = require('./powerbiembeddedUtils');

var $ = utils.getLocaleString;

exports.init = function (cli) {
  var log = cli.output;

  var powerbiembeddedcli = cli.category('powerbi')
    .description($('Commands to manage your Azure Power BI Embedded Workspace Collections'));

  /**
   * Create new workspace collection
   */
  powerbiembeddedcli.command('create <resourceGroup> <name> [location] [tags]')
    .description($('Create a new workspace collection'))
    .option('-g --resource-group <resourceGroup>', $('Name of the resource group'))
    .option('-n --name <name>', $('The name of the new workspace collection'))
    .option('-l --location [location]', $('The location (azure region/datacenter) where the workspace collection will be provisioned'))
    .option('-t --tags [tags]', $('Tags to set to the resource group. Can be multiple. ' +
        'In the format of \'name=value\'. Name is required and value is optional. ' +
        'For example, -t \'tag1=value1;tag2\'. Providing an empty string \'\' will delete the tags.'))
    .option('-s --subscription [subscription]', $('The subscription identifier'))
    .execute(function (resourceGroup, name, options, _) {
      /** Validate parameters */
      if (!resourceGroup) {
        return cli.missingArgument('resourceGroup');
      }
      if (!name) {
        return cli.missingArgument('name');
      }

      /** Create client */
      var subscription = profile.current.getSubscription(options.subscription);
      var client = utils.createPowerbiManagementClient(subscription);

      /** Invoke client method */
      var tags = {};
      tags = tagUtils.buildTagsParameter(tags, options);

      var workspaceCollectionCreationOptions = {
        location: options.location || "southcentral",
        tags: tags,
        sku: {
          name: "S1",
          tier: "Standard"
        }
      };

      var progress = cli.interaction.progress(util.format($('Creating workspace collection: %s'), name));
      var workspaceCollection;
      try {
        console.log('creation parameters: ', name, workspaceCollectionCreationOptions);
        workspaceCollection = client.workspaceCollections.create(resourceGroup, name, workspaceCollectionCreationOptions, _);
      } finally {
        progress.end();
      }

      log.info('WorkspaceCollection ' + workspaceCollection.name + ' has been created.');
      log.info('Id: ' + workspaceCollection.id);
      log.info('Location: ' + workspaceCollection.location);
    });

  /**
   * Update existing workspace collection
   */
  powerbiembeddedcli.command('set <resourceGroup> <name> <tags>')
    .description($('Update a workspace collection\'s tags'))
    .option('-g --resource-group <resourceGroup>', $('Name of the resource group'))
    .option('-n --name <name>', $('Name of workspace collection'))
    .option('-t --tags <tags>', $('Tags to set to the resource group. Can be multiple. ' +
        'In the format of \'name=value\'. Name is required and value is optional. ' +
        'For example, -t \'tag1=value1;tag2\'. Providing an empty string \'\' will delete the tags.'))
    .option('-s --subscription [subscription]', $('The subscription identifier'))
    .execute(function (resourceGroup, name, tags, options, _) {
      /** Validate parameters */
      if (!resourceGroup) {
        return cli.missingArgument('resourceGroup');
      }
      if (!name) {
        return cli.missingArgument('name');
      }
      if (!tags) {
        return cli.missingArgument('tags');
      }

      var tagsObject = {};
      tagsObject = tagUtils.buildTagsParameter(tags, {tags: tags});

      /** Create client */
      var subscription = profile.current.updateSubscription(options.subscription);
      var client = utils.createPowerbiManagementClient(subscription);

      /** Invoke client method */
      var body = {
        tags: tagsObject,
        sku: {
          name: "S1"
        }
      };

      var progress = cli.interaction.progress(util.format($('Udating workspace collection: %s'), name));
      var workspaceCollection;
      try {
        workspaceCollection = client.workspaceCollections.update(resourceGroup, name, body, _);
      } finally {
        progress.end();
      }

      /** Display output */
      log.info('WorkspaceCollection updated!');
    });

  /**
   * Delete existing workspace collection
   */
  powerbiembeddedcli.command('delete [resourceGroup] [name]')
    .description($('Create a sample'))
    .option('-g --resource-group <resourceGroup>', $('Name of the resource group'))
    .option('-n --name <name>', $('Name of workspace collection'))
    .option('--subscription [subscription]', $('The subscription identifier'))
    .execute(function (resourceGroup, name, options, _) {
      /** Validate parameters */
      if (!resourceGroup) {
        return cli.missingArgument('resourceGroup');
      }
      if (!name) {
        return cli.missingArgument('name');
      }

      /** Create client */
      var subscription = profile.current.getSubscription(options.subscription);
      var client = utils.getSampleClient(subscription);

      /** Invoke client method */
      var progress = cli.interaction.progress(util.format($('Deleting workspace collection %s'), name));

      var result;
      try {
        result = client.workspaceCollections.delete(resourceGroup, name, _);
      } finally {
        progress.end();
      }
    });

  /**
   * List by Subscription or by Resource Group
   */
  powerbiembeddedcli.command('list [resourceGroup]')
    .description($('List workspace collections within subscription or within resource group'))
    .option('-g --resource-group [resourceGroup]', $('Name of the resource group'))
    .option('-s --subscription [subscription]', $('The subscription identifier'))
    .execute(function (options, _) {
      /** Create client */
      var subscription = profile.current.getSubscription(options.subscription);
      var client = utils.createPowerbiManagementClient(subscription);

      /** Invoke client method */
      var workspaceCollections;
      if(options.resourceGroup) {
        var progress = cli.interaction.progress($('Getting workspace collections in subscription ' + subscription + ' resource group: ' + options.resourceGroup));
        try {
          workspaceCollections = client.workspaceCollections.listByResourceGroup(options.resourceGroup);
        } finally {
          progress.end();
        }
      }
      else {
        var progress = cli.interaction.progress($('Getting workspace collections in subscription: ' + subscription));
        try {
          workspaceCollections = client.workspaceCollections.listBySubscription();
        } finally {
          progress.end();
        }
      }

      /** Output result */
      log.info('WorkspaceCollections:');
      var logString = workspaceCollections
        .reduce(function (s, workspaceCollection, i) {
          s += i + '. ' + workspaceCollection.name + ' : ' + workspaceCollection.id;
          return s;
        }, '')

      log.info(logString);
    });

  /**
   * Get access keys for workspace collection
   */
  powerbiembeddedcli.command('get-keys <resourceGroup> <name>')
    .description($('Get access keys for a workspace collection'))
    .option('-g --resource-group <resourceGroup>', $('Name of the resource group'))
    .option('-n --name <name>', $('Name of workspace collection'))
    .option('-s --subscription [subscription]', $('The subscription identifier'))
    .execute(function (resourceGroup, name, options, _) {
      /** Validate parameters */
      if (!resourceGroup) {
        return cli.missingArgument('resourceGroup');
      }
      if (!name) {
        return cli.missingArgument('name');
      }

      /** Create client */
      var subscription = profile.current.getSubscription(options.subscription);
      var client = utils.createPowerbiManagementClient(subscription);

      /** Invoke client method */
      var progress = cli.interaction.progress($('Getting workspace collection access keys...'));
      var accessKeys;
      try {
        accessKeys = client.workspaceCollections.getAccessKeys(resourceGroup, name);
      } finally {
        progress.end();
      }

      /** Output result */
      log.info('AccessKeys:');
      log.info('Key1: ' + accessKeys.key1);
      log.info('Key2: ' + accessKeys.key2);
    });

  /**
   * Regenerage access key
   */
  powerbiembeddedcli.command('regenerate-key <resourceGroup> <name> <keyName>')
    .description($('Get access keys for a workspace collection'))
    .option('-g --resource-group <resourceGroup>', $('Name of the resource group'))
    .option('-n --name <name>', $('Name of workspace collection'))
    .option('-k --keyName <keyName>', $('Name of key you would like to regenerate. Accepted values: "key1" (Primary) or "key2" (Secondary)'))
    .option('-s --subscription [subscription]', $('The subscription identifier'))
    .execute(function (resourceGroup, name, keyName, options, _) {
      /** Validate parameters */
      if (!resourceGroup) {
        return cli.missingArgument('resourceGroup');
      }
      if (!name) {
        return cli.missingArgument('name');
      }
      if (!keyName) {
        return cli.missingArgument('keyName');
      }

      /** Create client */
      var subscription = profile.current.getSubscription(options.subscription);
      var client = utils.createPowerbiManagementClient(subscription);

      /** Invoke client method */
      var progress = cli.interaction.progress($('Regenerate workspace collection access key: ' + keyName));
      var accessKeys;

      var body = {
        keyName: keyName
      };
      try {
        accessKeys = client.workspaceCollections.regenerateKey(resourceGroup, name, body);
      } finally {
        progress.end();
      }

      /** Output result */
      var key1string = 'key1';
      if(keyName === "key1") {
        key1string += ' (Regenerated)';
      }
      key1string += ': ' + accessKeys.key1;

      var key2string = 'key2';
      if(keyName === "key2") {
        key2string += ' (Regenerated)';
      }
      key2string += ': ' + accessKeys.key2;

      log.info('AccessKeys:');
      log.info(key1string);
      log.info(key2string);
    });

    /**
     * List workspaces within workspace collection
     */
    powerbiembeddedcli.command('list-workspaces <resourceGroup> <name>')
    .description($('Get workspaces within given workspace collection'))
    .option('-g --resource-group <resourceGroup>', $('Name of the resource group'))
    .option('-n --name <name>', $('Name of workspace collection'))
    .option('-s --subscription [subscription]', $('The subscription identifier'))
    .execute(function (resourceGroup, name, options, _) {
      /** Validate parameters */
      if (!resourceGroup) {
        return cli.missingArgument('resourceGroup');
      }
      if (!name) {
        return cli.missingArgument('name');
      }

      /** Create client */
      var subscription = profile.current.getSubscription(options.subscription);
      var client = utils.createPowerbiManagementClient(subscription);

      /** Invoke client method */
      var progress = cli.interaction.progress($('Fetching workspaces...'));
      var workspaces;

      try {
        workspaces = client.workspaces.list(resourceGroup, name, _);
      } finally {
        progress.end();
      }

      /** Output result */
      log.info('Workspaces:');
      workspaces.forEach(function (workspace, i) {
        log.info(i + ': ' + workspace.id);
      });
    });
};
<|endoftext|>


<commit_before>'use strict';

/******************
 *  Dependencies  *
 ******************/

var Promise = require('promise');
var sass = require('node-sass');
var path = require('path');
var log = require('../logger');
var bourbon = require('node-bourbon');
var neat = require('node-neat');

/****************
 *  Algorithms  *
 ****************/

/**
 *
 * @param {type} [name] [description]
 */
function appendModuleImports(style, modPath, modules) {
    var thisPath, name;

    style += '\n';

    for (var i in modules) {
        name =
        thisPath = path.join(modPath, i, 'main.scss');

        if (modules[i].sass) {
            style += '@import "' + thisPath + '";\n';
        }
    }

    return style;
}

/**
 *
 * @param {type} [name] [description]
 */
function recursiveCompileSass(context, src, dest, promises, crumbs) {
    var srcPath, destPath, normalizePath;
    var settings = context.settings;
    var styleSettings = settings.styles;
    var sassSheet = src['main.scss'] || '';
    var modules = dest._page._modules;
    var modPath = path.join(process.cwd(), settings.src, 'modules');
    var cwd = process.cwd();
    var debug = styleSettings.debug;
    var includePaths = bourbon.includePaths.concat(neat.includePaths.concat(styleSettings.includePaths || []));

    crumbs = crumbs || [];

    // Add normalize
    normalizePath = path.join(__dirname, '../../node_modules/normalize.scss');
    includePaths.push(normalizePath);

    // Append modules
    if (modules) {
        sassSheet = appendModuleImports(sassSheet, modPath, modules);
    }

    // Determine the src and dest path
    srcPath = path.join(cwd,
        settings.src,
        'site',
        crumbs.join(path.sep),
        'main.scss');
    destPath = path.join(cwd,
        settings.src,
        settings.dest,
        crumbs.join(path.sep),
        'main.css');

    // Asynchronously render CSS
    promises.push(new Promise(function(resolve) {
        sass.render({
            file: srcPath,
            data: sassSheet,
            outFile: destPath,
            includePaths: includePaths|| [],
            outputStyle: styleSettings.outputStyle || 'nested',
            omitSourceMapUrl: !debug,
            sourceComments: debug,
            sourceMap: debug,
            success: function(result) {
                resolve();

                dest['main.css'] = result.css;

                // Optionally write map
                if (styleSettings.debug) {
                    dest['main.css.map'] = JSON.stringify(result.map);
                }
            },
            error: function(error) {
                var file = error.file.replace(process.cwd() + path.sep, '');
                var msg = '"' + error.message + '" in ' + file + ' on line ' + error.line;

                log('SASS', msg, 'error');
                resolve();
            }
        });
    }));

    // Continue recursion
    for (var j in src) {
        if (src[j] === Object(src[j])) {
            crumbs.push(j);
            dest[j] = dest[j] || {};
            recursiveCompileSass(context, src[j], dest[j], promises, crumbs);
            crumbs.pop(j);
        }
    }

    return Promise.all(promises);
}

/*************
 *  Exports  *
 *************/

module.exports = function(context) {
    var start = Date.now();
    var site = context.app.site;
    var dist = context.dist;
    var promises = [];

    return new Promise(function(resolve, reject) {
        try {
            recursiveCompileSass(context, site, dist, promises)
                .then(function() {
                    var delta = (Date.now() - start) / 1000;
                    log('SASS', 'Compiled in ' + delta + 's');
                    resolve(context);
                })
                .catch(function(err) {
                    reject(err);
                });
        } catch (err) {
            reject('[compile-styles.js] ' + err);
        }
    });
};
<commit_msg>cleanup<commit_after>'use strict';

/******************
 *  Dependencies  *
 ******************/

var Promise = require('promise');
var sass = require('node-sass');
var path = require('path');
var log = require('../logger');
var bourbon = require('node-bourbon');
var neat = require('node-neat');

/****************
 *  Algorithms  *
 ****************/

/**
 *
 * @param {type} [name] [description]
 */
function appendModuleImports(style, modPath, modules) {
    var thisPath, name;

    style += '\n';

    for (var i in modules) {
        name =
        thisPath = path.join(modPath, i, 'main.scss');

        if (modules[i].sass) {
            style += '@import "' + thisPath + '";\n';
        }
    }

    return style;
}

/**
 *
 * @param {type} [name] [description]
 */
function recursiveCompileSass(context, src, dest, promises, crumbs) {
    var srcPath, destPath, normalizePath;
    var settings = context.settings;
    var styleSettings = settings.styles;
    var sassSheet = src['main.scss'] || '';
    var modules = dest._page._modules;
    var modPath = path.join(process.cwd(), settings.src, 'modules');
    var cwd = process.cwd();
    var debug = styleSettings.debug;
    var includePaths = bourbon.includePaths.concat(neat.includePaths.concat(styleSettings.includePaths || []));

    crumbs = crumbs || [];

    // Add normalize
    normalizePath = path.join(__dirname, '../../node_modules/normalize.scss');
    includePaths.push(normalizePath);

    // Append modules
    if (modules) {
        sassSheet = appendModuleImports(sassSheet, modPath, modules);
    }

    // Determine the src and dest path
    srcPath = path.join(cwd,
        settings.src,
        'site',
        crumbs.join(path.sep),
        'main.scss');
    destPath = path.join(cwd,
        settings.src,
        settings.dest,
        crumbs.join(path.sep),
        'main.css');

    // Asynchronously render CSS
    promises.push(new Promise(function(resolve) {
        sass.render({
            file: srcPath,
            data: sassSheet,
            outFile: destPath,
            includePaths: includePaths || [],
            outputStyle: styleSettings.outputStyle || 'nested',
            omitSourceMapUrl: !debug,
            sourceComments: debug,
            sourceMap: debug,
            success: function(result) {
                resolve();

                dest['main.css'] = result.css;

                // Optionally write map
                if (styleSettings.debug) {
                    dest['main.css.map'] = JSON.stringify(result.map);
                }
            },
            error: function(error) {
                var file = error.file.replace(process.cwd() + path.sep, '');
                var msg = '"' + error.message + '" in ' + file + ' on line ' + error.line;

                log('SASS', msg, 'error');
                resolve();
            }
        });
    }));

    // Continue recursion
    for (var j in src) {
        if (src[j] === Object(src[j])) {
            crumbs.push(j);
            dest[j] = dest[j] || {};
            recursiveCompileSass(context, src[j], dest[j], promises, crumbs);
            crumbs.pop(j);
        }
    }

    return Promise.all(promises);
}

/*************
 *  Exports  *
 *************/

module.exports = function(context) {
    var start = Date.now();
    var site = context.app.site;
    var dist = context.dist;
    var promises = [];

    return new Promise(function(resolve, reject) {
        try {
            recursiveCompileSass(context, site, dist, promises)
                .then(function() {
                    var delta = (Date.now() - start) / 1000;
                    log('SASS', 'Compiled in ' + delta + 's');
                    resolve(context);
                })
                .catch(function(err) {
                    reject(err);
                });
        } catch (err) {
            reject('[compile-styles.js] ' + err);
        }
    });
};
<|endoftext|>


<commit_before>const { fields, validators, widgets, create: createForm } = require('forms');

function extendOptions(options, newOptions) {
  return Object.assign({ }, options, newOptions);
}

function textField(label, maxlength, options = { }) {
  return fields.string(extendOptions(options, {
    widget: widgets.text({
      maxlength,
      classes: [ 'pixel' ],
      placeholder: options.placeholder,
    }),
    label,
    validators: [
      validators.maxlength(maxlength),
    ],
    cssClasses,
  }));
}

const cssClasses = {
  error: [ 'error' ],
  label: [ 'form-label-longform' ],
  field: [ 'form-row', 'form-row-margin' ],
};

const requiredField = validators.required('This field is required.');

/**
 * Create the object representation of our application form.
 *
 * To support client side validation in browsers that don't have sufficient APIs, there is
 * an option to disable file validation.
 */
exports.createTeamForm = function createTeamForm(defaults = { }) {
  for (const def in defaults) {
    defaults[def] = { value: defaults[def] };
  }
  return createForm({
    memberB: textField('B', 256, extendOptions(defaults.memberB, { required: requiredField, placeholder: 'Enter the Application ID' })),
    memberC: textField('C', 256, extendOptions(defaults.memberC, { placeholder: 'Enter the Application ID' })),
    memberD: textField('D', 256, extendOptions(defaults.memberD, { placeholder: 'Enter the Application ID' })),
  }, {
    validatePastFirstError: true,
  });
};<commit_msg>Move constants to top of file<commit_after>const { fields, validators, widgets, create: createForm } = require('forms');

const cssClasses = {
  error: [ 'error_msg form-error-message' ],
  label: [ 'form-label-longform' ],
  field: [ 'form-row', 'form-row-margin' ],
};

function extendOptions(options, newOptions) {
  return Object.assign({ }, options, newOptions);
}

function textField(label, maxlength, options = { }) {
  return fields.string(extendOptions(options, {
    widget: widgets.text({
      maxlength,
      classes: [ 'pixel' ],
      placeholder: options.placeholder,
    }),
    label,
    validators: [
      validators.maxlength(maxlength),
    ],
    cssClasses,
  }));
}

const requiredField = validators.required('This field is required.');

/**
 * Create the object representation of our application form.
 *
 * To support client side validation in browsers that don't have sufficient APIs, there is
 * an option to disable file validation.
 */
exports.createTeamForm = function createTeamForm(defaults = { }) {
  for (const def in defaults) {
    defaults[def] = { value: defaults[def] };
  }
  return createForm({
    memberB: textField('B', 256, extendOptions(defaults.memberB, { required: requiredField, placeholder: 'Enter the Application ID' })),
    memberC: textField('C', 256, extendOptions(defaults.memberC, { placeholder: 'Enter the Application ID' })),
    memberD: textField('D', 256, extendOptions(defaults.memberD, { placeholder: 'Enter the Application ID' })),
  }, {
    validatePastFirstError: true,
  });
};<|endoftext|>